Non-Destructive Nodes

 
I. Exporting the Rig for Stable Editing

1. With Milkshape still running, File--Export--Half-Life SMD..., which pops the Save As dialog.
2. Name the Export file: "m7player[ref].smd", click Save, then the SMD Export dialog pops and prompts for some radio box parameters. There should be 3 choices: Reference, Sequence, & a new Vertex Weight (HL2) parameter.
3. Check the Reference radio box and the OK button to finish the Export.
4. In the developers' favorite text editor/IDE, open the "m7player[ref].smd" file and examine the lines of script that comprise the object within the Milkshape3D Scene, as a text file. Since this is a Reference SMD, the data is in 3 Lists: Nodes Listing[sound familiar? which represent the Joints string literals], Skeleton Listing[which 2 tuples represent the coordinates], & the Triangles Listing[which represent the vertex coordinate positions for the Faces. This last List of the Triangles will not be edited in this Process. It essentially locates the mesh Groups in relation to the Nodes/Joints that they are weighted to.
Side Note: This whole process could 'probably' be accomplished by utilizing the Milkshape3D ASCII format which generates a text based file as the SMD format. The native Milkshape ASCII file will be quite a bit larger and a tiny bit more difficult to manage. I use the SMD format, because of the bare bones data needed to trasnfer the values, :). There's a little quirk to workaround, but all in all; an easier method for this author. That's all!
5. Notice from the included image above the Nodes & Skeleton Lists. They appear to be simple indexed arrays that hold all the values. You will no doubt quickly see the format's outline. First there is the index #, followed by the string literal for the Joints naming convention, and then follows[the really cool part!], it's Parent Node. Following is the Skeleton List. This Listing gives our index# of the Node/Joint, followed by some very familiar constructs. The 2-tuples indicate the Position & Orientation of the Node, in relation to it's Parent Node! That's how the format keeps data to a minimum and helps us do some very quick editing. The Time0 heading indicates this is referenced from the Scene Root[Node{-1}, I think] and contains no animation.

II. Editing the SMD File to Include a New Node

1. Begin by deciding what to name the next Node in the developers' design.
2. Add a new line under the Nodes List for the next Node in the index{28}. This will be our new Node's index#, the name will be "Mount3" for this example, and then the all-important Parent Node declaration of {10}; which will Parent this Node to the "Bip01 R Hand" Joint[which happens to be index#{10}]. Here is why this is so cool; editing in this fashion and then Importing this newly edited SMD Reference file will result in a new Node added, without disturbing the existing Transforms, since we're applying the values for this new Node from the Parent's coordinates. That's the easiest way for me to describe the Top Secret method for adding Nodes.
3. Add a new line under the Skeleton List for this new Node, just established in the Node List above and give it the same index# as in the Node List above, {28}. Give this Node these values: "0.000000 0.000000 0.000000 0.000000 0.000000 0.000000". This is another interesting part that perhaps needs a little explanation as good as this author/artist can explain this math and how it relates to our manipulation of a skeletal rig. By giving the "Mount3" Node this value, we are Positioning & Rotating it this value; referencing the Parent's local coordinate system/position/orientation. This last bit I'm not 100% certain is true; this is my observation from Trial/Error/Discovery Method of problem solving. It is subject to change as I experience and educate myself. This means that when this file is Saved & Imported back into Milkshape, and the Joint is selected/highlighted; it will be exactly stacked on it's Parent. This is something that is extremely difficult to do with the UI's current control system, in my opinion. If it takes editing a file, textually; I don't mind at all, ;), it solves a problem that existed for this author, perhaps others.
4. After adding the 2 new lines to the 'script', m7player[ref].smd, Save the file. I hope archival procedures don't need to be continously addressed as a Step in the Process.
Side Note: Normally I would begin to plug values into the tuples for the new Node and be on my way, however; this is a Guide to the Process, and to that end, I'll continue with the Discovery part to give a fuller understanding of how to work this alone. There are a few little quirks to demonstrate and workaround. There is hardly any Process that doesn't have one.

III. Checking the SMD Edits Visually in Ms3D

1. After Saving the edit work done to the SMD in the IDE, in Milkshape3D: File--Import--Half-Life SMD... and select "m7player[ref].smd" and Open. The Import Options dialog pops and prompts for some radio box parameters. Select Triangles[the mesh] and Skeleton[the rig]. Do not select Rename Bones. This is a CounterStrike specific setting and will rename the Joints to match the existing skeleton in the Scene, if the coordinates are the same, but the naming convention differs, 'I think'. Never did CS, so it's moot to this author.
2. Take time to examine the new skeleton! Bring up the Joints Tab, and select the "Mount3" Joint. It should highlight red[if default config is used], and it's coordinate system axis is highlighted the 3 cardinal colors associated with them in the default Preferences. Take note of it's orientation. Now, select the "Bip01 L Hand" Joint. It should highlight green[default config], and it's coordinate system's axis is highlighted in the same manner as the "Mount3".
Side Note: The cardinal colors for the Ms3d coordinate system are: X[-right to +left]= Yellow, Y[-down to + up]=Cyan, & Z[-back to +forward]=Magenta. These are different than Torque's coordinate system, however; the exporter seems to do the calculations necessary to offset this difference, and we should adopt the Ms3d colors as our coordinates and not the Cartesian setup we expect to see. Whew, that made nearly no sense. It will when we begin to manipulate the SMD tuples, ;). When examing the Joints List, the newest Node, while Parented to the proper Joint, is not nested underneath it in the psuedo-hierarchy the program builds to display the chain. It will have no effect on the resulting DTS hierarchy!
3. The image above may make it easier to see that the two separate Joints are indeed in the same reference position/orientation. This hardly does the developer any real gain as it would need scripting to offset the mounting of an ImageShape correctly. Eventually, we need to have the Magenta axis pointing along the forward plane of the hand[Ms3d-Forward/FrontView]. As it is now; it's pointing straight up, er..and to the right[which would put it to the TGE X+ axis when brought to bare weaponery in a 'neutral/gun forward position', not what we want!] This step was meant to give a broader understanding of Milkshape's environment and how we need to proceed. Without Saving this SMD Import as a Scene, clear the UI by File--New. We have just added a new Node to an existing Hierarchy, without disturbing the existing values! That is the most important fact about this whole Process and I can't emphasise it enough. This is very good news for any work previously done and needing some 'tweeking'. This may save countless hours reanimating a shape, all at the expense of some minor quirks. Once I established the workflow[and my key tuple values], I very quickly maxxed out the default code with a total of 8 Mountpoints on the playerClass shape. Now, to locate and orientate this newest of Nodes. We will be editing again in the developers' preferred IDE.

IV. The Easy Bit & The Ugliest Part

Side Notes of Tedium:
This next section is going to get difficult to understand and where the tedium arrives. It's time to locate and orientate the Node to be of some eventual use to the developer following along and to make any further additions easier to deal with. This first Node was extremely frustrating to get right. It took a number of back/forth attempts to even begin to comprehend the system used to record the values in the orientation tuple. The location was easy; with the caveat that what you 'normally' expect to see in a tuple(X,Y,Z), in the SMD format is slightly reversed. The Z/Y positions in the tuple are swapped, meaning the value in the SMD file reads: (X,Z,Y)-in relation to the UI's coordinates used for control inside Milkshape3D. Another whew, that was thick. What made it 'easy' was it was in native Ms3d 'units' which are equal to 1 meter. So, for example, if I wanted to move the Node 1 meter in the Z+ direction[UP], the value of that tuple would be: (0.000000 1.000000 0.000000). Notice the amount of precision available, it appears to this author that I could position a Node to within a millimeter of where I needed it, I think, or better.

Not arriving here from an engineering/programming career; it got much more difficult for this author to understand the system used for recording the Orientation values. I'm an artist afterall, or at least I play one on TV, lol.... I started out by noticing that my cardinal orientation to sync with TGE was off. I need the Magenta axis forward, Cyan axis up, and the Yellow axis to left of the player, exactly Milkshape's native coordinates. I first noticed that it would be easy to rotate the axis by a large, stepped 'chunk', since it was essentially out of whack by 180 degrees in one direction and something like 90 in another. That didn't work at all, it gave very bizarre results once imported. To bring my understanding of the value system along; I sidetracked a little, for engineering purposes.

I needed to find out some conversion from what the UI understood in degrees of rotation, to what appears in a tuple. I found the easiest way for me was to create a simple cube primitive, texture it, create 3 Joints[unlinked], & finally Assign the cube's vertices to Joint1. These steps need to be taken to get a successful SMD export, it's expecting the object to be in a certain condition[textured & all verts assigned]. Also, when exporting, I believe the exporter expects the texture to be a .BMP[afterall it was originally intended for HL models] file and appends the string with the extension, automatically. It also gives the imported mesh that extension also. Simply rename the Group and Material, and reestablish the texture path. Eh, few more quirks, nothing life stopping. Ms3dASCII, again, may prove more 'friendly', but I find managing the file a little awkward in comparing the two indices, ;). I made certain the Joint created had the same orientation system that prevailed within the interface. Create a single Joint in any Viewport and observe. I next animated this shape in the axis I was absolutely certain of, X, and rotated the cube in 90 degree X+ steps, a full 360 degrees. After leaving Animation Mode, I Exported the file as a SequenceSMD this time, and examined the result in my IDE.

It gave me a lot of information to assimilate. The first observation I made was that the values appeared to be based on Pi perhaps...?? The second was that the further away from the cardinal UI coordinates the Joint was, the harder it was to figure the rotations needed to correctly orientate the Joint. This again involved setting up more animations with incremental rotations applied and then exporting to SMD format for evaluating the conversions. This was the ugliest & most tedius part of the whole Process. It took countless back/forths to establish the parameters I wanted. A table of some kind could be probably generated to help. From the above snapshot of the SequenceSMD, you can see the pattern beginning to develope with my next series of rotations in the Y+ axis @ Time6. The pattern repeated for Y, but not when I got to the Z+ rotations. Then, I got some negative values that broke the pattern. Starting with the key number of 1.570795, I began plugging it into a position of the tuple[and giving it a negative value when needed] and Imported the result, noted where/how far it moved, and continued; I finally had 'tweeked' my results until a reference weapon was mounted in the proper orientation for a default mounting[no scripting offset]. It was a bit of work, but I now have all this data documented to make it a little easier to do this very difficult task, again & again. As I progressed along, and added Nodes based off Joints that were very close to the UI's cardinal coordinates, my values never strayed far from the 'magic' number of 1.57095/6. It was either that value or a combination of it's mirror[-1.57095] that finished off my Node list. This ends a very poor explanation of Quarterion System math.... Time to complete the new Node on the Left hand, to mirror the "Mount0" weapon location.

V. Positioning & Orientating Mount3

Side Note: My deepest apologies for drawing that last Section out as long as it was. It was a very long part of learning how to do this correctly and I feel needs a full explanation of how I arrived at my results. I'll speed things along now, and give some 'magic numbers' to plug-in and make the left hand of the default player a little more useful to those following along, waiting for something to actually happen. Things will definitely, 'spin-up'; as from this point it's a regular Export to DTS from Milkshape.
1. Open "m7player[ref].smd" in the developers' preferred IDE/text editor.
2. Copy both the Position & Orientation tuple values of index#15[Mount0]. This string of the two values should be: (-0.192386 0.000898 0.047977 2.462168 -1.332946 -2.475295). Paste this value for index#28's Position & Orientation tuples. "Mount3" should now have the same values as "Moun0". If this were Saved & Imported into Ms3d and compiled into a playerClass shape. Mounting a weapon to the Node, will reveal the orientation not to be what the developer would expect.
3. Change the Orientation tuple to read these values: (-0.785398 1.332946 2.475295). By doing this, we 'mirrored' the Y/Z axis; since this Node is on the other side of zero to the shape, and the X axis needs a little rotating to get a weapon lined up correctly to compensate[assuming] for the difference between the two Hand* Nodes references. If you use these values and continue to compile, load, and mount a weapon in the ShowToolPro, you'll see the results pictured above in the snapshot. The playerClass avatar is now holding a weapon, orientated correctly in the left hand, along with the default right handed one, and loaded all the sequences! Continue the Process by....
4. Save the file: "m7player[ref].smd". Close the text editor.
5. Launch Milkshape3D, if it is not already running.
6. Import the file: "m7player[ref].smd", using the Triangles & Skeleton parameter radio boxes. Don't be overly concerned if there is an Error Message in the Message Window, Ms3d is unable to find the correct texture and it's not a Project stopping error. Texturing the export with a .BMP copy of the target texture will correct this, and I'll include a copy in that format in the package.
7. Examine the Scene to make certain the "Mount3" Joint is in fact in the Joints Tab and is part of the skeleton's chain by selecting it and observing it in a Perspective Viewport. If everything I've laid out is correct[and steps correctly followed], the Magenta axis is along the player's forward plane, the Cyan axis is pointing UP, and the Yellow axis is along the player's left side, more or less, depending on the hands current position.
8. Once satisfied the new Node is correctly positioned & orientated, Save the Scene as: "player.ms3d"
9. Bring up the Materials Tab and renavigate the path from (Mat.:defaultRGBPalette.bmp) to a texture bitmap the developer desires to see mapped to the "BoxyBoy0" mesh once exported, instead of the Rhi default provided. Rename the Material, to delete the .BMP extension, or just remove the extension.
10. Bring up the Groups Tab and select the only Group in the list: "defaultRGBPalette.bmp". Rename this Group: "BoxyBoy0", while still selected; bring up the Materials Tab, select the intended bitmap from the List, & Assign the texture to the Group. If the texture doesn't appear in a Viewport correctly or all Black, bring up the Materials Tab once again, and Clear All the Smoothing Groups with the provided button. At this time; the developer is free to re-Assign faces to Smoothing Groups if it's desired.
11. Save the Scene & BU the Scene. Another 'good' bit of information about the SMD format, is that it keeps the weighting of the original Vertex Assignments that were established in the our Humble Beginnings, also any UV mapping, so to me it's not much different than running a special Max script or using some plug-in. I find it somewhat reassuring to be able to manually 'control' what the program is doing, since that author has/had no idea what I'm up to right now, or could foresee my special requirements. I'm merely leveraging the existing technology to the best advantage.
12. Call up the DTSPlus! exporter and not the default one in File. You can load the DTSPlus! exporter into the File list, by utilizing the ShortCut & Plug-in Manageer under Tools.
13. Set these parameters in the TGE DTSplus Exporter dialog under Options:
Scale: = 1;
Use .cfg File: = true/Y/checked;
Export Animations: = false/N/unchecked;
Output dump File: = true/Y/checked;

I'll include a prepared .CFG file for this purpose and include it with the Resource materials. This Guide is focusing on a new technique and not on general DTS exporting.
13. Hit the ExportDTS button. Depending on system specs, the Process should take moments and there is no dialog signaling completion; the Save As dialog merely closes. Barring any unforeseen complications due to procedure of steps, the export should be successful, time to proof inside the engine. This will prove to need some setup to get working 'perfectly'. For one, there is no new pose to accompany this weapon, and no scripting to accomodate said weapon. Afterall; this is a free, online Guide, and additional materials supplied such as those would approach the level of a 'for purchase' content package.

VI. Proofing to a Valid Conclusion

Needing a quick solution to proof my concept, I decided the quickest & easiest way to provide it was for this author to make a very simple script edit to a file in the Demo MOD; to the flag shapeImage, and then take a snapshot of it mounting to the left hand via the calling in code by activating the button, during a default Mission[Features.mis]. As you can see, when the Flag button is activated during the Scene, the flag shapeImage mounts to the "Mount3" Node we created earlier in Milkshape3D, er, more accurately, TribalIDE. I positioned my cursor/arrow toward "Mount3".
 

Your Link

Your Link

Your Link
 
 
 

  HOME     ...more Rex     gS2DTS Setup     Mesh Prep     Shape Build     Gallery     Nodes w/o Destruction     Milkshape3D Blends