• 0

    posted a message on Model Animation

    I've looked into the smoothing, it's because your importing the model through the OBJ importer in 3ds max. It uses an algorithm to automatically smooth faces based on their angles to one another when no smoothing groups are provided, I'm assuming the SC2 engine does something similar. I'm not sure how to do this through my script, but I've checked my normals against the ones present in your OBJ generated files and they're the same. I'll try and hunt down some maxscript code that does similar smoothing to the OBJ importer.

    I'm also interested in figuring out the basic information an M3 requires for rendering. It'll be easy to export static mesh geometry at this point, the only problems I foresee are the materials with their layer information. However I believe alot of the values are mostly pointless (such as the many animation ref's) so it won't be long before we can start putting custom models into SC2. My concern is that we're at a road block with animations. Until we figure out what's going wrong, we're going to be stuck with just geometry exporting capabilities, and that's not much fun.

    Posted in: Project Workplace
  • 0

    posted a message on Model Animation

    Hrm? Which seams? The normals seem fine to me, can put up a shot of the max normals or you can look for yourself in max. You don't have to do the player colours by hand Sixen, I'm just rendering them with no colour. Witchsong is correct. Really have to figure out these animations and why they're going so wrong. It's confusing because some bones seem to go where they should be while others are completely messed up.

    Posted in: Project Workplace
  • 0

    posted a message on Model Animation

    I got the zealot and marine vertices all good now:


    The immortal is still messed up, I'll work on it later. I'll explain how I got the zealot and other bindposes looking proper later too :).

    Posted in: Project Workplace
  • 0

    posted a message on Model Animation

    Initial Reference (fancy wording for bindpose?) would be my guess. Yes, so far as I can tell the matrix has no impact on the bone itself. The bone bindpose is setup through the scale/rotations/translation values found in the bone chunks. The IREF values seem like they're only used for putting vertices in the bindpose position. I'm thinking you could move the vertices to their IREF positions then have the bones carry them to the bindpose position, but I'm not getting good results trying that method through maxscript.

    I've found a guide on how to calculate final vertex positions with vertices weighted to multiple bones in this MD5 guide which I've added to my new M3 import script. The M3 format is extremely close to how the MD5 format is read, at least when it comes to bones/vertices/bindposes and animations. Even moving the vertices with multiple bone weights, there's geometry ending up where it shouldn't be. The immortal is very tricky, its left cannon is completely reversed. The zealot's bones do not animate as they should (check out the Fidget_Full animation to see what I mean) and its blade vertices seem bound to the wrong bones and consequently positioned incorrectly. I'm definitely missing something major when it comes to animations. My bindposes are almost identical to how they look in-game for most models, but some such as the immortal and the zealot have vertices seemingly weighted to bogus bones and ending up in weird orientations/positions. I'll keep investigating, there's something we're missing.

    Posted in: Project Workplace
  • 0

    posted a message on Model Animation

    This is mostly for witchsong and myself, but feel free to eavesdrop :)

    I'm going to explain how I setup the bones/mesh in my maxscript plugin. I'm not very good with matrices, so maybe you can shed some light on what I may be missing. To begin with, I have noticed alot of parallels between the MD5 (doom3) model format and M3. I believe they use similar methods to animate their models. You can find out more about the MD5 file format at Doom3world.

    Bone Arrangement

    The IREF chunks in M3's seem to contain the transformation matrix for each of the bone nodes. However this is not the bindpose, the nodes are additionally positioned, orientated and scaled through the bone chunks all relative to the parent. In my script I don't even use the matrices to arrange the bindpose bone setup.

    First, I create all the bones, then I set up the chain by linking all the bones with parents to their parent bone. After that I iterate through the bones based on depth so that I begin with bones furthest from the root bone of the chain. Then I apply the scale, rotation and position (in that order) to the bone in the coordinate system of the parent bone (in maxscript you have to indicate the coordinate system) for all the bones so that the root bone is done last. I'm not sure if this is the correct way to go about arranging the bones but it gives me what I believe is the bindpose of the model when no animation data is present. That's the bindpose of the bones covered. Code is here:

    mb = mread.bones -- M3 bone chunks
    for i = 1 to mb.count do -- iterate through bone chunks
    	b = mb[i] -- assign b current bone in iteration
            -- create bone node, placement seems irrelevant as changed later
    	cb = BoneSys.createBone [0,0,0] [0,0,0] [0,0,0.1] 
            -- 3ds Max settings, nothing important just visual elements
    	cb.name 		= b.name
    	cb.width 		= bonesize
    	cb.height		= bonesize
    	cb.showLinks	= true
    	cb.boneScaleType = #none
            -- append the cb node onto cbones array (maxscript dynamically enlarges array)
    	append cbones cb
    max views redraw -- redraws all viewports
    -- After bone nodes are created, link them together
    echo "Setting up bone hierarchy"
    for i=1 to mb.count do -- iterate through bone chunks/nodes
    	b = mb[i] -- current bone chunk
            -- Maxscript uses 1 based arrays instead of 0 based
            -- -1 for no bone becomes 0, 0 becomes 1, and so forth
    	if b.parent!=0 then -- if bone has a parent...
    		cbones[i].parent = cbones[b.parent] -- assign the nodes parent
    echo "Set up bone depth"
    -- sort bones by depth function, returns an array of depth assorted bones with 
    -- x and y members. x indicates depth of bone, y indicates the bone
    local bd = M3_Get_Bone_Depth mread.bones
    echo "Set up bone transform"
    for i=1 to cbones.count do -- iterate through bone nodes
            -- Do deepest bones first
    	local h = bd[i].y -- h = bone to transform
    	b = mread.bones[h] -- M3 bone chunk
    	cb = cbones[h] -- 3ds Max bone node
    	in coordsys parent -- in the parent coordinate system
                    -- apply the scale, rotation and translation in the bone chunk
                    -- to the bone node
    		cb.scale = b.scale
    		cb.rotation = b.rot
    		cb.position = b.pos

    Vertex Setup

    Now the bindpose is not arranged so that it deforms the standard mesh, so you need to adjust the vertices so that the mesh fits the bone placement. The way I do this, I really don't understand the math completely to be honest, but it seems to work at least partially. Iterating through each vertex:

    1. Multiply the original vertex position by the IREF matrix of the first bone it's weighted to (I assume there's a way to do all the bones a vertex is weighted to but I don't know how yet)
    2. Multiply the new vertex position by the scale, inverse rotation and position of the bone. The rotation is the inverse due to the way 3ds max stores transform matrix rotations.
    -- 2. for each vertex, setup the bone weights and adjust the vertex position
    for j=1 to mread.verts.count do -- iterate through vertices
        v = mread.verts[j] -- current vertex
        for h = 1 to 4 do -- for each of the possible bone weights
            if v.bw[h]>0 then -- only if the bone weight is larger than 0...
                k = v.bi[h] -- the bone lookup index associated with that weight
                -- grab the bone index from the bone lookup (+1 as maxscript arrays are 1 based)
                b = mread.blist[k] + 1 -- bone to adjust the vertex by
                if h == 1 then
                    -- only adjust based on the first bone weight for now
                    -- multiply original vertex position by the bone IREF matrix, returns new position
                    pos = v.pos * mread.IREF[b]
                    pos = pos * cbones[b].scale -- adjust position by bone node scale
                    pos = pos * (inverse cbones[b].rotation) -- by bone node rotation
                    pos = (pos + cbones[b].position) -- by bone node position
                    meshop.setvert m j pos -- move vertex to final calculated position

    Hopefully that makes a bit of sense. I know maxscript can be confusing to read coming from C. Now I know the bones/mesh seems a bit off. I'm not sure why, I think this is as far as I can get. Figuring out the rest will be up to someone who has a better understanding of matrices and such.

    I've got a few models to compare to show that my bindposes are at least mostly accurate. The in-game shots are done by blanking all the animid's in the bone chunks so that they don't reference any sequence data. All you're left with is the bindpose of the model. I notice that some meshes aren't in the right place, I believe this has something to do with vertices that are weighted to multiple bones which I'm not taking into consideration, and also attachments using their own transformation matrix.

    Comparison shots:
    http://fooo.fr/~vjeux/curse/sc2/news/m3anim/HydraComp01_small.png http://fooo.fr/~vjeux/curse/sc2/news/m3anim/ImmComp01_small.png http://fooo.fr/~vjeux/curse/sc2/news/m3anim/MarineComp01_small.png

    Immortal has bad geometry, something I need to look into

    Posted in: Project Workplace
  • To post a comment, please or register a new account.