NifSkope Editing
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)
Modifying an Existing NIF
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
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
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
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
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
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
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 BrumaUpperDoorFull02 in meshes/architecture/Bruma. Even though it is a door, it will work fine for us. It is helpful to have your final mesh setup the same as this door- There is a NiNode with another child NiNode, which then has the NiTriStrips data. On the Bruma door mesh, rename the base 0 NiNode from "BrumaUpperDoorFull02" to whatever your final mesh is, and its child NiNode from "BrumaUpperDoorFull02 NonAccum" to whatever the equivalent NiNode is in your mesh (which is the NiNode that has the NiTriStrips data). This will allow you to copy the entire NiTransformController branch, and paste the whole branch into your mesh. In your mesh now, for the 0 NiNode, set the "Controller" value to the controller block you just pasted. After this step, your mesh should have the animation that the door had.
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 usually 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. There are already two sequence scripts to use, but I do not know of any three or more sequence scripts.
To start, change the "stop time" value in the NiControllerData and the TextKeys block for both sequences. 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, which will be useful later on. The new animation time may or may not be displayed in NifSkope, but either way, it definitely will when you save and reopen the mesh. Next you need to edit the actual animation. You want to find the NiTransformInterpolator block within each sequence. There will be three actually, but only one will have a child block called NiTransfromData. First set the "Num Rotation Keys" to 0. Then set the "Num scale keys" to 0 and update that array. Obviously you can use these if you wish for your animation. When I need rotation I only need to set the "Num Rotation Keys" to 1, because there is another value to actually create more keys which affects the array. This will give you three sets of keys which affect the XYZ axis'. Note that the value of rotation is not in degrees- it is in radians- so a turn of 90 degrees requires a value of 1.802.
Onto the translation data, which is relatively easy to set up. Set at least two keys and update the array. The first value must start 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 difference between Linear and Quadratic keys is explained below in the Miscellaneous Animation section. Realize that it is easiest to just let the forward animation play first. If you want to switch them later, I have had success only with actually changing the blocks, instead of the script. This is easier than messing with scripts, because all you must change is the name.
In my example, I 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.
Multiple Object Animation
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 NiTriStrips. This must be done with the NiTransformData from the NiTransformInterpolator! I will give an example: if you want to move a rotated block of NiTriStrips, in addition to the translation keys, you will need XYZ rotation keys to set the desired rotation. Simply setting the rotation in the NiNode that the NiTriStrips are attached to will not work in the game, even though it works in NifSkope. I have only tested this with rotation, however- I do not know if scale or translation acts this way. I still use the NiNode settings to find the exact value I want to use, then plug them into the NiTransformData blocks.
Preparing Collision for Animation
There are several settings on static collision blocks that needs to be changed in order to make it animate.