Closed Candoran2 closed 2 years ago
With the hash names figured out, should the information in the option be changed to reflect the hashes/material names? Currently they include some spaces where they shouldn't be. For example:
<option value="2632367422" name="SKY_HAV_MAT_MATERIAL_SKIN_SMALL">Material Skin Small</option>
is actually mapped to the MaterialSkinSmall
material name (rather than "Material Skin Small").
Also, some materials exist in the game records, but are only created dynamically and not used by any nifs (such as MaterialBlockAxe). Should they be added to the material options?
The same question goes for materials that are obvious mistakes and do not exist in-game, but do exist in vanilla nifs, such as 617099282, which is used in meshes\dlc01\clutter\dlc01deerskin.nif and is the hash for 'materialcloth' (which does not exist in the CK), whereas almost every other pelt uses 3839073443 (hash for 'cloth').
Changes to spec
Default
type
attribute toonlyT
For easier parsing, the
type
attribute of the<default>
tag was changed toonlyT
. Thetype
attribute in default tags means that the associated value only applies when the struct or niobject it's in is that type. TheonlyT
attribute on field tags takes a similar place, meaning the field only exists when the struct or niobject it's in is that type. The change was made to unify this (the type attribute in fields is already used).Addition of the
<verattr>
tag.The
verattr
tag is introduced to make it easier for codegen to link the attributes of versions to global variables (like those used by thevercond
attribute). Essentially, it functions like token replacement specifically for attribute names of the version tag. It can also be used to specify priority between the different attributes that define a version number, in order to more robustly define the ordering of version IDs. Example:The
name
attribute of theverattr
tag corresponds to the attribute name in theversion
tag. This should not use any of the predefined attributes (id
,supported
,custom
orext
). Theaccess
attribute defines the associated global variable (using the same definitions as thevercond
attribute). Theindex
attribute defines the priority of eachverattr
token. These should start at 0 and each index should only be used once. The lower the index, the more significant the version attribute. So in the example, a version with a highernum
attribute than another version, is always later than that other version, regardless of any other version attributes.In the cobra-tools repository some verattr tags also got the
type=
attribute, which was necessary because otherwise there was no way to know if it was a bitfield or not (and hence how to do assignment). The default is interpretation as versions/integers, so in nif.xml it was not necessary.Changes originating from NifSkope dev8
ver1
andver2
attributes were renamed tountil
andsince
, respectively. This was already done on most tags, but not yet on<field>
tags.<compound>
tag was renamed to<struct>
.arr1
andarr2
attributes were renamed tolength
andwidth
, respectively.Other NifSkope dev8 changes
Changes to BSInvMarker
Identifications of unknown material values.
I have identified a number of previously unidentified Skyrim Havok Material values. This was done via the following process:
Any option that was left unmatched did not have a response. I think these materials are not actually used in-game, or at least not in the traditional way. Some may have some other function (I suspect 1574477864 and 1591009235, since they appear with relative consistency in creature skeletons under the character controller) and some may just be mistakes (I suspect 2290050264, since there are vanilla objects with that like the sabre cat pelt. It simply has no sound when colliding at all). The value for any given material is obtained via a hash of the lower case material name, using this hash (also used in Fallout 4 for material and ba2, thank you zilav for pointing that out). In python this can be easily replicated using the following code:
Changes to bhkCMSChunk
A detailed explanation follows below. An example mesh to study would be genkitrmwall01.nif, or farmhous01walkway.nif.
Use of UshortVector3 in the Vertices field.
Previously, the vertices field was regarded as one array of ushorts. However, these numbers are actually associated per vertex, like so:
This stores the havok coordinates for each vertex. However, they are still ushorts, rather than floats (or hfloats). The values, however, are actually the havok coordinate*1000, giving some measure of precision. Negative coordinates are not needed: the lowest X, Y and Z are alway 0, and the translation entry in the chunk itself gives allows for the final position to be negative.
Doc string in indices and strips field
The strips field defines strips of vertices within the indices field. Let an example be the following: indices field: [7, 4, 6, 5, 15, 11, 14, 10, 17, 16, 6] strips field: [4, 4] This defines strips [7, 4, 6, 5] and [15, 11, 14, 10], with the numbers referring to the vertex index in the vertices array. The single-triangle at the end ([17, 16, 6]) is not included in the strips field (there can be multiple of these, each taking three entries). In the example above, the resulting triangles would be:
Here, even-index triangles (starting from index 0 within every strip) are defined counterclockwise and odd-index triangles are defined clockwise.
Changes to welding info field
This is the most difficult to decode, and there are still some mysteries remaining. However, I believe the most important parts are here.
Welding info is always as long as the indices field. This way, one entry in welding info is associated with one entry in the indices field. Each entry in welding info contains information about the edges of the triangle which is defined by the associated indices entry and the two following entries. This means there are some welding info fields which contain information for non-existing triangles. So in the example above, the welding info would look like this:
The welding info for nonexistent triangles is often the same as the indices entry it is associated with, but I think they are entirely inconsequential entries. The welding info for existent triangles is formatted as follows (expressed in bits):
0 xxxxx xxxxx xxxxx
Here, each group of 5 bits contains the exterior angle that an edge of the triangle makes with another triangle, measured as shown below. Edges without an other adjacent triangle are considered to have an angle of 180. Illustration of how to measure the exterior angle. Blue arrows show the normal facing direction of a triangle This mapping of course isn't perfectly smooth, because there are only 5 bits to store this information in. The association of various exterior angles with the decimal representation of the welding info for that edge is shown below, with an included trendline. The best approximation that I have found so far for a function that matches exterior angle to the outputted value is as follows :While this function does not exactly match all the data points I have, the uncertainty is, from some experimentation, close enough to be due to precision limits.
The way in which these angles are associated with the edge is as follows: If the triangle is even-index in the strip (counterclockwise), reverse the vertex indices. Otherwise, leave them as they are. The weld information is now in the same order as the vertex indices. The weld information for an edge is associated with the vertex that edge goes to. For a more concrete example: Let's consider the indices above, looking only at the first strip ([7, 4, 6, 5]). This has two triangles. Let's consider the situation where they make a 270° exterior (90° interior) angle with each other, as shown below, and all the other edges are unconnected or connected at 180° to another triangle, except that edge 5-6 also makes a similar angle with another triangle. The following weld information would then be associated with that strip:
[7, 4, 6] is reversed to become [6, 4, 7], so: [7-6 is flat, 6-4 is 270°, 4-7 is 270°] And the other triangle remains [4, 6, 5], so [5-4 is flat, 4-6 is 270°, 6-5 is flat]