Exemple #1
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);
        }
        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);
        }
Exemple #3
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);
        }