| Class: MilkSkeleton | urdpyg/milk_skeleton.py | ||||||||
|---|---|---|---|---|---|---|---|---|---|
|
----------------------------------------------------------------------
Data structures.
- Skeleton - this is where everything is put together. - we may want to share some data between skeletons, so we may need a higher level system. - this higher level system would share the different parts of memory. - Maybe it could even transform all of the data at once. = BoneHeirachy DONE. = Keyframes = Bone2Vert_Map DONE. = Time2Keyframe_Map = KeyframeNumber2Time_Map Keyframes - collects the different keyframe data for a skeleton. = AbsoluteBones = RelativeBones = Time2Keyframe_Map = KeyframeNumber2Time_Map AbsoluteBones - bones represented in their absolute form.
- Need matrix, and quat+pos_vector versions
- The matrix versions would be used to transform verts.
- The quat_pos_vector versions will blend with other bones.
- The conversion to matrices will need to be cached.
- Use three arrays.
- rotation quats( an array of RelativeBones - these bones will have all relative data. Eg each bone will only be relative to the others. Time2Keyframe_Map. - gets two keyframes on either side of a given time. - this would be per bone? Not at the moment(it should be per skeleton). KeyframeNumber2Time_Map. - given a keyframe number, give the time for it. - this would be per bone? Not at the moment(it should be per skeleton). DONE. BoneHeirachy - which bones are parents/children of which other bones. - has bone names, and bone indices into AbsoluteBones/RelativeBones. - GetChildren_names/indices - returns a list of names/indices. BoneName2BoneNumber_Map - mapping of bone names to a number in the bone index. DONE. Bone2Vert_Map - a list of indices for the verts that each bone should transform. Vert2Bone_Map - vert to list of bones which effect them. MilkBones - this is the data from the milk format. This contains the positions, and rotations in euler format, and the keyframe times. local2world_transform - a transform specifying where in the world the skeleton is. - This will likely change occasionally. - from every frame to once every minute. - is this specified by the root node? - Could we add this as the new root node? - would simplify the code if we did. - Can be added as an after thought if needed. Pretty easy. - Not really, as it possible this would change all the time. - We may want to add this, as it will solve having to re-transform them. - On the other hand this could be done in hardware with gf+ cards. ---------------------------------------------------------------------- --------------------------------------------------------------------- Order of the operations. - Things that need to be done in order to get the model transformed. Set up stuff. - things to do around load time.From the milk bones set up: - BoneHeirachy - Set up the relative bones. - Convert the Euler angle milkshape rotations into quaternions. - Convert the milkshape positions into quaternions. Q(Px, Py, Pz, w =0.0) - rotation, position quaternions multiplied and stored.
AbsoluteBones are made from RelativeBones. For each keyframe. Multiply the bones down the heirarchy. child.absolute = parent.absolute * child.relative Per frame stuff.Get current time in animation. From Time2Keyframe_Map grab two keyframes on either side of current time. For every absolute quat: Interpolate between two keyframes: t1 = current_time_in_animation - kf_a.time t2 = kf_b.time -kf_a.time slerp = t1/t2 frame_now = quat_slerp(kf_a.absolute, kf_b.absolute, slerp) Generate the matrices for each absolute quat. Transform each absolute matrix by the local2world_transform. Transform verts of the mesh: For vertex which is affected by one bone: For each absolute matrix transform its verts. If the vert is only affected by one bone: Multiply the vert by the absolute matrix. else: somehow interpolate the different bones. - TODO: ^ - maybe this could be done in the slerp? - storing some extra absolute quats for the verts affected by multiple ones. - this is where bone weights can fit in. For now we will only support one bone per vertex. Alternate way to transform the skin: For each vertex: look at the weight structure. ulong32 boneIndices - 4 indices to bones. ulong32 weights - 4 weights. --------------------------------------------------------------------- Optimizations. --------------------------------------------------------------------- When a key frame does not have any translations the transform of the vertices can be optimized to only use a 3x3 rot, instead of a 4x4. - There may be other optimizations depending on the bones state. - Maybe we could store a BONE_STATE int which will allow us to quickly identify a type of bone? This would allow us to quickly see if the bone has no translation. - We could group bones of similar nature together to make the transforms quicker. Eg all bones with no translation part could be stuck together. - Remember that we need to apply a local2world transform to all of the different absolute matrices. We may be able to cache certain different transforms. - I'm pretty sure there will be many repeated transforms. A cheap way to interpolate between keyframes would be linear using the mesh's verts. This would involve calculating the mesh for each key frame, and then interpolating between each vertex in meshes a, and b. Perhaps this could be an optional thing. To be used for slow computers, when a character is far away, or when the difference in time or movement of the character is really small. A downside to this is that you need to keep at least three sets of the mesh around at any time. An upside to this is that interpolation can be done on lighting values too. --------------------------------------------------------------------- --------------------------------------------------------------------- TODOS: Future todos: - have keyframe data for seperate parts of the skeleton. - eg make the hand have it's own keyframes. - This would complicate how to construct the absolute quats. - You would recalculate down from the animation for that part. - so if the arm was using some extra ones we'd go from there.
--------------------------------------------------------------------- --------------------------------------------------------------------- Dependencies - a list of different dependencies that need to be considered. - helps with caching different things. --------------------------------------------------------------------- --------------------------------------------------------------------- OLD Order of the operations. X Convert the axis angle milkshape rotations into quaternions. X The translations should also be converted into quaternions, X and multiplied by the rotation part. Q(Px, Py, Pz, w =0.0) X Have an absolute quaternion, and a relative one for each bone. X Quats should be seperate for the current frame that is to be rendered. X - that is the final bones for the current frame should be in a single X array. X - this is so that they may be easily converted to matrices. X Absolute matrices for the current frame should be made. X - these matrices include For each keyframe. Multiply the bones down the heirarchy. child.absolute = parent.absolute * child.relative To interpolate between two keyframes we do: t1 = current_time_in_animation - keyframe_a.time t2 = keyframe_b.time -keyframe_a.time slerp = t1/t2 frame_now = quat_slerp(keyframe_a.absolute, keyframe_b.absolute, slerp) Any time a bones rotation changes we need to recalculate all of its children. To transform verts of the mesh: We need the absolute matricies for each bone. Do we support multiple bones per vertex? If so will we use weighting? Apply a local2world transform to all of the different absolute matrices. - this should be added as a new root node.
|