List<int> SortBones(IIGameSkin skin)
        {
            var boneIds = new List<int>();
            var boneIndex = new Dictionary<int, IIGameNode>();
            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var bone = skin.GetIGameBone(index, false);
                if (bone == null)
                {
                    // non bone in skeletton
                    boneIds.Add(-2);

                }
                else
                {
                    boneIds.Add(bone.NodeID);
                    boneIndex[bone.NodeID] = bone;
                }
            }
            while (true)
            {
                bool foundMisMatch = false;
                for (int i = 0; i < boneIds.Count; ++i)
                {
                    var id = boneIds[i];
                    if (id == -2)
                    {
                        continue;
                    }
                    var parent = boneIndex[id].NodeParent;
                    if (parent != null)
                    {
                        var parentId = parent.NodeID;
                        if (boneIds.IndexOf(parentId) > i)
                        {
                            boneIds.RemoveAt(i);
                            boneIds.Insert(boneIds.IndexOf(parentId) + 1, id);
                            foundMisMatch = true;
                            break;
                        }
                    }
                }
                if (!foundMisMatch)
                {
                    break;
                }
            }
            return boneIds;

        }
Exemple #2
0
        int CreateGlobalVertex(IIGameMesh mesh, IFaceEx face, int facePart, List <GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List <GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin, List <int> boneIds)
        {
            var vertexIndex = (int)face.Vert[facePart];

            var vertex = new GlobalVertex
            {
                BaseIndex = vertexIndex,
                Position  = mesh.GetVertex(vertexIndex, true),
                Normal    = mesh.GetNormal((int)face.Norm[facePart], true)
            };

            if (hasUV)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(1, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(1, indices[facePart]);
                vertex.UV = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasUV2)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(2, indices[facePart]);
                vertex.UV2 = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasColor)
            {
                var   vertexColorIndex = (int)face.Color[facePart];
                var   vertexColor      = mesh.GetColorVertex(vertexColorIndex);
                float alpha            = 1;
                if (hasAlpha)
                {
                    var indices = new int[3];
                    unsafe
                    {
                        fixed(int *indicesPtr = indices)
                        {
                            mesh.GetMapFaceIndex(-2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                        }
                    }
                    var color = mesh.GetMapVertex(-2, indices[facePart]);

                    alpha = color.X;
                }

                vertex.Color = new[] { vertexColor.X, vertexColor.Y, vertexColor.Z, alpha };
            }

            if (skin != null)
            {
                float weight0 = 0;
                float weight1 = 0;
                float weight2 = 0;
                float weight3 = 0;
                int   bone0   = bonesCount;
                int   bone1   = bonesCount;
                int   bone2   = bonesCount;
                int   bone3   = bonesCount;
                var   nbBones = skin.GetNumberOfBones(vertexIndex);

                if (nbBones > 0)
                {
                    bone0   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 0).NodeID);
                    weight0 = skin.GetWeight(vertexIndex, 0);
                }

                if (nbBones > 1)
                {
                    bone1   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 1).NodeID);
                    weight1 = skin.GetWeight(vertexIndex, 1);
                }

                if (nbBones > 2)
                {
                    bone2   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 2).NodeID);
                    weight2 = skin.GetWeight(vertexIndex, 2);
                }

                if (nbBones > 3)
                {
                    bone3   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 3).NodeID);
                    weight3 = skin.GetWeight(vertexIndex, 3);
                }

                if (nbBones == 0)
                {
                    weight0 = 1.0f;
                    bone0   = bonesCount;
                }

                vertex.Weights      = Loader.Global.Point4.Create(weight0, weight1, weight2, weight3);
                vertex.BonesIndices = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;

                if (nbBones > 4)
                {
                    bone0   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 4).NodeID);
                    weight0 = skin.GetWeight(vertexIndex, 4);

                    weight1 = 0;
                    weight2 = 0;
                    weight3 = 0;

                    if (nbBones > 5)
                    {
                        bone1   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 5).NodeID);
                        weight1 = skin.GetWeight(vertexIndex, 5);
                    }

                    if (nbBones > 6)
                    {
                        bone2   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 6).NodeID);
                        weight2 = skin.GetWeight(vertexIndex, 6);
                    }

                    if (nbBones > 7)
                    {
                        bone3   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 7).NodeID);
                        weight3 = skin.GetWeight(vertexIndex, 7);
                    }

                    vertex.WeightsExtra      = Loader.Global.Point4.Create(weight0, weight1, weight2, weight3);
                    vertex.BonesIndicesExtra = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;

                    if (nbBones > 8)
                    {
                        RaiseError("Too many bones influences per vertex: " + nbBones + ". Babylon.js only support 8 bones influences per vertex.", 2);
                    }
                }
            }

            if (verticesAlreadyExported != null)
            {
                if (verticesAlreadyExported[vertexIndex] != null)
                {
                    var index = verticesAlreadyExported[vertexIndex].IndexOf(vertex);

                    if (index > -1)
                    {
                        return(verticesAlreadyExported[vertexIndex][index].CurrentIndex);
                    }
                }
                else
                {
                    verticesAlreadyExported[vertexIndex] = new List <GlobalVertex>();
                }

                vertex.CurrentIndex = vertices.Count;
                verticesAlreadyExported[vertexIndex].Add(vertex);
            }

            vertices.Add(vertex);

            return(vertices.Count - 1);
        }
        int CreateGlobalVertex(IIGameMesh mesh, IFaceEx face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List<GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin, List<int> boneIds)
        {
            var vertexIndex = (int)face.Vert[facePart];

            var vertex = new GlobalVertex
            {
                BaseIndex = vertexIndex,
                Position = mesh.GetVertex(vertexIndex, true),
                Normal = mesh.GetNormal((int)face.Norm[facePart], true)
            };

            if (hasUV)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed (int* indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(1, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(1, indices[facePart]);
                vertex.UV = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasUV2)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed (int* indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(2, indices[facePart]);
                vertex.UV2 = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasColor)
            {
                var vertexColorIndex = (int)face.Color[facePart];
                var vertexColor = mesh.GetColorVertex(vertexColorIndex);
                float alpha = 1;
                if (hasAlpha)
                {
                    var indices = new int[3];
                    unsafe
                    {
                        fixed (int* indicesPtr = indices)
                        {
                            mesh.GetMapFaceIndex(-2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                        }
                    }
                    var color = mesh.GetMapVertex(-2, indices[facePart]);

                    alpha = color.X;
                }

                vertex.Color = new[] { vertexColor.X, vertexColor.Y, vertexColor.Z, alpha };
            }

            if (skin != null)
            {
                float weight0 = 0;
                float weight1 = 0;
                float weight2 = 0;
                int bone0 = bonesCount;
                int bone1 = bonesCount;
                int bone2 = bonesCount;
                int bone3 = bonesCount;
                int nbBones = skin.GetNumberOfBones(vertexIndex);

                if (nbBones > 0)
                {
                    bone0 = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 0).NodeID);
                    weight0 = skin.GetWeight(vertexIndex, 0);
                }

                if (nbBones > 1)
                {
                    bone1 = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 1).NodeID);
                    weight1 = skin.GetWeight(vertexIndex, 1);
                }

                if (nbBones > 2)
                {
                    bone2 = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 2).NodeID);
                    weight2 = skin.GetWeight(vertexIndex, 2);
                }

                if (nbBones > 3)
                {
                    bone3 = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 3).NodeID);
                }

                if (nbBones == 0)
                {
                    weight0 = 1.0f;
                    bone0 = bonesCount;
                }

                if (nbBones > 4)
                {
                    RaiseError("Too many bones influences per vertex: " + nbBones + ". Babylon.js only support 4 bones influences per vertex.", 2);
                }

                vertex.Weights = Loader.Global.Point4.Create(weight0, weight1, weight2, 1.0 - weight0 - weight1 - weight2);
                vertex.BonesIndices = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;
            }

            if (verticesAlreadyExported != null)
            {
                if (verticesAlreadyExported[vertexIndex] != null)
                {
                    var index = verticesAlreadyExported[vertexIndex].IndexOf(vertex);

                    if (index > -1)
                    {
                        return verticesAlreadyExported[vertexIndex][index].CurrentIndex;
                    }
                }
                else
                {
                    verticesAlreadyExported[vertexIndex] = new List<GlobalVertex>();
                }

                vertex.CurrentIndex = vertices.Count;
                verticesAlreadyExported[vertexIndex].Add(vertex);
            }

            vertices.Add(vertex);

            return vertices.Count - 1;
        }
        int CreateGlobalVertex(IIGameNode meshNode, IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IFaceEx face, int facePart, List <GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List <GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin, List <int> boneIds)
        {
            var vertexIndex = (int)face.Vert[facePart];

            // Position can by retreived in world space or object space
            // Unfortunately, this value can't be retreived in local space
            var vertex = new GlobalVertex
            {
                BaseIndex = vertexIndex,
                Position  = mesh.GetVertex(vertexIndex, false),             // world space
                Normal    = mesh.GetNormal((int)face.Norm[facePart], false) // world space
            };

            if (exportParameters.exportTangents)
            {
                int     indexTangentBinormal = mesh.GetFaceVertexTangentBinormal(face.MeshFaceIndex, facePart, 1);
                IPoint3 normal    = vertex.Normal.Normalize;
                IPoint3 tangent   = mesh.GetTangent(indexTangentBinormal, 1).Normalize;
                IPoint3 bitangent = mesh.GetBinormal(indexTangentBinormal, 1).Normalize;
                int     w         = GetW(normal, tangent, bitangent);
                vertex.Tangent = new float[] { tangent.X, tangent.Y, tangent.Z, w };
            }

            // Convert position and normal to local space
            vertex.Position = invertedWorldMatrix.PointTransform(vertex.Position);

            vertex.Normal = invertedWorldMatrix.VectorTransform(vertex.Normal);
            // 1. scale normals with node scales
            var nodeScaling = BabylonVector3.FromArray(babylonAbstractMesh.scaling);

            vertex.Normal = vertex.Normal.Multiply(Loader.Global.Point3.Create(Math.Abs(nodeScaling.X), Math.Abs(nodeScaling.Y), Math.Abs(nodeScaling.Z)));

            // 2. scale normals with objectOffsetScales (unrotate by objectOffsetRot, then scale, then rotate again)
            // note: LH coordinate system => flip y and z
            var objOffsetScale          = Loader.Global.Point3.Create(meshNode.MaxNode.ObjOffsetScale.S);
            var scaleX                  = Math.Abs(objOffsetScale.X);
            var scaleY                  = Math.Abs(objOffsetScale.Y);
            var scaleZ                  = Math.Abs(objOffsetScale.Z);
            var objOffsetScaleFlipYZInv = Loader.Global.Point3.Create(1 / scaleX, 1 / scaleZ, 1 / scaleY);

            var objOffsetQuat = meshNode.MaxNode.ObjOffsetRot;
            var qFlippedYZ    = objOffsetQuat;
            var tmpSwap       = objOffsetQuat.Y;

            qFlippedYZ.Y = objOffsetQuat.Z;
            qFlippedYZ.Z = tmpSwap;

            var nUnrotated       = RotateVectorByQuaternion(vertex.Normal, qFlippedYZ);
            var nUnrotatedScaled = nUnrotated.Multiply(objOffsetScaleFlipYZInv);

            nUnrotatedScaled = nUnrotatedScaled.Normalize;
            var nRerotatedScaled = RotateVectorByQuaternion(nUnrotatedScaled, qFlippedYZ.Conjugate);

            vertex.Normal = nRerotatedScaled;

            if (hasUV)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(1, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(1, indices[facePart]);
                vertex.UV = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasUV2)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(2, indices[facePart]);
                vertex.UV2 = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasColor)
            {
                var   vertexColorIndex = (int)face.Color[facePart];
                var   vertexColor      = mesh.GetColorVertex(vertexColorIndex);
                float alpha            = 1;
                if (hasAlpha)
                {
                    var indices = new int[3];
                    unsafe
                    {
                        fixed(int *indicesPtr = indices)
                        {
                            mesh.GetMapFaceIndex(-2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                        }
                    }
                    var color = mesh.GetMapVertex(-2, indices[facePart]);

                    alpha = color.X;
                }

                vertex.Color = new[] { vertexColor.X, vertexColor.Y, vertexColor.Z, alpha };
            }

            if (skin != null)
            {
                float weight0 = 0;
                float weight1 = 0;
                float weight2 = 0;
                float weight3 = 0;
                int   bone0   = bonesCount;
                int   bone1   = bonesCount;
                int   bone2   = bonesCount;
                int   bone3   = bonesCount;
                var   nbBones = skin.GetNumberOfBones(vertexIndex);

                if (nbBones > 0)
                {
                    bone0   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 0).NodeID);
                    weight0 = skin.GetWeight(vertexIndex, 0);
                }

                if (nbBones > 1)
                {
                    bone1   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 1).NodeID);
                    weight1 = skin.GetWeight(vertexIndex, 1);
                }

                if (nbBones > 2)
                {
                    bone2   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 2).NodeID);
                    weight2 = skin.GetWeight(vertexIndex, 2);
                }

                if (nbBones > 3)
                {
                    bone3   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 3).NodeID);
                    weight3 = skin.GetWeight(vertexIndex, 3);
                }

                if (nbBones == 0)
                {
                    weight0 = 1.0f;
                    bone0   = bonesCount;
                }

                vertex.Weights      = Loader.Global.Point4.Create(weight0, weight1, weight2, weight3);
                vertex.BonesIndices = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;

                if (nbBones > 4)
                {
                    bone0   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 4).NodeID);
                    weight0 = skin.GetWeight(vertexIndex, 4);

                    weight1 = 0;
                    weight2 = 0;
                    weight3 = 0;

                    if (nbBones > 5)
                    {
                        bone1   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 5).NodeID);
                        weight1 = skin.GetWeight(vertexIndex, 5);
                    }

                    if (nbBones > 6)
                    {
                        bone2   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 6).NodeID);
                        weight2 = skin.GetWeight(vertexIndex, 6);
                    }

                    if (nbBones > 7)
                    {
                        bone3   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, 7).NodeID);
                        weight3 = skin.GetWeight(vertexIndex, 7);
                    }

                    vertex.WeightsExtra      = Loader.Global.Point4.Create(weight0, weight1, weight2, weight3);
                    vertex.BonesIndicesExtra = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;

                    if (nbBones > 8)
                    {
                        RaiseError("Too many bones influences per vertex: " + nbBones + ". Babylon.js only support 8 bones influences per vertex.", 2);
                    }
                }
            }

            if (verticesAlreadyExported != null)
            {
                if (verticesAlreadyExported[vertexIndex] != null)
                {
                    var index = verticesAlreadyExported[vertexIndex].IndexOf(vertex);

                    if (index > -1)
                    {
                        return(verticesAlreadyExported[vertexIndex][index].CurrentIndex);
                    }
                }
                else
                {
                    verticesAlreadyExported[vertexIndex] = new List <GlobalVertex>();
                }

                vertex.CurrentIndex = vertices.Count;
                verticesAlreadyExported[vertexIndex].Add(vertex);
            }

            vertices.Add(vertex);

            return(vertices.Count - 1);
        }
        private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene)
        {
            var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) };
            babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;

            RaiseMessage(babylonSkeleton.name, 1);

            var skinIndex = skins.IndexOf(skin);

            var bones = new List<BabylonBone>();
            var gameBones = new List<IIGameNode>();
            var boneIds = new List<int>();
            var bindPoseInfos = new List<BonePoseInfo>();
            for(int i = 0; i < skin.TotalSkinBoneCount; ++i)
            {
                bones.Add(null);
                gameBones.Add(null);
                boneIds.Add(-1);
                bindPoseInfos.Add(null);
            }
            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var gameBone = skin.GetIGameBone(index, false);

                var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID);

                gameBones[sortedIndex] = (gameBone);
                boneIds[sortedIndex] =(gameBone.NodeID);
                bones[sortedIndex]=(new BabylonBone { index = sortedIndex, name = gameBone.Name });

                var boneInitMatrix = gameBone.GetObjectTM(0);
                bindPoseInfos[sortedIndex] = (new BonePoseInfo { AbsoluteTransform = boneInitMatrix });
            }

            // fix hierarchy an generate animation keys
            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");

            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var gameBone = gameBones[index];
                var parent = gameBone.NodeParent;
                var babBone = bones[index];
                if (parent != null)
                {
                    babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID);
                }

                if (babBone.parentBoneIndex == -1)
                {
                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform;
                }
                else
                {
                    var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex];
                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse);
                }

                babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray();

                var babylonAnimation = new BabylonAnimation
                {
                    name = gameBone.Name + "Animation",
                    property = "_matrix",
                    dataType = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = Loader.Global.FrameRate
                };

                var start = Loader.Core.AnimRange.Start;
                var end = Loader.Core.AnimRange.End;

                float[] previous = null;
                var keys = new List<BabylonAnimationKey>();
                for (var key = start; key <= end; key += Ticks)
                {
                    var objectTM = gameBone.GetObjectTM(key);
                    var parentNode = gameBone.NodeParent;
                    IGMatrix mat;
                    if (parentNode == null || babBone.parentBoneIndex == -1)
                    {
                        mat = objectTM;
                    }
                    else
                    {
                        mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
                    }

                    var current = mat.ToArray();
                    if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current)))
                    {
                        keys.Add(new BabylonAnimationKey
                        {
                            frame = key / Ticks,
                            values = current
                        });
                    }

                    previous = current;
                }

                babylonAnimation.keys = keys.ToArray();
                babBone.animation = babylonAnimation;
            }

            babylonSkeleton.needInitialSkinMatrix = true;
            babylonSkeleton.bones = bones.ToArray();

            babylonScene.SkeletonsList.Add(babylonSkeleton);
        }
Exemple #6
0
        int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, IFaceEx face, int facePart, List <GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List <GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin, List <int> boneIds)
        {
            var vertexIndex = (int)face.Vert[facePart];

            // Position can by retrieved in world space or object space
            // Unfortunately, this value can't be retrieved in local space
            var vertex = new GlobalVertex
            {
                BaseIndex = vertexIndex,
                Position  = mesh.GetVertex(vertexIndex, false),            // world space
                Normal    = mesh.GetNormal((int)face.Norm[facePart], true) // object space (world space was somehow bugged for normal)
            };

            //System.Diagnostics.Debug.WriteLine("vertex normal: " + string.Join(", ", vertex.Normal.ToArray().Select(v => Math.Round(v, 3))));

            // position (from world to local/node space)
            vertex.Position = invertedWorldMatrix.PointTransform(vertex.Position);

            // normal (from object to local/node space)
            vertex.Normal = offsetTM.VectorTransform(vertex.Normal).Normalize;

            // tangent
            if (exportParameters.exportTangents)
            {
                int     indexTangentBinormal = mesh.GetFaceVertexTangentBinormal(face.MeshFaceIndex, facePart, 1);
                IPoint3 normal    = vertex.Normal.Normalize;
                IPoint3 tangent   = mesh.GetTangent(indexTangentBinormal, 1).Normalize;
                IPoint3 bitangent = mesh.GetBinormal(indexTangentBinormal, 1).Normalize;
                int     w         = GetW(normal, tangent, bitangent);
                vertex.Tangent = new float[] { tangent.X, tangent.Y, tangent.Z, w };
            }

            if (hasUV)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(1, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(1, indices[facePart]);
                vertex.UV = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasUV2)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(2, indices[facePart]);
                vertex.UV2 = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasColor)
            {
                var   vertexColorIndex = (int)face.Color[facePart];
                var   vertexColor      = mesh.GetColorVertex(vertexColorIndex);
                float alpha            = 1;
                if (hasAlpha)
                {
                    var indices = new int[3];
                    unsafe
                    {
                        fixed(int *indicesPtr = indices)
                        {
                            mesh.GetMapFaceIndex(-2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                        }
                    }
                    var color = mesh.GetMapVertex(-2, indices[facePart]);

                    alpha = color.X;
                }

                vertex.Color = new[] { vertexColor.X, vertexColor.Y, vertexColor.Z, alpha };
            }

            if (skin != null)
            {
                float[] weight = new float[4] {
                    0, 0, 0, 0
                };
                int[] bone = new int[4] {
                    0, 0, 0, 0
                };
                var nbBones = skin.GetNumberOfBones(vertexIndex);

                int currentVtxBone  = 0;
                int currentSkinBone = 0;

                // process skin bones until we have 4 bones for this vertex or we run out of skin bones
                for (currentSkinBone = 0; currentSkinBone < nbBones && currentVtxBone < 4; ++currentSkinBone)
                {
                    float boneWeight = skin.GetWeight(vertexIndex, currentSkinBone);
                    if (boneWeight <= 0)
                    {
                        continue;
                    }

                    bone[currentVtxBone]   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID);
                    weight[currentVtxBone] = skin.GetWeight(vertexIndex, currentSkinBone);
                    ++currentVtxBone;
                }

                // if we didnt have any bones with a weight > 0
                if (currentVtxBone == 0)
                {
                    weight[0] = 1.0f;
                    bone[0]   = 0;
                }

                vertex.Weights      = Loader.Global.Point4.Create(weight);
                vertex.BonesIndices = (bone[3] << 24) | (bone[2] << 16) | (bone[1] << 8) | bone[0];

                if (currentVtxBone >= 4 && currentSkinBone < nbBones)
                {
                    weight = new float[4] {
                        0, 0, 0, 0
                    };
                    bone = new int[4] {
                        0, 0, 0, 0
                    };

                    // process remaining skin bones until we have a total of 8 bones for this vertex or we run out of skin bones
                    for (; currentSkinBone < nbBones && currentVtxBone < 8; ++currentSkinBone)
                    {
                        float boneWeight = skin.GetWeight(vertexIndex, currentSkinBone);
                        if (boneWeight <= 0)
                        {
                            continue;
                        }

                        if (isGltfExported)
                        {
                            RaiseError("Too many bone influences per vertex for vertexIndex: " + vertexIndex + ". glTF only supports up to 4 bone influences per vertex.", 2);
                            break;
                        }

                        bone[currentVtxBone - 4]   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID);
                        weight[currentVtxBone - 4] = skin.GetWeight(vertexIndex, currentSkinBone);
                        ++currentVtxBone;
                    }

                    // if we have any extra bone weights
                    if (currentVtxBone > 4)
                    {
                        vertex.WeightsExtra      = Loader.Global.Point4.Create(weight);
                        vertex.BonesIndicesExtra = (bone[3] << 24) | (bone[2] << 16) | (bone[1] << 8) | bone[0];

                        if (currentSkinBone < nbBones)
                        {
                            // if we have more skin bones left, this means we have used up all our bones for this vertex
                            // check if any of the remaining bones has a weight > 0
                            for (; currentSkinBone < nbBones; ++currentSkinBone)
                            {
                                float boneWeight = skin.GetWeight(vertexIndex, currentSkinBone);
                                if (boneWeight <= 0)
                                {
                                    continue;
                                }
                                RaiseError("Too many bone influences per vertex for vertexIndex: " + vertexIndex + ". Babylon.js only supports up to 8 bone influences per vertex.", 2);
                                break;
                            }
                        }
                    }
                }
            }

            if (verticesAlreadyExported != null)
            {
                if (verticesAlreadyExported[vertexIndex] != null)
                {
                    var index = verticesAlreadyExported[vertexIndex].IndexOf(vertex);

                    if (index > -1)
                    {
                        return(verticesAlreadyExported[vertexIndex][index].CurrentIndex);
                    }
                }
                else
                {
                    verticesAlreadyExported[vertexIndex] = new List <GlobalVertex>();
                }

                vertex.CurrentIndex = vertices.Count;
                verticesAlreadyExported[vertexIndex].Add(vertex);
            }

            vertices.Add(vertex);

            return(vertices.Count - 1);
        }
Exemple #7
0
        int CreateGlobalVertex(IIGameNode meshNode, IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh, IMatrix3 invertedWorldMatrix, IFaceEx face, int facePart, List <GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List <GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin, List <int> boneIds)
        {
            var vertexIndex = (int)face.Vert[facePart];

            // Position can by retreived in world space or object space
            // Unfortunately, this value can't be retreived in local space
            var vertex = new GlobalVertex
            {
                BaseIndex = vertexIndex,
                Position  = mesh.GetVertex(vertexIndex, false),             // world space
                Normal    = mesh.GetNormal((int)face.Norm[facePart], false) // world space
            };

            if (exportParameters.exportTangents)
            {
                int     indexTangentBinormal = mesh.GetFaceVertexTangentBinormal(face.MeshFaceIndex, facePart, 1);
                IPoint3 normal    = vertex.Normal.Normalize;
                IPoint3 tangent   = mesh.GetTangent(indexTangentBinormal, 1).Normalize;
                IPoint3 bitangent = mesh.GetBinormal(indexTangentBinormal, 1).Normalize;
                int     w         = GetW(normal, tangent, bitangent);
                vertex.Tangent = new float[] { tangent.X, tangent.Y, tangent.Z, w };
            }

            // Convert position and normal to local space
            vertex.Position = invertedWorldMatrix.PointTransform(vertex.Position);

            vertex.Normal = invertedWorldMatrix.VectorTransform(vertex.Normal);
            // 1. scale normals with node scales
            var nodeScaling = BabylonVector3.FromArray(babylonAbstractMesh.scaling);

            vertex.Normal = vertex.Normal.Multiply(Loader.Global.Point3.Create(Math.Abs(nodeScaling.X), Math.Abs(nodeScaling.Y), Math.Abs(nodeScaling.Z)));

            // 2. scale normals with objectOffsetScales (unrotate by objectOffsetRot, then scale, then rotate again)
            // note: LH coordinate system => flip y and z
            var objOffsetScale          = Loader.Global.Point3.Create(meshNode.MaxNode.ObjOffsetScale.S);
            var scaleX                  = Math.Abs(objOffsetScale.X);
            var scaleY                  = Math.Abs(objOffsetScale.Y);
            var scaleZ                  = Math.Abs(objOffsetScale.Z);
            var objOffsetScaleFlipYZInv = Loader.Global.Point3.Create(1 / scaleX, 1 / scaleZ, 1 / scaleY);

            var objOffsetQuat = meshNode.MaxNode.ObjOffsetRot;
            var qFlippedYZ    = objOffsetQuat;
            var tmpSwap       = objOffsetQuat.Y;

            qFlippedYZ.Y = objOffsetQuat.Z;
            qFlippedYZ.Z = tmpSwap;

            var nUnrotated       = RotateVectorByQuaternion(vertex.Normal, qFlippedYZ);
            var nUnrotatedScaled = nUnrotated.Multiply(objOffsetScaleFlipYZInv);

            nUnrotatedScaled = nUnrotatedScaled.Normalize;
            var nRerotatedScaled = RotateVectorByQuaternion(nUnrotatedScaled, qFlippedYZ.Conjugate);

            vertex.Normal = nRerotatedScaled;

            if (hasUV)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(1, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(1, indices[facePart]);
                vertex.UV = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasUV2)
            {
                var indices = new int[3];
                unsafe
                {
                    fixed(int *indicesPtr = indices)
                    {
                        mesh.GetMapFaceIndex(2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                    }
                }
                var texCoord = mesh.GetMapVertex(2, indices[facePart]);
                vertex.UV2 = Loader.Global.Point2.Create(texCoord.X, -texCoord.Y);
            }

            if (hasColor)
            {
                var   vertexColorIndex = (int)face.Color[facePart];
                var   vertexColor      = mesh.GetColorVertex(vertexColorIndex);
                float alpha            = 1;
                if (hasAlpha)
                {
                    var indices = new int[3];
                    unsafe
                    {
                        fixed(int *indicesPtr = indices)
                        {
                            mesh.GetMapFaceIndex(-2, face.MeshFaceIndex, new IntPtr(indicesPtr));
                        }
                    }
                    var color = mesh.GetMapVertex(-2, indices[facePart]);

                    alpha = color.X;
                }

                vertex.Color = new[] { vertexColor.X, vertexColor.Y, vertexColor.Z, alpha };
            }

            if (skin != null)
            {
                float[] weight = new float[4] {
                    0, 0, 0, 0
                };
                int[] bone = new int[4] {
                    bonesCount, bonesCount, bonesCount, bonesCount
                };
                var nbBones = skin.GetNumberOfBones(vertexIndex);

                int currentVtxBone  = 0;
                int currentSkinBone = 0;

                // process skin bones until we have 4 bones for this vertex or we run out of skin bones
                for (currentSkinBone = 0; currentSkinBone < nbBones && currentVtxBone < 4; ++currentSkinBone)
                {
                    float boneWeight = skin.GetWeight(vertexIndex, currentSkinBone);
                    if (boneWeight <= 0)
                    {
                        continue;
                    }

                    bone[currentVtxBone]   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID);
                    weight[currentVtxBone] = skin.GetWeight(vertexIndex, currentSkinBone);
                    ++currentVtxBone;
                }

                // if we didnt have any bones with a weight > 0
                if (currentVtxBone == 0)
                {
                    weight[0] = 1.0f;
                    bone[0]   = bonesCount;
                }

                vertex.Weights      = Loader.Global.Point4.Create(weight);
                vertex.BonesIndices = (bone[3] << 24) | (bone[2] << 16) | (bone[1] << 8) | bone[0];

                if (currentVtxBone >= 4 && currentSkinBone < nbBones)
                {
                    weight = new float[4] {
                        0, 0, 0, 0
                    };
                    bone = new int[4] {
                        bonesCount, bonesCount, bonesCount, bonesCount
                    };

                    // process remaining skin bones until we have a total of 8 bones for this vertex or we run out of skin bones
                    for (; currentSkinBone < nbBones && currentVtxBone < 8; ++currentSkinBone)
                    {
                        float boneWeight = skin.GetWeight(vertexIndex, currentSkinBone);
                        if (boneWeight <= 0)
                        {
                            continue;
                        }

                        if (isGltfExported)
                        {
                            RaiseError("Too many bone influences per vertex for vertexIndex: " + vertexIndex + ". glTF only supports up to 4 bone influences per vertex.", 2);
                            break;
                        }

                        bone[currentVtxBone - 4]   = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID);
                        weight[currentVtxBone - 4] = skin.GetWeight(vertexIndex, currentSkinBone);
                        ++currentVtxBone;
                    }

                    // if we have any extra bone weights
                    if (currentVtxBone > 4)
                    {
                        vertex.WeightsExtra      = Loader.Global.Point4.Create(weight);
                        vertex.BonesIndicesExtra = (bone[3] << 24) | (bone[2] << 16) | (bone[1] << 8) | bone[0];

                        if (currentSkinBone < nbBones)
                        {
                            // if we have more skin bones left, this means we have used up all our bones for this vertex
                            // check if any of the remaining bones has a weight > 0
                            for (; currentSkinBone < nbBones; ++currentSkinBone)
                            {
                                float boneWeight = skin.GetWeight(vertexIndex, currentSkinBone);
                                if (boneWeight <= 0)
                                {
                                    continue;
                                }
                                RaiseError("Too many bone influences per vertex for vertexIndex: " + vertexIndex + ". Babylon.js only supports up to 8 bone influences per vertex.", 2);
                                break;
                            }
                        }
                    }
                }
            }

            if (verticesAlreadyExported != null)
            {
                if (verticesAlreadyExported[vertexIndex] != null)
                {
                    var index = verticesAlreadyExported[vertexIndex].IndexOf(vertex);

                    if (index > -1)
                    {
                        return(verticesAlreadyExported[vertexIndex][index].CurrentIndex);
                    }
                }
                else
                {
                    verticesAlreadyExported[vertexIndex] = new List <GlobalVertex>();
                }

                vertex.CurrentIndex = vertices.Count;
                verticesAlreadyExported[vertexIndex].Add(vertex);
            }

            vertices.Add(vertex);

            return(vertices.Count - 1);
        }
        private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene)
        {
            var babylonSkeleton = new BabylonSkeleton {
                id = skins.IndexOf(skin)
            };

            babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;

            RaiseMessage(babylonSkeleton.name, 1);

            var skinIndex = skins.IndexOf(skin);

            var bones         = new List <BabylonBone>();
            var gameBones     = new List <IIGameNode>();
            var boneIds       = new List <int>();
            var bindPoseInfos = new List <BonePoseInfo>();

            for (int i = 0; i < skin.TotalSkinBoneCount; ++i)
            {
                bones.Add(null);
                gameBones.Add(null);
                boneIds.Add(-1);
                bindPoseInfos.Add(null);
            }
            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var gameBone = skin.GetIGameBone(index, false);

                var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID);

                gameBones[sortedIndex] = (gameBone);
                boneIds[sortedIndex]   = (gameBone.NodeID);
                bones[sortedIndex]     = (new BabylonBone {
                    index = sortedIndex, name = gameBone.Name
                });

                var boneInitMatrix = gameBone.GetObjectTM(0);
                bindPoseInfos[sortedIndex] = (new BonePoseInfo {
                    AbsoluteTransform = boneInitMatrix
                });
            }

            // fix hierarchy an generate animation keys
            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");

            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var gameBone = gameBones[index];
                var parent   = gameBone.NodeParent;
                var babBone  = bones[index];
                if (parent != null)
                {
                    babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID);
                }

                if (babBone.parentBoneIndex == -1)
                {
                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform;
                }
                else
                {
                    var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex];
                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse);
                }

                babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray();

                var babylonAnimation = new BabylonAnimation
                {
                    name           = gameBone.Name + "Animation",
                    property       = "_matrix",
                    dataType       = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior   = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = Loader.Global.FrameRate
                };

                var start = Loader.Core.AnimRange.Start;
                var end   = Loader.Core.AnimRange.End;

                float[] previous = null;
                var     keys     = new List <BabylonAnimationKey>();
                for (var key = start; key <= end; key += Ticks)
                {
                    var      objectTM   = gameBone.GetObjectTM(key);
                    var      parentNode = gameBone.NodeParent;
                    IGMatrix mat;
                    if (parentNode == null || babBone.parentBoneIndex == -1)
                    {
                        mat = objectTM;
                    }
                    else
                    {
                        mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
                    }

                    var current = mat.ToArray();
                    if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current)))
                    {
                        keys.Add(new BabylonAnimationKey
                        {
                            frame  = key / Ticks,
                            values = current
                        });
                    }

                    previous = current;
                }

                babylonAnimation.keys = keys.ToArray();
                babBone.animation     = babylonAnimation;
            }

            babylonSkeleton.needInitialSkinMatrix = true;
            babylonSkeleton.bones = bones.ToArray();

            babylonScene.SkeletonsList.Add(babylonSkeleton);
        }
        private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene)
        {
            var babylonSkeleton = new BabylonSkeleton {
                id = skins.IndexOf(skin)
            };

            babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;

            RaiseMessage(babylonSkeleton.name, 1);

            var skinIndex = skins.IndexOf(skin);

            var bones         = new List <BabylonBone>();
            var gameBones     = new List <IIGameNode>();
            var boneIds       = new List <int>();
            var bindPoseInfos = new List <BonePoseInfo>();

            for (int i = 0; i < skin.TotalSkinBoneCount; ++i)
            {
                bones.Add(null);
                gameBones.Add(null);
                boneIds.Add(-1);
                bindPoseInfos.Add(null);
            }
            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var gameBone = skin.GetIGameBone(index, false);

                var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID);

                gameBones[sortedIndex] = (gameBone);
                boneIds[sortedIndex]   = (gameBone.NodeID);
                bones[sortedIndex]     = (new BabylonBone {
                    index = sortedIndex, name = gameBone.Name
                });

                var boneInitMatrix = gameBone.GetObjectTM(0);
                bindPoseInfos[sortedIndex] = (new BonePoseInfo {
                    AbsoluteTransform = boneInitMatrix
                });
            }

            // fix hierarchy and generate animation keys
            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
            {
                var gameBone = gameBones[index];
                var parent   = gameBone.NodeParent;
                var babBone  = bones[index];
                if (parent != null)
                {
                    babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID);
                }

                if (babBone.parentBoneIndex == -1)
                {
                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform;
                }
                else
                {
                    var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex];
                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse);
                }

                babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray();

                var babylonAnimation = ExportMatrixAnimation("_matrix", key =>
                {
                    var objectTM   = gameBone.GetObjectTM(key);
                    var parentNode = gameBone.NodeParent;
                    IGMatrix mat;
                    if (parentNode == null || babBone.parentBoneIndex == -1)
                    {
                        mat = objectTM;
                    }
                    else
                    {
                        mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
                    }
                    return(mat.ToArray());
                },
                                                             false); // Do not remove linear animation keys for bones

                if (babylonAnimation != null)
                {
                    babylonAnimation.name = gameBone.Name + "Animation"; // override default animation name
                    babBone.animation     = babylonAnimation;
                }
            }

            babylonSkeleton.needInitialSkinMatrix = true;
            babylonSkeleton.bones = bones.ToArray();

            babylonScene.SkeletonsList.Add(babylonSkeleton);
        }