// First pass: calculate the transofmration matrix for each vertex // here we must associate a matrix with each bone (maybe with each vertex_id??) // then we multiply the current_bone matrix with the one we had before // (perhaps it was identity, perhaps it was already some matrix (if // the bone influences many vertices) ) // then we store this multiplied matrix. // in the render function we get a vertex_id, so we can find the matrix to apply // to the vertex, then we send the vertex to OpenGL public void RecursiveCalculateVertexTransform(Node nd, Matrix4x4 current) { Matrix4x4 current_node = current * nd.Transform; foreach (int mesh_id in nd.MeshIndices) { Mesh cur_mesh = _scene._inner.Meshes[mesh_id]; MeshDraw mesh_draw = _mesh_id2mesh_draw[mesh_id]; foreach (Bone bone in cur_mesh.Bones) { // a bone transform is more than by what we need to trasnform the model BoneNode armature_node = _scene.GetBoneNode(bone.Name); Matrix4x4 bone_global_mat = armature_node.GlobTrans; /// bind tells the original delta in global coord, so we can find current delta Matrix4x4 bind = bone.OffsetMatrix; Matrix4x4 delta_roto = bind * bone_global_mat; Matrix4x4 current_bone = delta_roto * current_node; foreach (var pair in bone.VertexWeights) { // Can apply bone weight here mesh_draw._vertex_id2matrix[pair.VertexID] = current_bone; } } } foreach (Node child in nd.Children) { RecursiveCalculateVertexTransform(child, current_node); } }
/// <summary> /// Function to blend from one keyframe to another. /// </summary> public void ChangeLocalFixedDataBlend(ActionState st) { Debug.Assert(0 <= st.KfBlend && st.KfBlend <= 1); foreach (NodeAnimationChannel channel in _action.NodeAnimationChannels) { BoneNode bone_nd = _scene.GetBoneNode(channel.NodeName); // now rotation tk.Quaternion target_roto = tk.Quaternion.Identity; if (channel.RotationKeyCount > st.TargetKeyframe) { target_roto = channel.RotationKeys[st.TargetKeyframe].Value.eToOpenTK(); } tk.Quaternion start_frame_roto = channel.RotationKeys[st.OriginKeyframe].Value.eToOpenTK(); tk.Quaternion result_roto = tk.Quaternion.Slerp(start_frame_roto, target_roto, (float)st.KfBlend); // now translation tk.Vector3 target_trans = tk.Vector3.Zero; if (channel.PositionKeyCount > st.TargetKeyframe) { target_trans = channel.PositionKeys[st.TargetKeyframe].Value.eToOpenTK(); } tk.Vector3 cur_trans = channel.PositionKeys[st.OriginKeyframe].Value.eToOpenTK(); tk.Vector3 result_trans = cur_trans + tk.Vector3.Multiply(target_trans - cur_trans, (float)st.KfBlend); // combine rotation and translation tk.Matrix4 result = tk.Matrix4.CreateFromQuaternion(result_roto); result.Row3.Xyz = result_trans; bone_nd.LocTrans = result.eToAssimp(); } }