public Boolean ProcessRefSkeletonFromAssetContext(H1SkeletalContext.JointNode node, ref H1ReferenceSkeleton refSkeleton) { H1SkeletalContext.Joint jointData = null; // node.JointData; // add mesh bone info H1MeshBoneInfo meshBoneInfo = new H1MeshBoneInfo(); //meshBoneInfo.Name = jointData.JointName; if (refSkeleton.NameToIndexMapIsEmpty()) { // should be root node, so parent index is '0' meshBoneInfo.ParentIndex = 0; } else if (node.Parent == null) { // should be sub-root node, so parent index is '0' (root motion node) meshBoneInfo.ParentIndex = refSkeleton.GetIndexByBoneName("RootMotionNode"); } else //meshBoneInfo.ParentIndex = refSkeleton.GetIndexByBoneName(node.Parent.JointData.JointName); if (meshBoneInfo.ParentIndex == -1) { return(false); } // the new index should be same with RefBoneBases Int32 newBoneInfoIndex = refSkeleton.RefBoneInfoList.Count; Int32 newBoneBaseIndex = refSkeleton.RefBoneBases.Count; if (newBoneBaseIndex != newBoneInfoIndex) { return(false); } refSkeleton.RefBoneInfoList.Add(meshBoneInfo); // add bone base H1Transform boneBase = new H1Transform(); boneBase.Translation = jointData.OffsetTransformation.Translation; boneBase.Scaling = jointData.OffsetTransformation.Scaling; boneBase.Rotation = jointData.OffsetTransformation.Rotation; refSkeleton.RefBoneBases.Add(boneBase); // add NameToIndex refSkeleton.AddNameToIndexPair(meshBoneInfo.Name, newBoneInfoIndex); return(true); }
// @TODO - change this delivering directly command list from the renderer after implementing overall rendering system public void SkeletonDebugDrawing(SharpDX.Direct3D12.GraphicsCommandList commandList, Boolean bDebugDraw = true) { // @TODO - temporary to check if animation is working H1SkeletalMeshComponent skeletalMeshComponent = H1Global <H1World> .Instance.PersistentLevel.GetActor(0).GetActorComponent <H1SkeletalMeshComponent>(); List <H1AnimInstance.InterpolatedLocalTransform> interpolatedLocalTransforms = new List <H1AnimInstance.InterpolatedLocalTransform>(); for (Int32 boneIndex = 0; boneIndex < m_Skeleton.RefSkeleton.RefBoneInfoList.Count; ++boneIndex) { H1AnimInstance.InterpolatedLocalTransform interpolatedLocalTransform = new H1AnimInstance.InterpolatedLocalTransform(); H1MeshBoneInfo meshBoneInfo = m_Skeleton.RefSkeleton.RefBoneInfoList[boneIndex]; interpolatedLocalTransform.BoneName = meshBoneInfo.Name; interpolatedLocalTransform.LocalTransform = m_Skeleton.RefSkeleton.RefBoneBases[boneIndex]; interpolatedLocalTransforms.Add(interpolatedLocalTransform); } // extract interpolated local transforms skeletalMeshComponent.AnimScriptInstance.ExtractInterpolatedLocalTransform(0.0f, ref interpolatedLocalTransforms); H1Transform[] globalTransforms = new H1Transform[m_Skeleton.RefSkeleton.RefBoneBases.Count]; // tracking only upper parent index by one Int32[] transformParentIndices = new Int32[m_Skeleton.RefSkeleton.RefBoneBases.Count]; for (Int32 boneIndex = 0; boneIndex < m_Skeleton.RefSkeleton.RefBoneInfoList.Count; ++boneIndex) { H1MeshBoneInfo meshBoneInfo = m_Skeleton.RefSkeleton.RefBoneInfoList[boneIndex]; //H1Transform localTransform = m_Skeleton.RefSkeleton.RefBoneBases[boneIndex]; H1Transform localTransform = interpolatedLocalTransforms[boneIndex].LocalTransform; // extract parent locals List <H1Transform> parentLocalTransforms = new List <H1Transform>(); H1MeshBoneInfo currMeshBoneInfo = meshBoneInfo; while (currMeshBoneInfo.ParentIndex != -1) { //parentLocalTransforms.Add(m_Skeleton.RefSkeleton.RefBoneBases[currMeshBoneInfo.ParentIndex]); parentLocalTransforms.Add(interpolatedLocalTransforms[currMeshBoneInfo.ParentIndex].LocalTransform); currMeshBoneInfo = m_Skeleton.RefSkeleton.RefBoneInfoList[currMeshBoneInfo.ParentIndex]; } // generate global transform for current bone space // 1. start to transform current local transformation matrix Matrix globalTransformMtx = localTransform.Transformation; // 2. from curr bone space to root space by going up to each parent node space for (Int32 index = 0; index < parentLocalTransforms.Count; ++index) { Matrix parentLocalTransformMtx = parentLocalTransforms[index].Transformation; globalTransformMtx = Matrix.Multiply(globalTransformMtx, parentLocalTransformMtx); } // decompose global matrix and generate H1Transform Vector3 translation; Vector3 scale; Quaternion rotate; globalTransformMtx.Decompose(out scale, out rotate, out translation); H1Transform globalTransform = new H1Transform(); globalTransform.Translation = translation; globalTransform.Scaling = scale; globalTransform.Rotation = rotate; globalTransforms[boneIndex] = globalTransform; transformParentIndices[boneIndex] = meshBoneInfo.ParentIndex; } // set bone matrices Int32 currGlobalBoneIndex = 0; foreach (H1Transform boneTransform in globalTransforms) { // @TODO - temporary scaling to match when we importing vertices in H1AssimpImporter //boneTransform.Scaling = boneTransform.Scaling * 0.01f; // get global offset matrices Matrix globalOffsetMatrix = m_Skeleton.RefSkeleton.RefOffsetBases[currGlobalBoneIndex].Transformation; // pass multiplied global offset matrices and animated global matrices H1Global <H1ManagedRenderer> .Instance.SetBoneMatrix(currGlobalBoneIndex, Matrix.Multiply(globalOffsetMatrix, boneTransform.Transformation)); currGlobalBoneIndex++; } // when debug draw is enabled if (bDebugDraw == true) { for (Int32 boneIndex = 0; boneIndex < globalTransforms.Count(); ++boneIndex) { Int32 parentIndex = transformParentIndices[boneIndex]; if (parentIndex < 0) { continue; } H1Transform parentBoneTransform = globalTransforms[parentIndex]; H1Transform boneTransform = globalTransforms[boneIndex]; Vector3 parentLoc = parentBoneTransform.Translation * 0.005f; Vector3 currLoc = boneTransform.Translation * 0.005f; float length = (currLoc - parentLoc).Length(); if (length < 0.001f) { continue; } Vector3 zAxis = Vector3.Normalize(currLoc - parentLoc); Matrix pitchMtx = Matrix.RotationYawPitchRoll(0, 0.1f, 0); Vector4 rotatedZAxis = Vector3.Transform(zAxis, pitchMtx); rotatedZAxis /= rotatedZAxis.W; Vector3 yAxis = Vector3.Normalize(Vector3.Cross(zAxis, Vector3.Normalize(new Vector3(rotatedZAxis.X, rotatedZAxis.Y, rotatedZAxis.Z)))); Vector3 xAxis = Vector3.Normalize(Vector3.Cross(zAxis, yAxis)); //H1RenderUtils.DrawCapsule(commandList, parentLoc, xAxis, yAxis, zAxis, 0.03f, length / 2.0f, 16); H1RenderUtils.DrawDashedLine(commandList, parentLoc, currLoc, 2.0f); //H1RenderUtils.DrawWireStar(commandList, currLoc, 0.03f); } } }
public H1StaticLODModel PrepareProcessAssetContext(H1SkeletalContext skeletalContext) { if (m_SkeletalMeshResource == null) { return(null); } // @TODO - temporary low LOD model, fix this H1StaticLODModel staticLODModel = m_SkeletalMeshResource.AddLODModel(); // add root node that controls all animation motion H1ReferenceSkeleton refSkeleton = m_Skeleton.RefSkeleton; // construct refSkeleton List <H1SkeletalContext.JointNode> jointNodes = skeletalContext.JointNodes; // to construct local transforms for each bone List <BoneOffsetTransformSet> boneOffsetTransforms = new List <BoneOffsetTransformSet>(); foreach (H1SkeletalContext.JointNode jointNode in jointNodes) { // if is not marked as bone node space, skip if (!jointNode.MarkedAsBoneSpace) { continue; } // prepare data to process bone node H1MeshBoneInfo meshBoneInfo = new H1MeshBoneInfo(); meshBoneInfo.Name = jointNode.JointName; // recursively find bone-space marked parent node (based on H1SkeletalContext.JointNode) // we need to reapply parent index based on 'refSkeleton.RefBoneInfoList' Int32 currParentIndex = jointNodes.FindIndex(x => { if (jointNode.Parent == null) { return(false); } return(x.JointName == jointNode.Parent.JointName); }); while (currParentIndex != -1 && // if not reaching to root node !jointNodes[currParentIndex].MarkedAsBoneSpace) // and if is not marked by bone-space { currParentIndex = jointNodes.FindIndex(x => { if (jointNodes[currParentIndex].Parent == null) { return(false); } return(x.JointName == jointNodes[currParentIndex].Parent.JointName); }); } meshBoneInfo.ParentIndex = currParentIndex; // the new index should be same with RefBoneBases Int32 newBoneInfoIndex = refSkeleton.RefBoneInfoList.Count; Int32 newBoneBaseIndex = refSkeleton.RefBoneBases.Count; if (newBoneBaseIndex != newBoneInfoIndex) { return(null); } refSkeleton.RefBoneInfoList.Add(meshBoneInfo); // what I learned from this disabled code section // 1. ASSIMP has separate node space and bone node space (transformation matrix) // 2. we need to handle those differently // - vertices resided in particular node space (mesh space we called) should be transformed into root node space (world space) // - localTransform in refSkeleton should be set by offsetMatrix in JointNode.JointData H1Transform boneBase = new H1Transform(); boneBase.Translation = jointNode.NodeLocalTransform.Translation; boneBase.Scaling = jointNode.NodeLocalTransform.Scaling; boneBase.Rotation = jointNode.NodeLocalTransform.Rotation; // allocate the space in advance refSkeleton.RefBoneBases.Add(boneBase); refSkeleton.AddNameToIndexPair(meshBoneInfo.Name, newBoneInfoIndex); // add bone offset transform set boneOffsetTransforms.Add(new BoneOffsetTransformSet()); // looping joint data foreach (H1SkeletalContext.Joint jointData in jointNode.JointDataList) { H1Transform meshContextLocalToGlobalTransform = jointData.MeshContextLocalToGlobal; // convert 'offsetTransformation' to H1Transform H1SkeletalContext.Transformation offsetTransformation = jointData.OffsetTransformation; H1Transform offsetTransform = new H1Transform(); offsetTransform.Translation = offsetTransformation.Translation; offsetTransform.Rotation = offsetTransformation.Rotation; offsetTransform.Scaling = offsetTransformation.Scaling; // apply meshContextLocalToGlobal Matrix result = Matrix.Multiply(Matrix.Invert(meshContextLocalToGlobalTransform.Transformation), offsetTransform.Transformation); Vector3 resultTranslation; Vector3 resultScaling; Quaternion resultRotation; result.Decompose(out resultScaling, out resultRotation, out resultTranslation); offsetTransform.Translation = resultTranslation; offsetTransform.Rotation = resultRotation; offsetTransform.Scaling = resultScaling; boneOffsetTransforms.Last().BoneOffsetTransforms.Add(offsetTransform); } } // construct parent index for H1MeshBoneInfo foreach (H1MeshBoneInfo meshBoneInfo in refSkeleton.RefBoneInfoList) { if (meshBoneInfo.ParentIndex == -1) // not handling root node case { continue; } String parentName = jointNodes[meshBoneInfo.ParentIndex].JointName; meshBoneInfo.ParentIndex = refSkeleton.RefBoneInfoList.FindIndex(x => { return(x.Name == parentName); }); } // @TODO - handle multiple offset transformations // set offset matrix Int32 currBoneIndex = 0; foreach (H1MeshBoneInfo meshBoneInfo in refSkeleton.RefBoneInfoList) { // add to global offset transform H1Transform globalOffsetTransform = boneOffsetTransforms[currBoneIndex].BoneOffsetTransforms.Count > 0 ? boneOffsetTransforms[currBoneIndex].BoneOffsetTransforms[0] : new H1Transform(); refSkeleton.RefOffsetBases.Add(globalOffsetTransform); currBoneIndex++; } return(staticLODModel); }