NifSkope Editing

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search


This page will attempt to help users who do not have the advanced programs, like 3D Studio MAX, required to edit NIFs directly. Oblivion uses NIF version 20.0.0.5 while current scripts for free programs like Blender will only take you to 20.0.0.4 (As of 6/10/07). Editing an existing NIF in Nifskope is the best way to achieve working results. One goal of this page is to save people the countless hours of trial and error I had to go through to get edited meshes to work. Even though different topics are covered, the later sections build upon the previous ones.

This page will be completed with various tutorials and images by this week (week of 6/11/07). The Animation tutorial is not quite working correct... I'm working on it.


Modifying an Existing NIF[edit | edit source]

When modifying a NIF, there are two different beasts to cope with. The first is the NiTriStrips, which set the shape of the mesh that the texture goes over, and the other is the collision data, which tells the game which parts of the mesh players can actually move through. I will demonstrate some of things that can be done.

Simple Editing[edit | edit source]

All NiTriStrips blocks have the scale, rotation and translation parameters. These are very useful when working with multi-mesh nifs. Note that changing the scale will make the mesh change size in NifSkope's window, but the next time you open this mesh, the axis will be changed relative to the scale of your mesh, so it may not look a different size, although it is.

When and if you edit the Num Vertices number in the NiTriStripsData blocks, you must also update the arrays for normals, vertex colors, and UV sets by simply right-clicking and selecting array -> update.

The NiMaterialProperty block will give you four colors that you can use to edit- to some degree- shading on the chosen texture. They don't actually change the color of the mesh if there is no texture.

Editing Mesh Properties En Mass[edit | edit source]

This is quite a detailed mesh, weighing in at almost 1.5 MB, but also very useful, since it is completely surrounded by a some a texture. My goal was to reduce it to just the steps part, and take out the railing, so I could stack one upon the other to make one long stairwell. The mesh I am using is the icpalacelibrarystairs01.nif, found in the meshes/architecture/imperialcity/interior directory.

The first thing we will edit is the NiTriStrips data. If you are very, very lucky, then the unneeded parts will have separate NiTriStrips. In the first case, we are lucky. if you click on the carpet in Nifskope, you will notice the triangles that make it up will be shown, and the appropriate block will [most of the time] be selected in Nifskope. The block we want is the highest block in the hierarchy that deals only with the carpet. For this reason, I will delete block 39, instead of just 44, since all of the texture data for the carpet is of course not needed. In the Block list, simply right click this block and select block -> Remove_Branch. Remove Branch is needed instead of Remove Block whenever the block has children (can be expanded). Given the ease of this kind of edit, the result is really quite gratifying.

The second thing I want to do is remove that rail. I will use the same process, and delete the whole branch at 20, and not 26. Notice how the other blocks' numbers move up to "fill in" the number gap. Another satisfying edit.

I will leave the flat part at the top even though I don't need it, simply because it would take a long time to remove. However, if you wanted to, I will show you how to remove select vertices and collision vertices in the next mesh.

The final thing to do is to remove the collision data. As you can see, the rail is still highly visible as collision, and will be invisible but impassable to the player. There is not way to select parts of the collision data, so it can be tricky. This particular mesh makes it easy for us though. You will find the collision in box 7, bhkCollisionObject. Most, if not all, meshes use this particular block for starting collision. Expand the entire tree until you reach the bottom, hkPackedNiTriStripsData. This block is the guts of the collision, storing all of the vertices and triangle data. Each vertice is a point in space, and if you expand a triangle, you will notice the first entry includes three numbers, which are the numbers of the vertices that are connected. If you expand the vertices and hold your mouse over the name column, the array index of that vertex will pop up- very useful for fine tuning! Note that without a triangle, the collision vertex itself does not create any collision.

Even though there are thousands of vertices and triangles, there is one way you can do it at once. You can delete these at once from the BOTTOM UP. This is done by changing the Num Triangles and Num Vertices respectively and updating the array (right-click on triangles or vertices and select array -> update). You can add to the arrays, but more useful will be deleting stuff. Lots of stuff. We will start with the triangles. Set the Num Triangles number lower by 100 and update the array. Notice how some of the rail disappears. We are lucky because the rail data was generated last. You will have to experiment to find exactly how much you want off, but for this mesh, the number of triangles I needed was 652, which took out all of the rail data. You can look at the last couple of triangles then to find the very last vertices that are used, and delete those, since they only add ot the file size now. The highest number appears to be 866, so I set the Num Vertices array to 867, and update.

The final step is EXTREMELY IMPORTANT!! Using this mesh will make the game crash completely. I narrowed down the problem to the MOPP data, though I don't even know what it does! inconsistencies will cause the game to crash upon viewing this mesh, so you will have to update this MOPP data. In this mesh, the MOPP Data Size is 21497, and I have no idea how it relates to the collision vertices, so I won't even touch it. The easiest thing to do is to take it out completely. To do this, go to the block one level higher, bhkRigidBody, and change the "shape" reference to the block after the bhkMoppBvTreeShape block, which is number 4- bhkPackedNiTriStripsShape. Doing this removes the bhkMoppBvTreeShape block out of the tree and to the bottom, so you can then cleanly remove it. You now have a useful spiral stairs!

Editing Mesh Properties in Small Sections[edit | edit source]

The above editing is very useful and easy, but often you will need to edit the different parts individually in order to customize meshes to your needs. Adding a "hole" to a mesh is very useful- I will show you with the ictowermiddle01.nif mesh. This is also found in the meshes/architecture/imperialcity/interior directory.

I want to add a hole in one side of this that can be used as a doorway. Of course, all of the sides are on one NiTriStrips block, so I will have to edit the data individually. Clicking on a side reveals that block 8 contains the data I expanding the "vertices" array shows you all of the vertices, and clicking anywhere changes the lines to vertices. The most useful thing is that, as of NifSkope 0.9.8, the selected vertex is displayed in yellow and is enlarged.

The hardest thing is where to start. I will start at the bottom. The lowest point (Z-axis) in this data appears to be -151.012. My plan is to bring down all of the points that make up one wall to this point in order to open up a hole. I ended up taking down the vertices with an array index of 151 to 161 to this lowest point. There were still a couple of left over vertices. The NifSkope shading can be EXTREMELY hard to see, so the best method is to be smart about the coordinates. Trail and error is the only way though, and save often so you can go back so there aren't any "mistakes" that you can't fix. Once you have taken down all of the coordinates, you will have your hole, BUT collision is still there.

You have two options. You can delete all of the collision data, or hunt down the two triangles that are blocking your doorway. Deleting all of the data is easily done by using "Remove Branch" on the bhkCollisionObject block. The other method is much better, but harder.

The best way for a mesh like this is to find the different levels. What we're looking for is a starting point- we need the array number of one vertice in the triangle we want to delete. Find the collision vertices and start taking notes. We'll start with the Z axis- notice the different levels. The highest level is 14.274/14.243, followed by 12.912, followed by 11.107, which is followed by 10.204. I also notice that my vertex will have one of the highest X values because it is at this far end of the mesh, and a slightly negative Y value. I save first, then find the point by searching for X = 53 or 54 while Z = 10.204, and test each candidate by adding in some large z value and seeing if my point moves. Then I can find the array index of the point and close and reopen the mesh. I find my vertex as number 613.

I can now open the triangles array and find the corresponding triangles. This is very easy because the triangles ascend by the first vertex entered. I find that triangles 358 and 359 use this vertex, so I set both of their vertex data to all zeros. This will not erase the triangle, but will render it ineffective. This is useful because now you do not have to do anything with the MOPP data like before. I find that both triangles disappear in front of my new doorway. Whew! It is tedious to be sure, but not quite as bad as it sounds.

Adding Collision[edit | edit source]

In some cases you may want to add collision. While it would be almost impossible to add collision manually, vertex by vertex and triangle by triangle, two options exist. The mesh I will use is the icpalacetower01 from the meshes/architecture/imperialcity directory.

If you want to use this mesh where the player can get close to it, you may be frustrated in that it has no collision! The first option is to copy the whole collision branch from one mesh to another, especially if they are about the same shape. You can then scale and translate the mesh with in the bhkRigidBody or bhkRigidBodyT block. That obviously won't work in this mesh though because there is nothing like it.

There are certain simple shapes that you can use for collision. By far the most common is the BoxShape, found here and there. CapsuleShape is just as useful though- we'll use it here. First insert a bhkCollisionObject, then a bhkRigidBodyT, then a bhkCapsuleShape. In the bhkCollisionObject, make the "body" link to the bhkRigidBodyT, and in the bhkRigidBodyT, make the "shape" link to the bhkCapsuleShape. Now your three blocks should be in a tree. Then select the base NiNode, which is numbered 0, and make the "Collision Object" link to the bhkCollisionObject. Finally, you will want to edit parameters on this capsule. Set the Radius to 75, the first point to 0,0,1500, and the second point to 0,0,100. I don't think Radius 1 and Radius 2 have any effect. You should see the capsule now; it will cover the smallest and longest tower extension. then go to the bhkRigidBodyT block and set the rotation to 0,0,18 in the YPR, not XYZ setting. This will make the capsule fit just a little better to the beams.

What about the rest? You can assign collision to any NiNode, but only one at a time, So you will need a few more NiNodes. First insert 4 more NiNodes. Then go to the 0 Ninode and set "Num Children" to 4. Update the Children array and then change the links to the four NiNodes you just made. Now you can link the NiTriStrips blocks to the four NiNodes you just made in any way you choose. I am not sure if each NiNode must have at least one data block attached, but you have might as well do it. All of the NiTriStrips must be attached to some NiNode! Now you can copy the collision branch you made earlier, paste it, and then link to it from the NiNodes you just created. Play with the settings to match the larger tower parts, like for the second capsule, you would use radius 100, first point 0,0,569, and second point 0,0,100. The very bottom of this mesh presents a problem. If I was going to plant this tower into the ground I could just make a big capsule for the base, but since I'm not, I will just leave it alone. You can also replace the CapsuleShape for a BoxShape to fill out some of the tower extrusions- I put two boxes at the top so a player can at least stand on the tower.

If you had a mesh where you needed more collision objects than NiTriStrips, you could create a NiNode that links to a NiNode that links to a NiNode... etc... until you wanted to finally link to the NiTriStrips data.

Animation in NifSkope[edit | edit source]

Animation in NifSkope is a fickle thing- everything will have to be just right. Considering the complexity of the required data blocks, it is best to take an existing animated mesh and copy and paste its animation, or swap its NiTriStrips, where you can then make any changes. Remember the old saying: If you fail to plan, you plan to waste a ridiculous amount of time playtesting and editing things in your animation. This holds true even in this case..

Single Object Animation[edit | edit source]

This is the easiest way to add one kind of animation to a NiNode. We'll start with something simple- I will make an elevator. A simple animation can be found with the mesh brudoorupperfull02.nif in meshes/architecture/Bruma. Even though it is a door, it will work fine for us. Once you find the object you want to animate, you only have to swap this door's NiTriStrips for your meshes NiTriStrips, and everything is setup. Just find the NiTriStrips of this door, which are 25 and 32, and delete the entire branch. Then paste in as many NiTriStrips blocks as you want and set than as children to their NiNode, which is 20. You will change the "Num Children" value in this block to the number of blocks, and update the array, then link to the new data blocks. You can also replace the collision in this manner. All you need to do to set it to the NiNode after pasting it in is to link to it via the "Collision Object" value, and then in the bhkCollisionObject block, set the "Parent" to the NiNode to which it is attached.

This is where planning comes in, because every time you want to change, for example the length of your amimation, you will have to change at least 6 values in different places. For this elevator, I want an animation time of 12 seconds. Notice the sequences labeled Forward and Backward- these are pretty self explanatory, and do not have to be equal in time or anything, however it is good to have one begin where the last one stopped. Potentially you could also have more than two sequences. The problem lies in scripting it in the CS. There are already two sequence scripts to use, but I do not know of any three or more sequence scripts. In this mesh, the two sequences are named "Open" and "Close".

To start, change the "stop time" value in the NiControllerSequence and the NiTextKeyExtraData block for both sequences. Notice there are three text keys: the particular text key you want is the last one with the "end" value, but note the others control when sounds are played during the animation. The new animation time may or may not be displayed when animated in NifSkope, but either way, it definitely will when you save and reopen the mesh. Next you need to edit the actual animation data. You want to find the NiTransformInterpolator block within each sequence. There will be three actually, but only one will have a child block called NiTransformData. First set the "Num Rotation Keys" to 0. Then set the "Num scale keys" to 0 (this particular mesh has 0 for this value by default) and update that array. Obviously you could use both of these if you wish for your animation. When you need rotation, you only need to set the "Num Rotation Keys" to 1, because there is another value to actually create more keys. Then set the "Rotation Type" to 4 or XYZ_Rotation_Key. This will give you three sets of keys which affect the XYZ axis' respectively. Note that the value of rotation is not in degrees- it is in radians. A turn of 90 degrees requires a value of .5/pi, which is ~1.57.

Onto the translation data, which is relatively easy to set up. Set at least two keys and update the array. Then use 1 for linear keys or 2 for quadratic keys for Interpolation, The difference of which is explained somewhat below in the misc section (NifSkope does not do the quadratic interpolation, so you can only test this in-game). The first value must start with time 0 and the last with the stop time of the animation. Obviously the coordinates specify the position of the object at that particular time. The first animation sequence, here named "Open", should play first, but if you want to switch them later, I have had success with just switching the names of the blocks, instead of messing with the CS script.

In this example, my two keys for forward are time 0, position 0,0,0 and time 12, position 0,0,-1000. Backward is time 0, position 0,0,-1000, and time 12, position 0,0,0. This is pretty simple, and you will have a working elevator.

The only other thing you must do is to prepare the collision data for animation, which you can read about below, and set up the script in the CS- also below.

Multiple Object Animation[edit | edit source]

You might want to animate separately multiple blocks within one mesh. This can be done pretty easily using a mesh that is already setup for this. The GroundPlate.nif from the meshes/Oblivion/citadel/smalltower folder is perfect for this. The best way to deal with this is to copy your NiTriStripsData that you want to animate, and attach it a NiTriStrips data block in place of the existing NiTriStripsData. You will also have to replace the collision data. This particular mesh has five NiNodes- the first is the actual elevator, and the last four are the wheels and wheellocks. In total, there are 11 different NiTriStrips blocks that are animated, which take 9 different animations (the plate, the spike, and the long thing under the plate are on the same animation). If you want more, you'll have to experiment.

After replacing the data, the removing the NiTriStrips you don't need, you will want to undoubtedly translate, rotate, and scale the different meshes you have combined. This must be done with the NiTransformData from the NiTransformInterpolator! I explain why below in the misc tips section.

By studying this mesh for animating multiple objects, most things are fairly evident. The biggest unknown for me is how the various NiTransformInterpolators are linked to their respective NiTriStrips. You will have to do some trial and error to find the correct motion data to your NiTriStrips depending on what you replaced.

Preparing Collision for Animation[edit | edit source]

There are several settings on static collision blocks that needs to be changed in order to make it animate. These are all applied to the bhkRigidBody or bhkRigidBodyT block of the collision. First, it must be a bhkRigidBodyT block, because NifSkope claims that the "T" at the end marks it for animation. Next, change the "Layer" and "Layer Copy" to 2, which is OL_ANIM_STATIC. Next, set the "Motion System" to 6, and "Motion Quality" to 2, which is MO_QUAL_KEYFRAMED. This will allow the collision to follow with the animation.

Scripting the animation into the CS[edit | edit source]

I'm not a scripter, so my method is straightforward. The first thing you need to do is rename the animation sequences to match the premade script I am going to tell you to use. The first sequence should be "forward" and the second sequence should be "backward" (change from, for example, the door mesh above, which uses open and close).

Important Miscellaneous Tips[edit | edit source]

Linear and Quadratic keys[edit | edit source]

Note that quadratic key data will look exactly like linear data in NifSkope, but will play back correctly in-game. Simply changing from linear to quadratic data will make the motion start and stop smoothly. This is a godsend when you only have NifSkope for animation. When the official meshes have animation, they always use linear keys for translation and have 30 keys per second to make it smooth; it is very hard to do the same in NifSkope. When there is rotation movement, they usually use quadratic data, I don't know why. I don't know the formula for the forward and backward tangents that become available with quadratic keys.. I would love to know though- I have not tested their effect.

Relative Motion[edit | edit source]

All settings for animation are relative to the scale of the mesh in the Construction Set. An object moving 1000 units in NifSkope, and is scaled to .6 in the CS, will only move 600 in-game units in the time of the animation. Other than that, NifSkope units and CS units align perfectly.

Fast Motion[edit | edit source]

Oblivion does not handle fast moving stuff well. After exhaustive testing, the maximum speed that anything can move without problems appears to be just over 300 units/second (this is the absolute speed in-game, after scaling is applied). My conclusion is based on an elevator I was making. At fast speeds, the player would fall through the elevator, or get stuck on nothing momentarily, or be quickly propelled down through the elevator. Either way, the result was not satisfactory, and seemed to be collision related.
Also note that in areas that lower the framerates on computers, being on a moving object will cause it to seem to stutter, sometimes violently, and the faster the worse it is. This is probably caused by the V-sync not being on, which lowers framerates and is not on in the default setting.

applying trans/rot/scale to objects[edit | edit source]

Animation data will override applied translation, rotation, and scaling you have done to the mesh's NiNode! Even if you do not use a certain type of animation, for example rotation, but want the object always rotated, you may have to set this with the animation keys. Simply setting the rotation in the NiNode that the NiTriStrips are attached to will not work in the game, even if it works in NifSkope. I haven't tested this extensively, but I have had this problem (especially with scaling collision), and this is how I fixed it.