Exemplo n.º 1
0
        public Boolean ExtractSkeletalMeshData(Node rootBoneNode, List <Bone> bones, ref H1SkeletalContext newContext)
        {
            H1SkeletalContext.JointNode rootNode = new H1SkeletalContext.JointNode();
            ExtractSkeletalMeshDataRecursive(rootBoneNode, bones, ref rootNode);
            newContext.Root = rootNode;

            return(true);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        public Boolean ProcessAssetContext(H1StaticLODModel staticLODModel, H1MeshContext[] meshContexts, H1SkeletalContext skeletalContext)
        {
            if (m_Skeleton == null)
            {
                return(false);
            }

            // 1. process skeletalContext (H1SkeletalContext)
            H1SkeletalContext.JointNode rootNode    = skeletalContext.Root;
            H1ReferenceSkeleton         refSkeleton = m_Skeleton.RefSkeleton;

            #region Disabled
            // process recursively from root node
            //Dictionary<String, H1SkeletalContext.JointNode> mapNodeNameToJointNode = new Dictionary<string, H1SkeletalContext.JointNode>();
            //if (!ProcessAssetContextRecursive(rootNode, ref refSkeleton, ref mapNodeNameToJointNode))
            //    return false; // failed to process nodes from root nodes
            #endregion

            // 2. process meshContexts (H1MeshContext)
            // collect all vertices for all different mesh contexts
            Int32[] meshContextOffsetsList = new Int32[meshContexts.Count()];

            List <Vector3> positionsList = new List <Vector3>();
            List <Vector3> tangentXList  = new List <Vector3>();
            List <Vector3> tangentYList  = new List <Vector3>();
            List <Vector3> tangentZList  = new List <Vector3>();
            List <Vector2> texcoordsList = new List <Vector2>();

            Int32 currMeshContextIndex = 0;
            foreach (H1MeshContext meshContext in meshContexts)
            {
                meshContextOffsetsList[currMeshContextIndex] = positionsList.Count;

                positionsList.AddRange(meshContext.Positions);
                tangentXList.AddRange(meshContext.Tangents);
                tangentYList.AddRange(meshContext.Normals);
                tangentZList.AddRange(meshContext.BiTangents);
                texcoordsList.AddRange(meshContext.UVBuffers[0].Buffer);

                currMeshContextIndex++;
            }

            Vector3[] positions = positionsList.ToArray();
            Vector3[] tangentX  = tangentXList.ToArray();
            Vector3[] tangentY  = tangentYList.ToArray();
            Vector3[] tangentZ  = tangentZList.ToArray();
            Vector2[] texcoords = texcoordsList.ToArray();

            Int32 numPositions = positions.Count();
            if (numPositions != texcoords.Count())
            {
                return(false);
            }

            // create the list of vertex info
            List <VertexInfo> vertexInfoList = new List <VertexInfo>();
#if DEBUG
            List <Boolean> taggedVertexInfoList = new List <Boolean>();
#endif

            for (Int32 i = 0; i < numPositions; ++i)
            {
                vertexInfoList.Add(new VertexInfo());
                vertexInfoList[i].VertexIndex = i;
#if DEBUG
                taggedVertexInfoList.Add(false);
#endif
            }

            // set the triangle index
            // create collection of index for all mesh contexts
            List <UInt32> indexList        = new List <UInt32>();
            Int32         meshContextIndex = 0;
            foreach (H1MeshContext meshContext in meshContexts)
            {
                // using meshContextOffsetsList information, remap indices correctly
                foreach (UInt32 vertexIndex in meshContext.Indices)
                {
                    indexList.Add(Convert.ToUInt32(meshContextOffsetsList[meshContextIndex]) + vertexIndex);
                }

                meshContextIndex++;
            }

            UInt32[] indices = indexList.ToArray();
#if DEBUG
            Boolean[] taggedIndices = new Boolean[indexList.Count];
#endif

            // looping index, set triangle index for each vertexInfoList
            Int32 indexOfIndex = 0;
            foreach (UInt32 index in indices)
            {
                Int32 vertexIndex   = Convert.ToInt32(index);
                Int32 triangleIndex = indexOfIndex / 3;

                // set the triangle index
                vertexInfoList[vertexIndex].TriangleIndices.Add(triangleIndex);
#if DEBUG
                taggedIndices[indexOfIndex] = false;
#endif
                indexOfIndex++;
            }

            // process vertex weights and bone index in advance by looping all H1MeshBoneInfo
            Int32 meshBoneInfoIndex = 0;
            foreach (H1MeshBoneInfo meshBoneInfo in refSkeleton.RefBoneInfoList)
            {
                Int32 jointNodeIndex             = skeletalContext.JointNodes.FindIndex(x => x.JointName == meshBoneInfo.Name);
                H1SkeletalContext.JointNode node = skeletalContext.JointNodes[jointNodeIndex];

                foreach (H1SkeletalContext.Joint nodeData in node.JointDataList)
                {
                    // looping weighted vertices
                    Int32 vertexIndexOffset = nodeData.MeshContextIndex == -1 ? 0 : meshContextOffsetsList[nodeData.MeshContextIndex];
                    // process vertex weights and bone index
                    foreach (H1SkeletalContext.WeightedVertex weightedVertex in nodeData.WeightedVertices)
                    {
                        VertexInfo.InfluenceBoneData influencedBoneData = new VertexInfo.InfluenceBoneData();
                        influencedBoneData.BoneIndex  = meshBoneInfoIndex;
                        influencedBoneData.BoneWeight = weightedVertex.Weight;

                        vertexInfoList[vertexIndexOffset + weightedVertex.VertexIndex].InfluencedBones.Add(influencedBoneData);
                    }
                }
                meshBoneInfoIndex++;
            }

#if DEBUG
            // verification code for vertex weights
            List <float> taggedVertexWeights = new List <float>();
            foreach (VertexInfo vertexInfo in vertexInfoList)
            {
                float totalWeight = 0.0f;
                foreach (VertexInfo.InfluenceBoneData influencedBoneData in vertexInfo.InfluencedBones)
                {
                    totalWeight += influencedBoneData.BoneWeight;
                }
                taggedVertexWeights.Add(totalWeight);
            }

            List <Int32> invalidVertexIndices = new List <Int32>();
            Int32        currVertexIndex      = 0;
            foreach (float totalWeight in taggedVertexWeights)
            {
                if (totalWeight < 0.99f)
                {
                    invalidVertexIndices.Add(currVertexIndex);
                }
                currVertexIndex++;
            }

            if (invalidVertexIndices.Count > 0)
            {
                return(false);
            }
#endif

            // looping meshBoneInfo, set bone index and bone weight
            foreach (H1MeshBoneInfo meshBoneInfo in refSkeleton.RefBoneInfoList)
            {
                Int32 jointNodeIndex             = skeletalContext.JointNodes.FindIndex(x => x.JointName == meshBoneInfo.Name);
                H1SkeletalContext.JointNode node = skeletalContext.JointNodes[jointNodeIndex];
                List <UInt32> ChunkVertexIndices = new List <UInt32>(); // vertex indices for this chunk (bone node)

                foreach (H1SkeletalContext.Joint nodeData in node.JointDataList)
                {
                    // looping weighted vertices
                    Int32 vertexIndexOffset = nodeData.MeshContextIndex == -1 ? 0 : meshContextOffsetsList[nodeData.MeshContextIndex];
                    // add chunk vertex indices
                    foreach (H1SkeletalContext.WeightedVertex weightedVertex in nodeData.WeightedVertices)
                    {
                        ChunkVertexIndices.Add(Convert.ToUInt32(vertexIndexOffset + weightedVertex.VertexIndex));
                    }
                }

                // exceptional handling for MeshBoneInfo which doesn't contain any mesh data, no need to generate chunk for this BasePose
                if (ChunkVertexIndices.Count == 0)
                {
                    continue;
                }

                // process skeletal mesh chunk
                H1SkelMeshChunk skelMeshChunk = new H1SkelMeshChunk();
                // calculate triangles for this mesh chunk
                List <UInt32> triangles = new List <UInt32>();

                foreach (Int32 vertexIndex in ChunkVertexIndices)
                {
                    VertexInfo vertexInfo = vertexInfoList[vertexIndex];

                    H1SoftSkinVertex newSoftSkinVertex = new H1SoftSkinVertex();
                    newSoftSkinVertex.Position = positions[vertexInfo.VertexIndex];
                    newSoftSkinVertex.TangentX = tangentX[vertexInfo.VertexIndex];
                    newSoftSkinVertex.TangentY = tangentY[vertexInfo.VertexIndex];
                    newSoftSkinVertex.TangentZ = tangentZ[vertexInfo.VertexIndex];

                    // @TODO - in the future, it could increase texcoords (ex. light map texcoord)
                    newSoftSkinVertex.UVs[0] = texcoords[vertexInfo.VertexIndex];

                    for (Int32 i = 0; i < H1ObjectGlobalDefinitions.MAX_TOTAL_INFLUENCES; ++i)
                    {
                        if (vertexInfo.InfluencedBones.Count <= i)
                        {
                            // insert the default value
                            newSoftSkinVertex.InfluenceWeights[i] = 0;
                            newSoftSkinVertex.InfluenceBones[i]   = 0;
                            continue;
                        }

                        VertexInfo.InfluenceBoneData boneData = vertexInfo.InfluencedBones[i];
                        newSoftSkinVertex.InfluenceWeights[i] = Convert.ToByte(boneData.BoneWeight * 255.0f);
                        // @TODO - for this bone index, we can replace with 'm_BoneMap'
                        newSoftSkinVertex.InfluenceBones[i] = Convert.ToByte(boneData.BoneIndex);
                    }

                    skelMeshChunk.SoftVertices.Add(newSoftSkinVertex);

                    // process triangle indices
                    foreach (Int32 triangleIndex in vertexInfo.TriangleIndices)
                    {
                        UInt32 triangleIndexUInt32 = Convert.ToUInt32(triangleIndex);
                        if (!triangles.Exists(x => { return(x == triangleIndexUInt32); }))
                        {
                            triangles.Add(triangleIndexUInt32);
                        }
                    }
                }

                // build vertex buffers
                List <Vector4> chunkPositions   = new List <Vector4>();
                List <Vector4> chunkTangentZs   = new List <Vector4>();
                List <Vector4> chunkTangentXs   = new List <Vector4>();
                List <Vector2> chunkTexcoords   = new List <Vector2>();
                List <Int4>    chunkBoneIndices = new List <Int4>();
                List <Vector4> chunkBoneWeights = new List <Vector4>();
                List <Vector4> chunkColors      = new List <Vector4>();

                Dictionary <Int32, Int32> vertexToChunkVertexMap = new Dictionary <Int32, Int32>();
                foreach (Int32 triangleIndex in triangles)
                {
                    for (Int32 faceIndex = 0; faceIndex < 3; ++faceIndex)
                    {
                        Int32 vertexIndex = Convert.ToInt32(indices[triangleIndex * 3 + faceIndex]);

#if DEBUG
                        taggedVertexInfoList[vertexIndex] = true;
#endif

                        // determine if the same vertex exists based on chunkPositions
                        //if (chunkPositions.Contains(new Vector4(positions[vertexIndex], 1.0f)))
                        if (vertexToChunkVertexMap.ContainsKey(vertexIndex))
                        {
                            continue;
                        }

                        // position index is base-index
                        Int32 newIndex = chunkPositions.Count;
                        vertexToChunkVertexMap.Add(vertexIndex, newIndex);

                        chunkPositions.Add(new Vector4(positions[vertexIndex], 1.0f));
                        chunkTangentZs.Add(new Vector4(tangentZ[vertexIndex], 1.0f));
                        chunkTangentXs.Add(new Vector4(tangentX[vertexIndex], 1.0f));
                        chunkTexcoords.Add(new Vector2(texcoords[vertexIndex].X, texcoords[vertexIndex].Y));

                        VertexInfo vertexInfo        = vertexInfoList[vertexIndex];
                        Int4       influencedBones   = new Int4(0);
                        Vector4    influencedWeights = new Vector4(0.0f);

                        Int32 insertedIndex = 0;
                        foreach (VertexInfo.InfluenceBoneData boneData in vertexInfo.InfluencedBones)
                        {
                            influencedBones[insertedIndex]   = boneData.BoneIndex;
                            influencedWeights[insertedIndex] = boneData.BoneWeight;
                            insertedIndex++;
                        }

                        chunkBoneIndices.Add(influencedBones);
                        chunkBoneWeights.Add(influencedWeights);

                        //@TODO - temporary set it as 'RED'
                        chunkColors.Add(new Vector4(1.0f, 0.0f, 0.0f, 1.0f));
                    }
                }

                // create skeletal mesh vertex data
                // 1. position
                H1SkeletalMeshVertexData <Vector4> positionVertexData = new H1SkeletalMeshVertexData <Vector4>();
                positionVertexData.SetVertexData(chunkPositions.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.Position, false);
                // 2. tangentZ
                H1SkeletalMeshVertexData <Vector4> tangentZVertexData = new H1SkeletalMeshVertexData <Vector4>();
                tangentZVertexData.SetVertexData(chunkTangentZs.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.TangentZ, false);
                // 3. tangentX
                H1SkeletalMeshVertexData <Vector4> tangentXVertexData = new H1SkeletalMeshVertexData <Vector4>();
                tangentXVertexData.SetVertexData(chunkTangentXs.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.TangentX, false);
                // 4. bone indices
                H1SkeletalMeshVertexData <Int4> boneIndicesVertexData = new H1SkeletalMeshVertexData <Int4>();
                boneIndicesVertexData.SetVertexData(chunkBoneIndices.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.InfluencedBones, false);
                // 5. bone weights
                H1SkeletalMeshVertexData <Vector4> boneWeightsVertexData = new H1SkeletalMeshVertexData <Vector4>();
                boneWeightsVertexData.SetVertexData(chunkBoneWeights.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.InfluencedWeights, false);
                // 6. texcoord
                H1SkeletalMeshVertexData <Vector2> texcoordVertexData = new H1SkeletalMeshVertexData <Vector2>();
                texcoordVertexData.SetVertexData(chunkTexcoords.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.Texcoord, false);
                // 7. colors
                H1SkeletalMeshVertexData <Vector4> colorVertexData = new H1SkeletalMeshVertexData <Vector4>();
                colorVertexData.SetVertexData(chunkColors.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.Color);

                Int32 newSkelMeshChunkIndex = staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers.Count;
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers.Add(new H1SkeletalMeshVertexBuffers(newSkelMeshChunkIndex));
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(positionVertexData);
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(tangentZVertexData);
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(tangentXVertexData);
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(boneIndicesVertexData);
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(boneWeightsVertexData);
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(texcoordVertexData);
                staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(colorVertexData);

                // build index buffer
                List <UInt32> chunkIndices = new List <UInt32>();
                foreach (Int32 triangleIndex in triangles)
                {
                    for (Int32 faceIndex = 0; faceIndex < 3; ++faceIndex)
                    {
#if DEBUG
                        taggedIndices[triangleIndex * 3 + faceIndex] = true;
#endif
                        Int32 vertexIndex = Convert.ToInt32(indices[triangleIndex * 3 + faceIndex]);
                        chunkIndices.Add(Convert.ToUInt32(vertexToChunkVertexMap[vertexIndex]));
                    }
                }

                staticLODModel.MultiSizeIndexContainer.Indices.AddRange(chunkIndices.ToArray());

                // add new chunk
                Int32 newChunkIndex = staticLODModel.Chunks.Count;
                staticLODModel.Chunks.Add(skelMeshChunk);

                // process skeletal mesh section
                H1SkelMeshSection skelMeshSection = new H1SkelMeshSection();
                skelMeshSection.ChunkIndex = Convert.ToUInt16(newChunkIndex);

                // @TODO - fix this num triangle inconsistency
                //skelMeshSection.NumTriangles = Convert.ToUInt16(triangles.Count);
                skelMeshSection.NumTriangles = Convert.ToUInt16(chunkIndices.Count / 3);

                //@TODO - add material index

                // add skeletal sections
                staticLODModel.Sections.Add(skelMeshSection);
            }

#if DEBUG
            // debugging code for detecting missing vertex to draw meshes
            List <Int32> notTaggedVertexIndex  = new List <Int32>();
            Int32        currTaggedVertexIndex = 0;
            foreach (Boolean isTaggedVertex in taggedVertexInfoList)
            {
                if (isTaggedVertex == false)
                {
                    notTaggedVertexIndex.Add(currTaggedVertexIndex);
                }
                currTaggedVertexIndex++;
            }
            if (notTaggedVertexIndex.Count > 0)
            {
                return(false);
            }

            // debugging code for detecting missing index to draw meshes
            List <Int32> notTaggedIndex   = new List <Int32>();
            Int32        currIndexOfIndex = 0;
            foreach (Boolean isTaggedIndex in taggedIndices)
            {
                if (isTaggedIndex == false)
                {
                    notTaggedIndex.Add(currIndexOfIndex);
                }
                currIndexOfIndex++;
            }
            if (notTaggedIndex.Count > 0)
            {
                return(false);
            }
#endif

            return(true);
        }
Exemplo n.º 4
0
        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);
        }