private aiMatrix4x4 InterpolateRotation(double time, NodeAnimationChannel channel) { aiQuaternion rotation; if (channel.RotationKeyCount == 1) { rotation = channel.RotationKeys[0].Value; } else { uint frameIndex = 0; for (uint i = 0; i < channel.RotationKeyCount - 1; i++) { if (time < (float)channel.RotationKeys[(int)(i + 1)].Time) { frameIndex = i; break; } } QuaternionKey currentFrame = channel.RotationKeys[(int)frameIndex]; QuaternionKey nextFrame = channel.RotationKeys[(int)((frameIndex + 1) % channel.RotationKeyCount)]; double delta = (time - (float)currentFrame.Time) / (float)(nextFrame.Time - currentFrame.Time); aiQuaternion start = currentFrame.Value; aiQuaternion end = nextFrame.Value; rotation = aiQuaternion.Slerp(start, end, (float)delta); rotation.Normalize(); } return(rotation.GetMatrix()); }
Matrix4x4 FindRotation(NodeAnimationChannel n) { Matrix4x4 result = Matrix4x4.Identity; for (int c = 0; c < n.RotationKeyCount; c++) { QuaternionKey q = n.RotationKeys[c]; q.Value = new Assimp.Quaternion(q.Value.W, q.Value.X, q.Value.Y, q.Value.Z); VectorKey pk = n.PositionKeys[c]; VectorKey ps = n.ScalingKeys[c]; if (_animationController.FrameCounter <= q.Time) { result = (Matrix4x4)q.Value.GetMatrix() * (Matrix4x4.FromTranslation(pk.Value)) * (Matrix4x4.FromScaling(ps.Value)) ; break; } } return(result); }
static NumMatrix4x4 GetTransformForFrame(NodeAnimationChannel Ch, int Frame) { VectorKey PosKey = Ch.PositionKeys[Ch.PositionKeys.Count - 1]; if (Frame < Ch.PositionKeys.Count) { PosKey = Ch.PositionKeys[Frame]; } QuaternionKey RotKey = Ch.RotationKeys[Ch.RotationKeys.Count - 1]; if (Frame < Ch.RotationKeys.Count) { RotKey = Ch.RotationKeys[Frame]; } VectorKey SclKey = Ch.ScalingKeys[Ch.ScalingKeys.Count - 1]; if (Frame < Ch.ScalingKeys.Count) { SclKey = Ch.ScalingKeys[Frame]; } NumMatrix4x4 Rot = NumMatrix4x4.CreateFromQuaternion(ConvertQuat(RotKey.Value)); NumMatrix4x4 Pos = NumMatrix4x4.CreateTranslation(ConvertVec(PosKey.Value)); NumMatrix4x4 Scl = NumMatrix4x4.CreateScale(ConvertVec(SclKey.Value)); //return Pos * Rot * Scl; return(Scl * Rot * Pos); }
/// <summary> /// Converts a <see cref="QuaternionKey"/> to a <see cref="DomainQuaternionKeyFrame"/>. /// </summary> /// <param name="assimpQuaternionKey">The source <see cref="QuaternionKey"/>.</param> /// <param name="ticksPerSecond">The number of ticks per second for the animation.</param> /// <returns>The resulting <see cref="DomainQuaternionKeyFrame"/>.</returns> private static DomainQuaternionKeyFrame GetDomainQuaternionKeyFrame(QuaternionKey assimpQuaternionKey, double ticksPerSecond) { var assimpQuaternion = assimpQuaternionKey.Value; assimpQuaternion.Normalize(); var quaternion = new NumericsQuaternion(assimpQuaternion.X, assimpQuaternion.Y, assimpQuaternion.Z, assimpQuaternion.W); return(new DomainQuaternionKeyFrame(assimpQuaternionKey.Time / ticksPerSecond, quaternion)); }
static void Main(string[] args) { string[] strs = Directory.GetFiles(Environment.CurrentDirectory, "*.dae", SearchOption.TopDirectoryOnly); foreach (string path in strs) { try { using (AssimpContext ACont = new AssimpContext()) { ACont.SetConfig(new NormalSmoothingAngleConfig(66f)); Scene scene = ACont.ImportFile(path, PostProcessSteps.Triangulate); if (!scene.HasAnimations) { Console.WriteLine("Skipping " + path); continue; } Animation anim = scene.Animations[0]; if (!anim.HasNodeAnimations) { Console.WriteLine("Invalid animation in " + path); continue; } StringBuilder sb = new StringBuilder(); sb.Append("// mcmonkey's animation details file format v0.2\n"); sb.Append("general\n"); sb.Append("{\n"); sb.Append("\tlength: ").Append((anim.DurationInTicks / anim.TicksPerSecond).ToString()).Append(";\n"); sb.Append("}\n"); for (int i = 0; i < anim.NodeAnimationChannelCount; i++) { NodeAnimationChannel node = anim.NodeAnimationChannels[i]; sb.Append(node.NodeName).Append('\n'); sb.Append("{\n"); Node found = LookForMatch(scene.RootNode, node.NodeName); string pNode = "<none>"; if (found != null) { pNode = found.Parent.Name; } sb.Append("\tparent: " + pNode + ";\n"); /*Bone bfound = LookForBone(scene, node.NodeName); * Matrix4x4 mat = Matrix4x4.Identity; * if (bfound != null) * { * mat = bfound.OffsetMatrix; * //bpos = bfound.OffsetMatrix.C1 + "=" + bfound.OffsetMatrix.C2 + "=" + bfound.OffsetMatrix.C3; * //bpos = bfound.OffsetMatrix.A4 + "=" + bfound.OffsetMatrix.B4 + "=" + bfound.OffsetMatrix.C4; * }*/ /*sb.Append("\toffset: " + mat.A1 + "=" + mat.A2 + "=" + mat.A3 + "=" + mat.A4 + "=" + * mat.B1 + "=" + mat.B2 + "=" + mat.B3 + "=" + mat.B4 + "=" + * mat.C1 + "=" + mat.C2 + "=" + mat.C3 + "=" + mat.C4 + "=" + * mat.D1 + "=" + mat.D2 + "=" + mat.D3 + "=" + mat.D4 +";\n");*/ if (node.HasPositionKeys) { sb.Append("\tpositions: "); for (int x = 0; x < node.PositionKeyCount; x++) { VectorKey key = node.PositionKeys[x]; sb.Append(key.Time.ToString() + "=" + key.Value.X.ToString() + "=" + key.Value.Y.ToString() + "=" + key.Value.Z.ToString() + " "); } sb.Append(";\n"); } if (node.HasRotationKeys) { sb.Append("\trotations: "); for (int x = 0; x < node.RotationKeyCount; x++) { QuaternionKey key = node.RotationKeys[x]; sb.Append(key.Time.ToString() + "=" + key.Value.X.ToString() + "=" + key.Value.Y.ToString() + "=" + key.Value.Z.ToString() + "=" + key.Value.W + " "); } sb.Append(";\n"); } // TODO: Should scaling matter? Probably not. sb.Append("}\n"); } File.WriteAllText(path + ".anim", sb.ToString()); } } catch (Exception ex) { Console.WriteLine("Processing " + path + ": " + ex.ToString()); } } }
bool ListQuaternionKey(ref List <QuaternionKey> list, int totalFrames) { bool hasChanges = false; for (int i = 0; i < list.Count; i++) { if (list[i] != list[GetNextIndex(list, i)]) { hasChanges = true; break; } } if (!hasChanges) { return(false); } List <QuaternionKey> interpolated = new List <QuaternionKey>(totalFrames); for (int i = 0; i < totalFrames; i++) { interpolated.Add(new QuaternionKey()); } QuaternionKey first = list[0]; QuaternionKey from; QuaternionKey to; for (int i = 0; i < list.Count; i++) { from = list[i]; to = list[GetNextIndex(list, i)]; if (Mathf.Abs(((int)to.Time - (int)from.Time)) == 1) { continue; } bool aNan = (float.IsNaN(from.Value.X) || float.IsNaN(from.Value.Y) || float.IsNaN(from.Value.Z) || float.IsNaN(from.Value.W)); bool bNan = (float.IsNaN(to.Value.X) || float.IsNaN(to.Value.Y) || float.IsNaN(to.Value.Z) || float.IsNaN(to.Value.W)); UnityEngine.Quaternion a = aNan ? UnityEngine.Quaternion.identity : new UnityEngine.Quaternion(from.Value.X, from.Value.Y, from.Value.Z, from.Value.W); UnityEngine.Quaternion b = bNan ? UnityEngine.Quaternion.identity : new UnityEngine.Quaternion(to.Value.X, to.Value.Y, to.Value.Z, to.Value.W); int stepCount = Mathf.Abs((int)to.Time - (int)from.Time); float step = 1f / stepCount; if (to.Time < from.Time) { step = 1f / (float)(totalFrames - (int)from.Time + (int)to.Time); } float t = 0f; for (int j = (int)from.Time; j != (int)to.Time; j = GetNextIndex(interpolated, j)) { QuaternionKey ik = interpolated[j]; ik.Time = j; UnityEngine.Quaternion ab = UnityEngine.Quaternion.Lerp(a, b, t); ik.Value = new Assimp.Quaternion(ab.w, ab.x, ab.y, ab.z); //print(ik.Value); interpolated[j] = ik; t += step; if (stepCount-- < 0) { break; } } if (to == first) { break; } } list = interpolated; return(true); }
/** * Kinect Joint Conversion to NodeAnim */ private void KinectJointToNode(Scene mainScene, Joint joint, NodeAnimationChannel matchedNode, double time) { VectorKey keyframePos = new VectorKey(); keyframePos.Value.X = joint.Position.X; keyframePos.Value.Y = joint.Position.Y; keyframePos.Value.Z = joint.Position.Z; keyframePos.Time = time; QuaternionKey keyframeRot = new QuaternionKey(); if (joint.JointType == JointType.HipCenter) { keyframeRot.Value = new Quaternion(0, (float)3, (float)1.3); } else { keyframeRot.Value.X = 0; keyframeRot.Value.Y = 0; keyframeRot.Value.Z = 0; } keyframeRot.Time = time; //We set last_assimp_joint node that we will reuse for calculate localPosition/Rotation the next step string prevNodeName = mainScene.RootNode.FindNode(matchedNode.NodeName).Parent.Name; VectorKey prevKeyframePos = new VectorKey(); bool find = false; /* * TODO: We could refactor that code to avoid to go through all joint each time * we need to look for a specific joint */ foreach (Joint j in currentJoinCol) { if (prevNodeName == "") find = true; if (j.JointType.ToString() == prevNodeName) { prevKeyframePos.Value.X = j.Position.X; prevKeyframePos.Value.Y = j.Position.Y; prevKeyframePos.Value.Z = j.Position.Z; find = true; break; } } if (find == false) throw new Exception(); if (prevNodeName != "") keyframePos.Value -= prevKeyframePos.Value; keyframePos.Value.X *= 17; keyframePos.Value.Y *= 17; keyframePos.Value.Z *= 17; matchedNode.PositionKeys.Add(keyframePos); matchedNode.RotationKeys.Add(keyframeRot); }
private Tuple<VectorKey, QuaternionKey> VectorToNode(Vector posVect, double time) { VectorKey keyframePos = new VectorKey(); keyframePos.Value.X = posVect.x / HAND_SCALE_RATIO; keyframePos.Value.Y = posVect.y / HAND_SCALE_RATIO; keyframePos.Value.Z = posVect.z / HAND_SCALE_RATIO; keyframePos.Time = time; QuaternionKey keyframeRot = new QuaternionKey(); keyframeRot.Value.X = 0; keyframeRot.Value.Y = 0; keyframeRot.Value.Z = 0; keyframeRot.Time = time; return new Tuple<VectorKey, QuaternionKey>(keyframePos, keyframeRot); }
public static SkeletalAnimation[] LoadAnimations(string fileName, Vector3 multiplier) { AssimpContext importer = new AssimpContext(); Scene scene = importer.ImportFile(fileName); List <SkeletalAnimation> skeletalAnimations = new List <SkeletalAnimation>(); if (scene.HasAnimations) { foreach (Animation animation in scene.Animations) { if (animation.HasNodeAnimations) { SkeletalAnimation skeletalAnimation = new SkeletalAnimation(animation.Name, (float)animation.TicksPerSecond); foreach (NodeAnimationChannel channel in animation.NodeAnimationChannels) { Vector3 lastPosition = Vector3.Zero; OpenTK.Quaternion lastRotation = OpenTK.Quaternion.Identity; Vector3 lastScale = Vector3.One; string nodeName = SanitizeBoneName(channel.NodeName); if (channel.NodeName.Contains("_$AssimpFbx$_Translation")) { foreach (VectorKey key in channel.PositionKeys) { lastPosition = new Vector3(key.Value.X, key.Value.Y, key.Value.Z) * multiplier; skeletalAnimation.AddKeyFrame(nodeName, (float)key.Time, lastPosition, lastRotation, lastScale); } } else if (channel.NodeName.Contains("_$AssimpFbx$_Rotation")) { foreach (QuaternionKey key in channel.RotationKeys) { lastRotation = new OpenTK.Quaternion(key.Value.X, key.Value.Y, key.Value.Z, key.Value.W); skeletalAnimation.AddKeyFrame(nodeName, (float)key.Time, lastPosition, lastRotation, lastScale); } } else if (channel.NodeName.Contains("_$AssimpFbx$_Scaling")) { foreach (VectorKey key in channel.ScalingKeys) { lastScale = new Vector3(key.Value.X, key.Value.Y, key.Value.Z); skeletalAnimation.AddKeyFrame(nodeName, (float)key.Time, lastPosition, lastRotation, lastScale); } } else { for (int i = 0; i < channel.PositionKeyCount; i++) { VectorKey keyT = channel.PositionKeys[i]; QuaternionKey keyR = channel.RotationKeys[i]; VectorKey keyS = channel.ScalingKeys[i]; lastPosition = new Vector3(keyT.Value.X, keyT.Value.Y, keyT.Value.Z) * multiplier; lastRotation = new OpenTK.Quaternion(keyR.Value.X, keyR.Value.Y, keyR.Value.Z, keyR.Value.W); lastScale = new Vector3(keyS.Value.X, keyS.Value.Y, keyS.Value.Z); skeletalAnimation.AddKeyFrame(nodeName, (float)keyT.Time, lastPosition, lastRotation, lastScale); } } } skeletalAnimations.Add(skeletalAnimation); } } } return(skeletalAnimations.ToArray()); }
private Tuple<VectorKey, QuaternionKey> BoneToNode(Bone bone) { VectorKey keyframePos = new VectorKey(); keyframePos.Value.X = joint.Position.X; keyframePos.Value.Y = joint.Position.Y; keyframePos.Value.Z = joint.Position.Z; keyframePos.Time = this.current_frametime; QuaternionKey keyframeRot = new QuaternionKey(); keyframeRot.Value.X = 0; keyframeRot.Value.Y = 0; keyframeRot.Value.Z = 0; keyframeRot.Time = this.current_frametime; return new Tuple<VectorKey, QuaternionKey>(keyframePos, keyframeRot); }
public bool Load(String fileName) { // @TODO - change the file path for asset folder in the future currently, set as executable path String path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Assets\\"); m_FileName = path + fileName; // setting assimp context AssimpContext importer = new AssimpContext(); importer.SetConfig(new NormalSmoothingAngleConfig(66.0f)); // loading scene Scene scene = null; try { scene = importer.ImportFile(m_FileName, PostProcessPreset.TargetRealTimeMaximumQuality | PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs | PostProcessSteps.FlipWindingOrder); } catch (Exception e) // handling assimp exception { if (e.Source != null) { Console.WriteLine("Error: {0}", e.Message); } } asset = new H1AssetContext(); H1ModelContext convertedModel = asset.AddModel(); // extract the meshes if (scene.HasMeshes) { Int32 meshCount = scene.Meshes.Count; List <H1MeshContext> meshContexts = new List <H1MeshContext>(); ExtractMeshData(scene, ref meshContexts); foreach (H1MeshContext meshContext in meshContexts) { convertedModel.Meshes.Add(meshContext); } } // extract skeletal data // what I learned from this failed algorithm // 1. root bone nodes can be multiple // 2. for example, blabla_Hub(containing null meshes, only space infos) have null information for weighted vertices, but it should not be considered as leaf node! #region Disabled Extracting skeletal mesh data methods /*if (scene.HasMeshes) * { * // collect all bones from meshes * List<Bone> bones = new List<Bone>(); * foreach (Mesh mesh in scene.Meshes) * { * if (mesh.HasBones) * { * bones.AddRange(mesh.Bones); * } * } * * // find root node for all meshes * Node boneRootNode = FindRootBone(bones, scene.RootNode); * * H1SkeletalContext skeletalContext = null; * skeletalContext = new H1SkeletalContext(); * //@TODO - need to optimize for deep copies * ExtractSkeletalMeshData(boneRootNode, bones, ref skeletalContext); * * convertedModel.SkeletalContexts.Add(skeletalContext); * }*/ #endregion // what I learned from this failed algorithm // 1. the counts of bones and bone nodes (joint nodes) can be different // 2. bone node can be used for just transforming spaces // 3. bone node could have empty meshes (just includes space information) // 4. bones are subsidiary for bone nodes // 5. don't consider aiBone as bone node in hierarchy rather regards node(aiNode) as bone node in hierarchy // 6. consider aiBone as node bone data containing all necessary data #region Failed Algorithm // new algorithms to handle multiple root node (like pelvis and head) more efficient way /*if (scene.HasMeshes) * { * // 1. extracted all bones for all meshes in the scene * // NOTICE - multiple meshes in file are considered in same body but chunked several parts * Dictionary<String, Bone> extractedBones = new Dictionary<String, Bone>(); * Dictionary<String, H1SkeletalContext.JointNode> jointNodes = new Dictionary<string, H1SkeletalContext.JointNode>(); * foreach (Mesh mesh in scene.Meshes) * { * if (mesh.HasBones) * { * foreach (Bone bone in mesh.Bones) * { * String boneName = bone.Name; * if (!extractedBones.ContainsKey(boneName)) * { * extractedBones.Add(boneName, bone); * * H1SkeletalContext.JointNode newJointNode = new H1SkeletalContext.JointNode(); * newJointNode.JointData.JointName = boneName; * jointNodes.Add(boneName, newJointNode); * } * } * } * } * * // 2. process extracted bones * // @TODO - naive algorithm need to optimize by searching tree and set the bones parent * foreach (KeyValuePair<String, Bone> extractedBone in extractedBones) * { * Node node = scene.RootNode.FindNode(extractedBone.Key); * H1SkeletalContext.JointNode jointNode = jointNodes[node.Name]; * H1SkeletalContext.JointNode parentJointNode = jointNodes[node.Parent.Name]; * * // set proper properties * jointNode.Parent = parentJointNode; * foreach (Node child in node.Children) * { * H1SkeletalContext.JointNode childJointNode = null; * if (jointNodes.TryGetValue(child.Name, out childJointNode)) * { * jointNode.Children.Add(childJointNode); * } * } * ExtractBone(extractedBone.Value, ref jointNode.JointData); * } * * // 3. find root node(s) and set them at the front * }*/ #endregion if (scene.HasMeshes) { H1SkeletalContext skeletalContext = null; skeletalContext = new H1SkeletalContext(); // prepare data for BFS search List <H1SkeletalContext.JointNode> jointNodes = skeletalContext.JointNodes; Dictionary <String, Int32> jointNameToJointNodeIndex = new Dictionary <String, Int32>(); // extractedBones could have same bone name and multiple bone data Dictionary <String, List <Bone> > extractedBones = new Dictionary <String, List <Bone> >(); // boneToMeshContexIndex should be mirrored same as extractedBones (index of list should be same) Dictionary <String, List <Int32> > boneToMeshContextIndex = new Dictionary <String, List <Int32> >(); #region Debug Validation Weight Vertex Counts #if DEBUG List <Boolean> taggedVertexIndex = new List <Boolean>(); // verification to tag all needed vertices List <float> taggedVertexWeights = new List <float>(); // verification to tag all vertex weight for sum of each vertex List <Int32> taggedVertexIndexOffset = new List <Int32>(); // pre-test for validation foreach (Mesh mesh in scene.Meshes) { if (mesh.HasVertices) { foreach (Vector3D vertex in mesh.Vertices) { taggedVertexIndex.Add(false); } } if (mesh.HasBones) { foreach (Bone bone in mesh.Bones) { if (bone.HasVertexWeights) { foreach (VertexWeight vertexWeight in bone.VertexWeights) { taggedVertexIndex[vertexWeight.VertexID] = true; } } } } List <Int32> notTaggedVertexIndex0 = new List <Int32>(); Int32 currVertexIndex0 = 0; foreach (Boolean isTagged in taggedVertexIndex) { if (isTagged == false) { notTaggedVertexIndex0.Add(currVertexIndex0); } currVertexIndex0++; } if (notTaggedVertexIndex0.Count > 0) { return(false); } taggedVertexIndex.Clear(); } #endif #endregion Int32 validMeshContextIndex = 0; foreach (Mesh mesh in scene.Meshes) { if (mesh.HasVertices && mesh.HasNormals && mesh.HasTangentBasis && mesh.TextureCoordinateChannels[0].Count > 0 && mesh.HasFaces) // process vertices in the mesh { if (mesh.HasBones) { foreach (Bone bone in mesh.Bones) { String boneName = bone.Name; if (!extractedBones.ContainsKey(boneName)) { // add new list of bone list extractedBones.Add(boneName, new List <Bone>()); extractedBones[boneName].Add(bone); // add new list of mesh context index boneToMeshContextIndex.Add(boneName, new List <Int32>()); boneToMeshContextIndex[boneName].Add(validMeshContextIndex); } else // same bone name, but different bone data exists { // no need to create list of data, just add new item // bone data could have different set of weighted vertices, but with same bone name extractedBones[boneName].Add(bone); boneToMeshContextIndex[boneName].Add(validMeshContextIndex); } } validMeshContextIndex++; #region Debug Validation Weight Vertex Count #if DEBUG taggedVertexIndexOffset.Add(taggedVertexIndex.Count); for (Int32 i = 0; i < mesh.VertexCount; ++i) { taggedVertexIndex.Add(false); taggedVertexWeights.Add(0.0f); } #endif #endregion } } } // BFS search to construct bone data Stack <Node> nodes = new Stack <Node>(); nodes.Push(scene.RootNode); while (nodes.Count != 0) { Node currNode = nodes.Pop(); H1SkeletalContext.JointNode jointNode = new H1SkeletalContext.JointNode(); H1SkeletalContext.JointNode parentJointNode = jointNodes.Find(x => (x.JointName == currNode.Parent.Name)); jointNode.Parent = parentJointNode; ExtractNodeSpace(currNode, ref jointNode); List <Bone> boneDataList = null; List <Int32> meshContextIndexList = null; if (extractedBones.TryGetValue(jointNode.JointName, out boneDataList)) { meshContextIndexList = boneToMeshContextIndex[jointNode.JointName]; // looping bone data list, extract bone data Int32 currBoneIndex = 0; foreach (Bone bone in boneDataList) { H1SkeletalContext.Joint newJointData = new H1SkeletalContext.Joint(); ExtractBone(bone, ref newJointData); newJointData.MeshContextIndex = meshContextIndexList[currBoneIndex]; currBoneIndex++; // store mesh context local-to-global H1Transform for later transformation of offsetMatrix for animation newJointData.MeshContextLocalToGlobal = convertedModel.Meshes[newJointData.MeshContextIndex].LocalToGlobalTransform; // add new joint data jointNode.JointDataList.Add(newJointData); } // mark this node is bone-space jointNode.MarkedAsBoneSpace = true; // tag its parent until it reaches the state that 'MarkedAsBoneSpace' is true H1SkeletalContext.JointNode markNode = jointNode.Parent; while (markNode != null && markNode.MarkedAsBoneSpace != true) { markNode.MarkedAsBoneSpace = true; markNode = markNode.Parent; } } else { // for debugging } foreach (Node child in currNode.Children) { nodes.Push(child); // tag child names to process child nodes after BFS search jointNode.ChildNodeNames.Add(child.Name); } // add new joint node Int32 newJointNodeIndex = jointNodes.Count; jointNodes.Add(jointNode); jointNameToJointNodeIndex.Add(jointNode.JointName, newJointNodeIndex); } // process tagged child nodes foreach (H1SkeletalContext.JointNode node in jointNodes) { foreach (String childName in node.ChildNodeNames) { node.Children.Add(jointNodes[jointNameToJointNodeIndex[childName]]); } } #region Debug Validation for total weight value of weighted vertices & vertex counts #if DEBUG foreach (H1SkeletalContext.JointNode node in jointNodes) { foreach (H1SkeletalContext.Joint jointData in node.JointDataList) { foreach (H1SkeletalContext.WeightedVertex weightedVertex in jointData.WeightedVertices) { // confirm all vertices in Mesh are tagged by weighted vertices taggedVertexIndex[taggedVertexIndexOffset[jointData.MeshContextIndex] + weightedVertex.VertexIndex] = true; // add vertex weight to verify taggedVertexWeights[taggedVertexIndexOffset[jointData.MeshContextIndex] + weightedVertex.VertexIndex] += weightedVertex.Weight; } } } // verification code to extract not tagged vertex index List <Int32> notTaggedVertexIndex = new List <Int32>(); Int32 currVertexIndex = 0; foreach (Boolean isTagged in taggedVertexIndex) { if (isTagged == false) { notTaggedVertexIndex.Add(currVertexIndex); } currVertexIndex++; } if (notTaggedVertexIndex.Count > 0) { return(false); } // verification code to extract vertex which has invalid vertex weight value List <Int32> invalidVertexWeightVertexIndex = new List <Int32>(); currVertexIndex = 0; foreach (float currVertexWeights in taggedVertexWeights) { if (currVertexWeights < 0.99f) { invalidVertexWeightVertexIndex.Add(currVertexIndex); } } if (invalidVertexWeightVertexIndex.Count > 0) { return(false); } #endif #endregion convertedModel.SkeletalContexts.Add(skeletalContext); } // extract the animations if (scene.HasAnimations) { H1AnimationContext newAnimContext = new H1AnimationContext(); for (Int32 animIndex = 0; animIndex < scene.AnimationCount; ++animIndex) { Animation currAnimation = scene.Animations[animIndex]; if (currAnimation.HasNodeAnimations) // we only handle node animations (not vertex animation) { // create new animation sequence H1AnimationContext.AnimSequence newAnimSeq = new H1AnimationContext.AnimSequence(); newAnimSeq.AnimSeqName = currAnimation.Name; newAnimSeq.Duration = currAnimation.DurationInTicks; newAnimSeq.TicksPerSecond = currAnimation.TicksPerSecond; foreach (NodeAnimationChannel animChannel in currAnimation.NodeAnimationChannels) { H1AnimationContext.JointAnimation newJointAnim = new H1AnimationContext.JointAnimation(); newJointAnim.BoneName = animChannel.NodeName; // calculate maximum number of keys to fill up the special case (only holding one key) Int32 maxNumKeys = Math.Max(Math.Max(animChannel.ScalingKeyCount, animChannel.RotationKeyCount), animChannel.PositionKeyCount); if (animChannel.HasPositionKeys) { if (animChannel.PositionKeyCount == 1) // special handling (only holding one key) { VectorKey positionKey = animChannel.PositionKeys[0]; for (Int32 numKey = 0; numKey < maxNumKeys; ++numKey) { H1AnimationContext.PositionKey newPosKey = new H1AnimationContext.PositionKey(); newPosKey.Time = positionKey.Time; newPosKey.Value = new Vector3(positionKey.Value.X, positionKey.Value.Y, positionKey.Value.Z); newJointAnim.PosKeys.Add(newPosKey); } } else { foreach (VectorKey positionKey in animChannel.PositionKeys) { H1AnimationContext.PositionKey newPosKey = new H1AnimationContext.PositionKey(); newPosKey.Time = positionKey.Time; newPosKey.Value = new Vector3(positionKey.Value.X, positionKey.Value.Y, positionKey.Value.Z); newJointAnim.PosKeys.Add(newPosKey); } } } if (animChannel.HasRotationKeys) { if (animChannel.RotationKeyCount == 1) // special handling (only holding one key) { QuaternionKey quatKey = animChannel.RotationKeys[0]; for (Int32 numKey = 0; numKey < maxNumKeys; ++numKey) { H1AnimationContext.QuaternionKey newQuatKey = new H1AnimationContext.QuaternionKey(); newQuatKey.Time = quatKey.Time; newQuatKey.Value = new SharpDX.Quaternion(quatKey.Value.X, quatKey.Value.Y, quatKey.Value.Z, quatKey.Value.W); newJointAnim.RotKeys.Add(newQuatKey); } } else { foreach (QuaternionKey quatKey in animChannel.RotationKeys) { H1AnimationContext.QuaternionKey newQuatKey = new H1AnimationContext.QuaternionKey(); newQuatKey.Time = quatKey.Time; newQuatKey.Value = new SharpDX.Quaternion(quatKey.Value.X, quatKey.Value.Y, quatKey.Value.Z, quatKey.Value.W); newJointAnim.RotKeys.Add(newQuatKey); } } } if (animChannel.HasScalingKeys) { if (animChannel.ScalingKeyCount == 1) // special handling (only holding one key) { VectorKey scalingKey = animChannel.ScalingKeys[0]; for (Int32 numKey = 0; numKey < maxNumKeys; ++numKey) { H1AnimationContext.ScalingKey newScalingKey = new H1AnimationContext.ScalingKey(); newScalingKey.Time = scalingKey.Time; newScalingKey.Value = new Vector3(scalingKey.Value.X, scalingKey.Value.Y, scalingKey.Value.Z); newJointAnim.ScaleKeys.Add(newScalingKey); } } else { foreach (VectorKey scalingKey in animChannel.ScalingKeys) { H1AnimationContext.ScalingKey newScalingKey = new H1AnimationContext.ScalingKey(); newScalingKey.Time = scalingKey.Time; newScalingKey.Value = new Vector3(scalingKey.Value.X, scalingKey.Value.Y, scalingKey.Value.Z); newJointAnim.ScaleKeys.Add(newScalingKey); } } } newAnimSeq.BoneAnimations.Add(newJointAnim); } newAnimContext.AnimSequences.Add(newAnimSeq); } } // set the animation context convertedModel.AnimationContext = newAnimContext; } return(true); }