Exemplo n.º 1
0
        /// <summary>
        /// Extract ordered indices on a triangle basis
        /// Extract position and normal of each vertex per face
        /// </summary>
        /// <param name="mFnMesh"></param>
        /// <param name="vertices"></param>
        /// <param name="indices"></param>
        /// <param name="subMeshes"></param>
        /// <param name="optimizeVertices"></param>
        private void ExtractGeometry(MFnMesh mFnMesh, List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, bool optimizeVertices)
        {
            // TODO - Multimaterials: create a BabylonSubMesh per submaterial
            // TODO - optimizeVertices
            MIntArray triangleCounts    = new MIntArray();
            MIntArray trianglesVertices = new MIntArray();

            mFnMesh.getTriangles(triangleCounts, trianglesVertices);

            // For each polygon of this mesh
            for (int polygonId = 0; polygonId < mFnMesh.numPolygons; polygonId++)
            {
                MIntArray verticesId  = new MIntArray();
                int       nbTriangles = triangleCounts[polygonId];

                // For each triangle of this polygon
                for (int triangleIndex = 0; triangleIndex < triangleCounts[polygonId]; triangleIndex++)
                {
                    int[] triangleVertices = new int[3];
                    mFnMesh.getPolygonTriangleVertices(polygonId, triangleIndex, triangleVertices);

                    // Inverse winding order
                    var tmp = triangleVertices[1];
                    triangleVertices[1] = triangleVertices[2];
                    triangleVertices[2] = tmp;

                    // For each vertex of this triangle (3 vertices per triangle)
                    foreach (int vertexId in triangleVertices)
                    {
                        MPoint point = new MPoint();
                        mFnMesh.getPoint(vertexId, point);

                        MVector normal = new MVector();
                        mFnMesh.getFaceVertexNormal(polygonId, vertexId, normal);

                        var vertex = new GlobalVertex
                        {
                            BaseIndex = vertexId,
                            Position  = point.toArray(),
                            Normal    = normal.toArray()
                        };

                        indices.Add(vertices.Count);
                        vertices.Add(vertex);
                    }
                }
            }

            // BabylonSubMesh
            var subMesh = new BabylonSubMesh {
                indexStart = 0, materialIndex = 0
            };

            subMeshes.Add(subMesh);

            subMesh.indexCount    = indices.Count;
            subMesh.verticesStart = 0;
            subMesh.verticesCount = vertices.Count;
        }
Exemplo n.º 2
0
        private void SetBabylonMaterial(BabylonMesh babylonMesh, BabylonSubMesh babylonSubMesh, GLTFMeshPrimitive meshPrimitive)
        {
            // Retreive the babylon material
            BabylonMaterial babylonMaterial;
            var             babylonMaterialId = babylonMesh.materialId;
            // From multi materials first, if any
            // Loop recursively even though it shouldn't be a real use case
            var babylonMultiMaterials = new List <BabylonMultiMaterial>(babylonScene.multiMaterials);
            BabylonMultiMaterial babylonMultiMaterial;

            do
            {
                babylonMultiMaterial = babylonMultiMaterials.Find(_babylonMultiMaterial => _babylonMultiMaterial.id == babylonMaterialId);
                if (babylonMultiMaterial != null)
                {
                    babylonMaterialId = babylonMultiMaterial.materials[babylonSubMesh.materialIndex];
                }
            }while (babylonMultiMaterial != null);
            // Then from materials
            var babylonMaterials = new List <BabylonMaterial>(babylonScene.materials);

            babylonMaterial = babylonMaterials.Find(_babylonMaterial => _babylonMaterial.id == babylonMaterialId);

            meshPrimitive.mode = GLTFMeshPrimitive.FillMode.TRIANGLES;

            // If babylon material was exported successfully
            if (babylonMaterial != null)
            {
                // Update primitive material index
                var indexMaterial = babylonMaterialsToExport.FindIndex(_babylonMaterial => _babylonMaterial == babylonMaterial);
                if (indexMaterial == -1)
                {
                    // Store material for exportation
                    indexMaterial = babylonMaterialsToExport.Count;
                    babylonMaterialsToExport.Add(babylonMaterial);
                }
                meshPrimitive.material = indexMaterial;

                // TODO - Add and retreive info from babylon material
                if (babylonMaterial.wireframe)
                {
                    meshPrimitive.mode = GLTFMeshPrimitive.FillMode.LINE_STRIP;
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Extract ordered indices on a triangle basis
        /// Extract position and normal of each vertex per face
        /// </summary>
        /// <param name="mFnMesh"></param>
        /// <param name="vertices"></param>
        /// <param name="indices"></param>
        /// <param name="subMeshes"></param>
        /// <param name="uvSetNames"></param>
        /// <param name="isUVExportSuccess"></param>
        /// <param name="optimizeVertices"></param>
        private void ExtractGeometry(MFnMesh mFnMesh, List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, MStringArray uvSetNames, ref bool[] isUVExportSuccess, bool optimizeVertices)
        {
            // TODO - optimizeVertices
            MIntArray triangleCounts    = new MIntArray();
            MIntArray trianglesVertices = new MIntArray();

            mFnMesh.getTriangles(triangleCounts, trianglesVertices);

            MObjectArray shaders        = new MObjectArray();
            MIntArray    faceMatIndices = new MIntArray(); // given a face index => get a shader index

            mFnMesh.getConnectedShaders(0, shaders, faceMatIndices);

            // Export geometry even if an error occured with shaders
            // This is a fix for Maya test files
            // TODO - Find the reason why shaders.count = 0
            int  nbShaders   = Math.Max(1, shaders.Count);
            bool checkShader = nbShaders == shaders.Count;

            RaiseVerbose("shaders.Count=" + shaders.Count, 2);

            // For each material of this mesh
            for (int indexShader = 0; indexShader < nbShaders; indexShader++)
            {
                var nbIndicesSubMesh      = 0;
                var minVertexIndexSubMesh = int.MaxValue;
                var maxVertexIndexSubMesh = int.MinValue;
                var subMesh = new BabylonSubMesh {
                    indexStart = indices.Count, materialIndex = indexShader
                };

                // For each polygon of this mesh
                for (int polygonId = 0; polygonId < faceMatIndices.Count; polygonId++)
                {
                    if (checkShader && faceMatIndices[polygonId] != indexShader)
                    {
                        continue;
                    }

                    // The object-relative (mesh-relative/global) vertex indices for this face
                    MIntArray polygonVertices = new MIntArray();
                    mFnMesh.getPolygonVertices(polygonId, polygonVertices);

                    // For each triangle of this polygon
                    for (int triangleId = 0; triangleId < triangleCounts[polygonId]; triangleId++)
                    {
                        int[] polygonTriangleVertices = new int[3];
                        mFnMesh.getPolygonTriangleVertices(polygonId, triangleId, polygonTriangleVertices);

                        /*
                         * Switch coordinate system at global level
                         *
                         * Piece of code kept just in case
                         * See BabylonExporter for more information
                         */
                        //// Inverse winding order to flip faces
                        //var tmp = triangleVertices[1];
                        //triangleVertices[1] = triangleVertices[2];
                        //triangleVertices[2] = tmp;

                        // For each vertex of this triangle (3 vertices per triangle)
                        foreach (int vertexIndexGlobal in polygonTriangleVertices)
                        {
                            // Get the face-relative (local) vertex id
                            int vertexIndexLocal = 0;
                            for (vertexIndexLocal = 0; vertexIndexLocal < polygonVertices.Count; vertexIndexLocal++)
                            {
                                if (polygonVertices[vertexIndexLocal] == vertexIndexGlobal)
                                {
                                    break;
                                }
                            }

                            GlobalVertex vertex = ExtractVertex(mFnMesh, polygonId, vertexIndexGlobal, vertexIndexLocal, uvSetNames, ref isUVExportSuccess);
                            vertex.CurrentIndex = vertices.Count;

                            indices.Add(vertex.CurrentIndex);
                            vertices.Add(vertex);

                            minVertexIndexSubMesh = Math.Min(minVertexIndexSubMesh, vertex.CurrentIndex);
                            maxVertexIndexSubMesh = Math.Max(maxVertexIndexSubMesh, vertex.CurrentIndex);
                            nbIndicesSubMesh++;
                        }
                    }
                }

                if (nbIndicesSubMesh != 0)
                {
                    subMesh.indexCount    = nbIndicesSubMesh;
                    subMesh.verticesStart = minVertexIndexSubMesh;
                    subMesh.verticesCount = maxVertexIndexSubMesh - minVertexIndexSubMesh + 1;

                    subMeshes.Add(subMesh);
                }
            }
        }
Exemplo n.º 4
0
        private void ExtractGeometry(List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, List <int> boneIds, IIGameSkin skin, IIGameMesh unskinnedMesh, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, bool optimizeVertices, int multiMatsCount, IIGameNode meshNode)
        {
            List <GlobalVertex>[] verticesAlreadyExported = null;

            if (optimizeVertices)
            {
                verticesAlreadyExported = new List <GlobalVertex> [unskinnedMesh.NumberOfVerts];
            }

            var indexStart = 0;


            for (int i = 0; i < multiMatsCount; ++i)
            {
                int materialId     = meshNode.NodeMaterial?.GetMaterialID(i) ?? 0;
                var indexCount     = 0;
                var minVertexIndex = int.MaxValue;
                var maxVertexIndex = int.MinValue;
                var subMesh        = new BabylonSubMesh {
                    indexStart = indexStart, materialIndex = i
                };

                if (multiMatsCount == 1)
                {
                    for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                    {
                        var face = unskinnedMesh.GetFace(j);
                        ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                    }
                }
                else
                {
                    ITab <IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
                    for (int j = 0; j < materialFaces.Count; ++j)
                    {
#if MAX2017
                        var faceIndexer = j;
#else
                        var faceIndexer = new IntPtr(j);
#endif
                        var face = materialFaces[faceIndexer];

#if !MAX2017
                        Marshal.FreeHGlobal(faceIndexer);
#endif
                        ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                    }
                }

                if (indexCount != 0)
                {
                    subMesh.indexCount    = indexCount;
                    subMesh.verticesStart = minVertexIndex;
                    subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                    indexStart += indexCount;

                    subMeshes.Add(subMesh);
                }
            }
        }
        private void _exportMorphTargets(BabylonMesh babylonMesh, BabylonSubMesh babylonSubMesh, BabylonMorphTargetManager babylonMorphTargetManager, GLTF gltf, GLTFBuffer buffer, GLTFMeshPrimitive meshPrimitive)
        {
            var gltfMorphTargets = new List <GLTFMorphTarget>();

            foreach (var babylonMorphTarget in babylonMorphTargetManager.targets)
            {
                var gltfMorphTarget = new GLTFMorphTarget();

                // Positions
                if (babylonMorphTarget.positions != null)
                {
                    var accessorTargetPositions = GLTFBufferService.Instance.CreateAccessor(
                        gltf,
                        GLTFBufferService.Instance.GetBufferViewFloatVec3(gltf, buffer),
                        "accessorTargetPositions",
                        GLTFAccessor.ComponentType.FLOAT,
                        GLTFAccessor.TypeEnum.VEC3
                        );
                    gltfMorphTarget.Add(GLTFMorphTarget.Attribute.POSITION.ToString(), accessorTargetPositions.index);
                    // Populate accessor
                    int nbComponents = 3; // Vector3
                    int startIndex   = babylonSubMesh.verticesStart * nbComponents;
                    int endIndex     = startIndex + babylonSubMesh.verticesCount * nbComponents;
                    accessorTargetPositions.min = new float[] { float.MaxValue, float.MaxValue, float.MaxValue };
                    accessorTargetPositions.max = new float[] { float.MinValue, float.MinValue, float.MinValue };
                    for (int indexPosition = startIndex; indexPosition < endIndex; indexPosition += 3)
                    {
                        var positionTarget = Tools.SubArray(babylonMorphTarget.positions, indexPosition, 3);


                        // Babylon stores morph target information as final data while glTF expects deltas from mesh primitive
                        var positionMesh = Tools.SubArray(babylonMesh.positions, indexPosition, 3);
                        for (int indexCoordinate = 0; indexCoordinate < positionTarget.Length; indexCoordinate++)
                        {
                            positionTarget[indexCoordinate] = positionTarget[indexCoordinate] - positionMesh[indexCoordinate];
                        }
                        positionTarget[2] *= -1;
                        // Store values as bytes
                        foreach (var coordinate in positionTarget)
                        {
                            accessorTargetPositions.bytesList.AddRange(BitConverter.GetBytes(coordinate));
                        }
                        // Update min and max values
                        GLTFBufferService.UpdateMinMaxAccessor(accessorTargetPositions, positionTarget);
                    }
                    accessorTargetPositions.count = babylonSubMesh.verticesCount;
                }

                // Normals
                if ((babylonMorphTarget.normals != null) && _exportMorphNormal)
                {
                    var accessorTargetNormals = GLTFBufferService.Instance.CreateAccessor(
                        gltf,
                        GLTFBufferService.Instance.GetBufferViewFloatVec3(gltf, buffer),
                        "accessorTargetNormals",
                        GLTFAccessor.ComponentType.FLOAT,
                        GLTFAccessor.TypeEnum.VEC3
                        );
                    gltfMorphTarget.Add(GLTFMorphTarget.Attribute.NORMAL.ToString(), accessorTargetNormals.index);
                    // Populate accessor
                    int nbComponents = 3; // Vector3
                    int startIndex   = babylonSubMesh.verticesStart * nbComponents;
                    int endIndex     = startIndex + babylonSubMesh.verticesCount * nbComponents;
                    for (int indexNormal = startIndex; indexNormal < endIndex; indexNormal += 3)
                    {
                        var normalTarget = Tools.SubArray(babylonMorphTarget.normals, indexNormal, 3);

                        // Babylon stores morph target information as final data while glTF expects deltas from mesh primitive
                        var normalMesh = Tools.SubArray(babylonMesh.normals, indexNormal, 3);
                        for (int indexCoordinate = 0; indexCoordinate < normalTarget.Length; indexCoordinate++)
                        {
                            normalTarget[indexCoordinate] = normalTarget[indexCoordinate] - normalMesh[indexCoordinate];
                        }
                        normalTarget[2] *= -1;
                        // Store values as bytes
                        foreach (var coordinate in normalTarget)
                        {
                            accessorTargetNormals.bytesList.AddRange(BitConverter.GetBytes(coordinate));
                        }
                    }
                    accessorTargetNormals.count = babylonSubMesh.verticesCount;
                }

                // Tangents
                if ((babylonMorphTarget.tangents != null) && _exportMorphTangent)
                {
                    var accessorTargetTangents = GLTFBufferService.Instance.CreateAccessor(
                        gltf,
                        GLTFBufferService.Instance.GetBufferViewFloatVec3(gltf, buffer),
                        "accessorTargetTangents",
                        GLTFAccessor.ComponentType.FLOAT,
                        GLTFAccessor.TypeEnum.VEC3
                        );
                    gltfMorphTarget.Add(GLTFMeshPrimitive.Attribute.TANGENT.ToString(), accessorTargetTangents.index);
                    // Populate accessor
                    // Note that the w component for handedness is omitted when targeting TANGENT data since handedness cannot be displaced.
                    int nbComponents = 4; // Vector4
                    int startIndex   = babylonSubMesh.verticesStart * nbComponents;
                    int endIndex     = startIndex + babylonSubMesh.verticesCount * nbComponents;
                    for (int indexTangent = startIndex; indexTangent < endIndex; indexTangent += 4)
                    {
                        var tangentTarget = Tools.SubArray(babylonMorphTarget.tangents, indexTangent, 3);

                        // Babylon stores morph target information as final data while glTF expects deltas from mesh primitive
                        var tangentMesh = Tools.SubArray(babylonMesh.tangents, indexTangent, 3);
                        for (int indexCoordinate = 0; indexCoordinate < tangentTarget.Length; indexCoordinate++)
                        {
                            tangentTarget[indexCoordinate] = tangentTarget[indexCoordinate] - tangentMesh[indexCoordinate];
                        }
                        tangentTarget[2] *= -1;
                        // Store values as bytes
                        foreach (var coordinate in tangentTarget)
                        {
                            accessorTargetTangents.bytesList.AddRange(BitConverter.GetBytes(coordinate));
                        }
                    }
                    accessorTargetTangents.count = babylonSubMesh.verticesCount;
                }
                gltfMorphTargets.Add(gltfMorphTarget);
            }
            if (gltfMorphTargets.Count > 0)
            {
                meshPrimitive.targets = gltfMorphTargets.ToArray();
            }
        }
Exemplo n.º 6
0
        private void ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
        {
            if (meshNode.MaxNode.IsInstance())
            {
                return;
            }

            if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            if (!ExportHiddenObjects && meshNode.MaxNode.IsHidden(NodeHideFlags.None, false))
            {
                return;
            }

            var  gameMesh    = meshNode.IGameObject.AsGameMesh();
            bool initialized = gameMesh.InitializeData; //needed, the property is in fact a method initializing the exporter that has wrongly been auto
            // translated into a property because it has no parameters

            var babylonMesh = new BabylonMesh {
                name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString()
            };

            if (meshNode.NodeParent != null)
            {
                babylonMesh.parentId = GetParentID(meshNode.NodeParent, babylonScene, scene);
            }

            // Sounds
            var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", "");

            if (!string.IsNullOrEmpty(soundName))
            {
                var filename = Path.GetFileName(soundName);

                var meshSound = new BabylonSound
                {
                    name            = filename,
                    autoplay        = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_autoplay", 1),
                    loop            = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_loop", 1),
                    volume          = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_volume", 1.0f),
                    playbackRate    = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_playbackrate", 1.0f),
                    connectedMeshId = babylonMesh.id,
                    isDirectional   = false,
                    spatialSound    = false,
                    distanceModel   = meshNode.MaxNode.GetStringProperty("babylonjs_sound_distancemodel", "linear"),
                    maxDistance     = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_maxdistance", 100f),
                    rolloffFactor   = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_rolloff", 1.0f),
                    refDistance     = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_refdistance", 1.0f),
                };

                var isDirectional = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_directional");

                if (isDirectional)
                {
                    meshSound.isDirectional  = true;
                    meshSound.coneInnerAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneinnerangle", 360f);
                    meshSound.coneOuterAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneouterangle", 360f);
                    meshSound.coneOuterGain  = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneoutergain", 1.0f);
                }

                babylonScene.SoundsList.Add(meshSound);

                try
                {
                    File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true);
                }
                catch
                {
                }
            }

            // Misc.
#if MAX2017
            babylonMesh.isVisible      = meshNode.MaxNode.Renderable;
            babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows;
            babylonMesh.applyFog       = meshNode.MaxNode.ApplyAtmospherics;
#else
            babylonMesh.isVisible      = meshNode.MaxNode.Renderable == 1;
            babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1;
            babylonMesh.applyFog       = meshNode.MaxNode.ApplyAtmospherics == 1;
#endif
            babylonMesh.pickable                 = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable");
            babylonMesh.showBoundingBox          = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox");
            babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox");
            babylonMesh.alphaIndex               = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000);

            // Actions
            babylonMesh.actions = ExportNodeAction(meshNode);

            // Collisions
            babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions");

            var        isSkinned          = gameMesh.IsObjectSkinned;
            var        skin               = gameMesh.IGameSkin;
            var        unskinnedMesh      = gameMesh;
            IGMatrix   skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true));
            List <int> boneIds            = null;
            int        maxNbBones         = 0;
            if (isSkinned)
            {
                bonesCount = skin.TotalSkinBoneCount;
                skins.Add(skin);

                skinnedNodes.Add(meshNode);
                babylonMesh.skeletonId = skins.IndexOf(skin);
                skin.GetInitSkinTM(skinInitPoseMatrix);
                boneIds = SortBones(skin);
                skinSortedBones[skin] = boneIds;
            }

            // Position / rotation / scaling
            var localTM = meshNode.GetObjectTM(0);
            if (meshNode.NodeParent != null)
            {
                var parentWorld = meshNode.NodeParent.GetObjectTM(0);
                localTM.MultiplyBy(parentWorld.Inverse);
            }

            var meshTrans         = localTM.Translation;
            var meshRotation      = localTM.Rotation;
            var meshScale         = localTM.Scaling;
            var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions");

            babylonMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z };

            if (exportQuaternions)
            {
                babylonMesh.rotationQuaternion = new[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W };
            }
            else
            {
                RotationToEulerAngles(babylonMesh, meshRotation);
            }

            babylonMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z };

            // Mesh
            RaiseMessage(meshNode.Name, 1);

            if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null)
            {
                if (unskinnedMesh.NumberOfFaces < 1)
                {
                    RaiseError($"Mesh {babylonMesh.name} has no face", 2);
                }

                if (unskinnedMesh.NumberOfVerts < 3)
                {
                    RaiseError($"Mesh {babylonMesh.name} has not enough vertices", 2);
                }

                if (unskinnedMesh.NumberOfVerts >= 65536)
                {
                    RaiseWarning($"Mesh {babylonMesh.name} has tmore than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", 2);
                }

                if (skin != null)
                {
                    for (var vertexIndex = 0; vertexIndex < unskinnedMesh.NumberOfVerts; vertexIndex++)
                    {
                        maxNbBones = Math.Max(maxNbBones, skin.GetNumberOfBones(vertexIndex));
                    }
                }

                // Physics
                var impostorText = meshNode.MaxNode.GetStringProperty("babylonjs_impostor", "None");

                if (impostorText != "None")
                {
                    switch (impostorText)
                    {
                    case "Sphere":
                        babylonMesh.physicsImpostor = 1;
                        break;

                    case "Box":
                        babylonMesh.physicsImpostor = 2;
                        break;

                    case "Plane":
                        babylonMesh.physicsImpostor = 3;
                        break;

                    default:
                        babylonMesh.physicsImpostor = 0;
                        break;
                    }

                    babylonMesh.physicsMass        = meshNode.MaxNode.GetFloatProperty("babylonjs_mass");
                    babylonMesh.physicsFriction    = meshNode.MaxNode.GetFloatProperty("babylonjs_friction", 0.2f);
                    babylonMesh.physicsRestitution = meshNode.MaxNode.GetFloatProperty("babylonjs_restitution", 0.2f);
                }

                // Material
                var mtl            = meshNode.NodeMaterial;
                var multiMatsCount = 1;

                if (mtl != null)
                {
                    babylonMesh.materialId = mtl.MaxMaterial.GetGuid().ToString();

                    if (!referencedMaterials.Contains(mtl))
                    {
                        referencedMaterials.Add(mtl);
                    }

                    multiMatsCount = Math.Max(mtl.SubMaterialCount, 1);
                }

                babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever);

                var  vertices        = new List <GlobalVertex>();
                var  indices         = new List <int>();
                var  mappingChannels = unskinnedMesh.ActiveMapChannelNum;
                bool hasUV           = false;
                bool hasUV2          = false;
                for (int i = 0; i < mappingChannels.Count; ++i)
                {
#if MAX2017
                    var indexer = i;
#else
                    var indexer = new IntPtr(i);
#endif
                    var channelNum = mappingChannels[indexer];
                    if (channelNum == 1)
                    {
                        hasUV = true;
                    }
                    else if (channelNum == 2)
                    {
                        hasUV2 = true;
                    }
                }
                var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
                var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;

                var optimizeVertices = meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices");

                // Compute normals
                List <GlobalVertex>[] verticesAlreadyExported = null;

                if (optimizeVertices)
                {
                    verticesAlreadyExported = new List <GlobalVertex> [unskinnedMesh.NumberOfVerts];
                }

                var subMeshes  = new List <BabylonSubMesh>();
                var indexStart = 0;


                for (int i = 0; i < multiMatsCount; ++i)
                {
                    int materialId     = meshNode.NodeMaterial?.GetMaterialID(i) ?? 0;
                    var indexCount     = 0;
                    var minVertexIndex = int.MaxValue;
                    var maxVertexIndex = int.MinValue;
                    var subMesh        = new BabylonSubMesh {
                        indexStart = indexStart, materialIndex = i
                    };

                    if (multiMatsCount == 1)
                    {
                        for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                        {
                            var face = unskinnedMesh.GetFace(j);
                            ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                        }
                    }
                    else
                    {
                        ITab <IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
                        for (int j = 0; j < materialFaces.Count; ++j)
                        {
#if MAX2017
                            var faceIndexer = j;
#else
                            var faceIndexer = new IntPtr(j);
#endif
                            var face = materialFaces[faceIndexer];

#if !MAX2017
                            Marshal.FreeHGlobal(faceIndexer);
#endif
                            ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                        }
                    }

                    if (indexCount != 0)
                    {
                        subMesh.indexCount    = indexCount;
                        subMesh.verticesStart = minVertexIndex;
                        subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                        indexStart += indexCount;

                        subMeshes.Add(subMesh);
                    }
                }

                if (vertices.Count >= 65536)
                {
                    RaiseWarning($"Mesh {babylonMesh.name} has {vertices.Count} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 2);

                    if (!optimizeVertices)
                    {
                        RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2);
                    }
                }

                RaiseMessage($"{vertices.Count} vertices, {indices.Count/3} faces", 2);

                // Buffers
                babylonMesh.positions = vertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray();
                babylonMesh.normals   = vertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray();
                if (hasUV)
                {
                    babylonMesh.uvs = vertices.SelectMany(v => new[] { v.UV.X, 1 - v.UV.Y }).ToArray();
                }
                if (hasUV2)
                {
                    babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray();
                }

                if (skin != null)
                {
                    babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
                    babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();

                    babylonMesh.numBoneInfluencers = maxNbBones;
                    if (maxNbBones > 4)
                    {
                        babylonMesh.matricesWeightsExtra = vertices.SelectMany(v => v.WeightsExtra != null ? v.WeightsExtra.ToArray() : new[] { 0.0f, 0.0f, 0.0f, 0.0f }).ToArray();
                        babylonMesh.matricesIndicesExtra = vertices.Select(v => v.BonesIndicesExtra).ToArray();
                    }
                }

                if (hasColor)
                {
                    babylonMesh.colors         = vertices.SelectMany(v => v.Color.ToArray()).ToArray();
                    babylonMesh.hasVertexAlpha = hasAlpha;
                }

                babylonMesh.subMeshes = subMeshes.ToArray();

                // Buffers - Indices
                babylonMesh.indices = indices.ToArray();
            }

            // Instances
            var tabs = Loader.Global.NodeTab.Create();

            Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs);
            var instances = new List <BabylonAbstractMesh>();

            for (var index = 0; index < tabs.Count; index++)
            {
#if MAX2017
                var indexer = index;
#else
                var indexer = new IntPtr(index);
#endif
                var tab = tabs[indexer];

#if !MAX2017
                Marshal.FreeHGlobal(indexer);
#endif

                if (meshNode.MaxNode.GetGuid() == tab.GetGuid())
                {
                    continue;
                }
                var instanceGameNode = scene.GetIGameNode(tab);
                if (instanceGameNode == null)
                {
                    continue;
                }
                tab.MarkAsInstance();

                var instance = new BabylonAbstractMesh {
                    name = tab.Name
                };
                {
                    var instanceLocalTM = instanceGameNode.GetObjectTM(0);

                    var instanceTrans    = instanceLocalTM.Translation;
                    var instanceRotation = instanceLocalTM.Rotation;
                    var instanceScale    = instanceLocalTM.Scaling;

                    instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };

                    if (exportQuaternions)
                    {
                        instance.rotationQuaternion = new[] { instanceRotation.X, instanceRotation.Y, instanceRotation.Z, -instanceRotation.W };
                    }
                    else
                    {
                        RotationToEulerAngles(instance, instanceRotation);
                    }

                    instance.scaling = new[] { instanceScale.X, instanceScale.Y, instanceScale.Z };
                }
                var instanceAnimations = new List <BabylonAnimation>();
                GenerateCoordinatesAnimations(meshNode, instanceAnimations);
                instance.animations = instanceAnimations.ToArray();

                instances.Add(instance);
            }

            babylonMesh.instances = instances.ToArray();

            // Animations
            var animations = new List <BabylonAnimation>();

            GenerateCoordinatesAnimations(meshNode, animations);

            if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations))
            {
                ExportFloatAnimation("visibility", animations, key => new[] { meshNode.MaxNode.GetVisibility(key, Tools.Forever) });
            }

            babylonMesh.animations = animations.ToArray();

            if (meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimate", 1))
            {
                babylonMesh.autoAnimate     = true;
                babylonMesh.autoAnimateFrom = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
                babylonMesh.autoAnimateTo   = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to", 100);
                babylonMesh.autoAnimateLoop = meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop", 1);
            }

            babylonScene.MeshesList.Add(babylonMesh);
        }
Exemplo n.º 7
0
        void DumpObject(NovaObject novaObject, BabylonScene babylonScene, NovaScene scene, int startIndex, int endIndex, string nameIndex = "")
        {
            var babylonMesh = new BabylonMesh();
            babylonScene.MeshesList.Add(babylonMesh);

            babylonMesh.name = novaObject.Name + nameIndex;
            babylonMesh.id = novaObject.ID.ToString();
            babylonMesh.materialId = novaObject.Material == null ? "" : novaObject.Material.ID.ToString();
            babylonMesh.parentId = novaObject.ParentEntity == null ? "" : novaObject.ParentEntity.ID.ToString();
            babylonMesh.isEnabled = novaObject.Enabled;
            babylonMesh.isVisible = novaObject.Renderable;
            babylonMesh.visibility = novaObject.Visibility;
            babylonMesh.checkCollisions = novaObject.CheckCollisions;
            babylonMesh.receiveShadows = novaObject.ReceiveShadows;
            babylonMesh.infiniteDistance = novaObject.InfiniteDistance;

            if (novaObject.Billboard)
            {
                babylonMesh.billboardMode |= (novaObject.BillboardX ? 1 : 0);
                babylonMesh.billboardMode |= (novaObject.BillboardY ? 2 : 0);
                babylonMesh.billboardMode |= (novaObject.BillboardZ ? 4 : 0);
            }

            if (novaObject.ParticleSystem != null)
            {
                particleSystemsToExport.Add(novaObject.ParticleSystem);
            }

            // Mirror
            if (novaObject.IsMirror && novaObject.Material != null)
            {
                mirrorsMaterials.Add(novaObject.Material, novaObject);
            }

            // World
            babylonMesh.position = novaObject.Position.ToArray();
            babylonMesh.rotation = novaObject.Rotation.ToArray();
            babylonMesh.localMatrix = (Matrix.Scaling(novaObject.Scaling) * novaObject.LocalMatrix).ToArray();

            // Animations
            var animations = new List<BabylonAnimation>();

            DumpInterpolator("Visibility animation", "visibility", novaObject.VisibilityInterpolator, scene, animations);

            // Position
            if (!DumpInterpolator("Position animation", "position", novaObject.PositionInterpolator, scene, animations))
            {
                DumpInterpolator("PositionX animation", "position.x", novaObject.PositionXInterpolator, scene, animations);
                DumpInterpolator("PositionY animation", "position.y", novaObject.PositionYInterpolator, scene, animations);
                DumpInterpolator("PositionZ animation", "position.z", novaObject.PositionZInterpolator, scene, animations);
            }

            // Rotation
            if (!DumpInterpolator("Rotation animation", "rotationQuaternion", novaObject.RotationInterpolator, scene, animations))
            {
                DumpInterpolator("RotationX animation", "rotation.x", novaObject.RotationXInterpolator, scene,
                    animations, -novaObject.Determinant);
                DumpInterpolator("RotationY animation", "rotation.y", novaObject.RotationYInterpolator, scene,
                    animations, -novaObject.Determinant);
                DumpInterpolator("RotationZ animation", "rotation.z", novaObject.RotationZInterpolator, scene,
                    animations, -novaObject.Determinant);
            }
            else
            {
                babylonMesh.localMatrix = Matrix.Identity.ToArray();
                babylonMesh.scaling = novaObject.Scaling.ToArray();
            }

            // Scaling
            if (!DumpInterpolator("Scaling animation", "scaling", novaObject.ScalingInterpolator, scene, animations))
            {
                DumpInterpolator("ScalingX animation", "scaling.x", novaObject.ScalingXInterpolator, scene, animations);
                DumpInterpolator("ScalingY animation", "scaling.y", novaObject.ScalingYInterpolator, scene, animations);
                DumpInterpolator("ScalingZ animation", "scaling.z", novaObject.ScalingZInterpolator, scene, animations);
            }
            else
            {
                babylonMesh.localMatrix = novaObject.LocalMatrix.ToArray();
                babylonMesh.scaling = novaObject.Scaling.ToArray();
            }

            babylonMesh.animations = animations.ToArray();
            babylonMesh.autoAnimate = novaObject.AutoAnimate;

            if (novaObject.AutoAnimate)
            {
                babylonMesh.autoAnimateFrom = novaObject.AnimationStartKey;
                if (novaObject.AnimationEndKey == -1)
                {
                    babylonMesh.autoAnimateTo = scene.AnimationKeyMax / scene.AnimationKeyStep;
                    babylonMesh.autoAnimateLoop = true;
                }
                else
                {
                    babylonMesh.autoAnimateTo = novaObject.AnimationEndKey;
                }
            }

            // Vertices & faces
            var exportedVerticesCount = DumpObjectGeometry(novaObject, babylonMesh, startIndex, endIndex);

            // Subobjects
            var subMeshes = new List<BabylonSubMesh>();

            if (novaObject.Is32bits)
            {
                var subMesh = new BabylonSubMesh();
                subMesh.materialIndex = 0;
                subMesh.verticesStart = 0;
                subMesh.verticesCount = exportedVerticesCount;
                subMesh.indexStart = 0;
                subMesh.indexCount = babylonMesh.indices.Length;

                subMeshes.Add(subMesh);
            }
            else
            {
                foreach (NovaSubObject subObject in novaObject.SubObjects)
                {
                    var subMesh = new BabylonSubMesh();
                    subMesh.materialIndex = subObject.AttributeRange.AttributeId;
                    subMesh.verticesStart = subObject.AttributeRange.VertexStart;
                    subMesh.verticesCount = subObject.AttributeRange.VertexCount;
                    subMesh.indexStart = subObject.AttributeRange.FaceStart * 3;
                    subMesh.indexCount = subObject.AttributeRange.FaceCount * 3;

                    subMeshes.Add(subMesh);
                }
            }
            babylonMesh.subMeshes = subMeshes.ToArray();

            if (novaObject.Material != null)
            {
                if (!materialsToExport.Contains(novaObject.Material))
                {
                    materialsToExport.Add(novaObject.Material);
                    var multiMat = novaObject.Material as NovaMultiMaterial;

                    if (multiMat != null)
                    {
                        foreach (var mat in multiMat.Materials)
                        {
                            if (!materialsToExport.Contains(mat))
                            {
                                materialsToExport.Add(mat);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 8
0
        void DumpObject(NovaObject novaObject, BabylonScene babylonScene, NovaScene scene, int startIndex, int endIndex, string nameIndex = "")
        {
            var babylonMesh = new BabylonMesh();

            babylonScene.MeshesList.Add(babylonMesh);

            babylonMesh.name            = novaObject.Name + nameIndex;
            babylonMesh.id              = novaObject.ID.ToString();
            babylonMesh.materialId      = novaObject.Material == null ? "" : novaObject.Material.ID.ToString();
            babylonMesh.parentId        = novaObject.ParentEntity == null ? "" : novaObject.ParentEntity.ID.ToString();
            babylonMesh.isEnabled       = novaObject.Enabled;
            babylonMesh.isVisible       = novaObject.Renderable;
            babylonMesh.visibility      = novaObject.Visibility;
            babylonMesh.checkCollisions = novaObject.CheckCollisions;
            babylonMesh.receiveShadows  = novaObject.ReceiveShadows;

            if (novaObject.Billboard)
            {
                babylonMesh.billboardMode |= (novaObject.BillboardX ? 1 : 0);
                babylonMesh.billboardMode |= (novaObject.BillboardY ? 2 : 0);
                babylonMesh.billboardMode |= (novaObject.BillboardZ ? 4 : 0);
            }

            if (novaObject.ParticleSystem != null)
            {
                particleSystemsToExport.Add(novaObject.ParticleSystem);
            }

            // Mirror
            if (novaObject.IsMirror && novaObject.Material != null)
            {
                mirrorsMaterials.Add(novaObject.Material, novaObject);
            }

            // World
            babylonMesh.position    = novaObject.Position.ToArray();
            babylonMesh.rotation    = novaObject.Rotation.ToArray();
            babylonMesh.localMatrix = (Matrix.Scaling(novaObject.Scaling) * novaObject.LocalMatrix).ToArray();

            // Animations
            var animations = new List <BabylonAnimation>();

            DumpInterpolator("Visibility animation", "visibility", novaObject.VisibilityInterpolator, scene, animations);

            // Position
            if (!DumpInterpolator("Position animation", "position", novaObject.PositionInterpolator, scene, animations))
            {
                DumpInterpolator("PositionX animation", "position.x", novaObject.PositionXInterpolator, scene, animations);
                DumpInterpolator("PositionY animation", "position.y", novaObject.PositionYInterpolator, scene, animations);
                DumpInterpolator("PositionZ animation", "position.z", novaObject.PositionZInterpolator, scene, animations);
            }

            // Rotation
            if (!DumpInterpolator("Rotation animation", "rotationQuaternion", novaObject.RotationInterpolator, scene, animations))
            {
                DumpInterpolator("RotationX animation", "rotation.x", novaObject.RotationXInterpolator, scene,
                                 animations, -novaObject.Determinant);
                DumpInterpolator("RotationY animation", "rotation.y", novaObject.RotationYInterpolator, scene,
                                 animations, -novaObject.Determinant);
                DumpInterpolator("RotationZ animation", "rotation.z", novaObject.RotationZInterpolator, scene,
                                 animations, -novaObject.Determinant);
            }
            else
            {
                babylonMesh.localMatrix = Matrix.Identity.ToArray();
                babylonMesh.scaling     = novaObject.Scaling.ToArray();
            }

            // Scaling
            if (!DumpInterpolator("Scaling animation", "scaling", novaObject.ScalingInterpolator, scene, animations))
            {
                DumpInterpolator("ScalingX animation", "scaling.x", novaObject.ScalingXInterpolator, scene, animations);
                DumpInterpolator("ScalingY animation", "scaling.y", novaObject.ScalingYInterpolator, scene, animations);
                DumpInterpolator("ScalingZ animation", "scaling.z", novaObject.ScalingZInterpolator, scene, animations);
            }
            else
            {
                babylonMesh.localMatrix = novaObject.LocalMatrix.ToArray();
                babylonMesh.scaling     = novaObject.Scaling.ToArray();
            }

            babylonMesh.animations  = animations.ToArray();
            babylonMesh.autoAnimate = novaObject.AutoAnimate;

            if (novaObject.AutoAnimate)
            {
                babylonMesh.autoAnimateFrom = novaObject.AnimationStartKey;
                if (novaObject.AnimationEndKey == -1)
                {
                    babylonMesh.autoAnimateTo   = scene.AnimationKeyMax / scene.AnimationKeyStep;
                    babylonMesh.autoAnimateLoop = true;
                }
                else
                {
                    babylonMesh.autoAnimateTo = novaObject.AnimationEndKey;
                }
            }

            // Vertices & faces
            var exportedVerticesCount = DumpObjectGeometry(novaObject, babylonMesh, startIndex, endIndex);

            // Subobjects
            var subMeshes = new List <BabylonSubMesh>();

            if (novaObject.Is32bits)
            {
                var subMesh = new BabylonSubMesh();
                subMesh.materialIndex = 0;
                subMesh.verticesStart = 0;
                subMesh.verticesCount = exportedVerticesCount;
                subMesh.indexStart    = 0;
                subMesh.indexCount    = babylonMesh.indices.Length;

                subMeshes.Add(subMesh);
            }
            else
            {
                foreach (NovaSubObject subObject in novaObject.SubObjects)
                {
                    var subMesh = new BabylonSubMesh();
                    subMesh.materialIndex = subObject.AttributeRange.AttributeId;
                    subMesh.verticesStart = subObject.AttributeRange.VertexStart;
                    subMesh.verticesCount = subObject.AttributeRange.VertexCount;
                    subMesh.indexStart    = subObject.AttributeRange.FaceStart * 3;
                    subMesh.indexCount    = subObject.AttributeRange.FaceCount * 3;

                    subMeshes.Add(subMesh);
                }
            }
            babylonMesh.subMeshes = subMeshes.ToArray();

            if (novaObject.Material != null)
            {
                if (!materialsToExport.Contains(novaObject.Material))
                {
                    materialsToExport.Add(novaObject.Material);
                    var multiMat = novaObject.Material as NovaMultiMaterial;

                    if (multiMat != null)
                    {
                        foreach (var mat in multiMat.Materials)
                        {
                            if (!materialsToExport.Contains(mat))
                            {
                                materialsToExport.Add(mat);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 9
0
        private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, List <int> boneIds, IIGameSkin skin, IIGameMesh unskinnedMesh, IMatrix3 invertedWorldMatrix, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, bool optimizeVertices, int multiMatsCount, IIGameNode meshNode, ref List <int> faceIndexes)
        {
            List <GlobalVertex>[] verticesAlreadyExported = null;

            if (optimizeVertices)
            {
                verticesAlreadyExported = new List <GlobalVertex> [unskinnedMesh.NumberOfVerts];
            }

            var indexStart = 0;

            // Whether or not to store order in which faces are exported
            // Storage is used when exporting Morph Targets geometry
            // To ensure face order is identical, especially with multimaterials involved
            bool storeFaceIndexes = faceIndexes == null;

            if (storeFaceIndexes)
            {
                faceIndexes = new List <int>();
            }
            int indexInFaceIndexesArray = 0;

            for (int i = 0; i < multiMatsCount; ++i)
            {
                int materialId     = meshNode.NodeMaterial?.GetMaterialID(i) ?? 0;
                var indexCount     = 0;
                var minVertexIndex = int.MaxValue;
                var maxVertexIndex = int.MinValue;
                var subMesh        = new BabylonSubMesh {
                    indexStart = indexStart, materialIndex = i
                };

                if (multiMatsCount == 1)
                {
                    for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                    {
                        IFaceEx face = null;
                        if (storeFaceIndexes)
                        {
                            face = unskinnedMesh.GetFace(j);
                            // Store face index (j = face.MeshFaceIndex)
                            faceIndexes.Add(j);
                        }
                        else
                        {
                            face = unskinnedMesh.GetFace(faceIndexes[indexInFaceIndexesArray++]);
                        }
                        ExtractFace(meshNode, skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                    }
                }
                else
                {
                    ITab <IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
                    for (int j = 0; j < materialFaces.Count; ++j)
                    {
                        IFaceEx face = null;
                        if (storeFaceIndexes)
                        {
                            // Retreive face
#if MAX2017 || MAX2018
                            face = materialFaces[j];
#else
                            face = materialFaces[new IntPtr(j)];
#endif

                            // Store face index
                            faceIndexes.Add(face.MeshFaceIndex);
                        }
                        else
                        {
                            face = unskinnedMesh.GetFace(faceIndexes[indexInFaceIndexesArray++]);
                        }
                        ExtractFace(meshNode, skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                    }
                }

                if (indexCount != 0)
                {
                    subMesh.indexCount    = indexCount;
                    subMesh.verticesStart = minVertexIndex;
                    subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                    indexStart += indexCount;

                    subMeshes.Add(subMesh);
                }
            }
        }
Exemplo n.º 10
0
        private BabylonMesh ExportMesh(Node meshNode, BabylonScene babylonScene)
        {
            var babylonMesh = new BabylonMesh();
            int vx1, vx2, vx3;

            RaiseMessage(meshNode.Name, true);
            babylonMesh.name = meshNode.Name;
            babylonMesh.id   = meshNode.GetGuid().ToString();
            if (meshNode.HasParent())
            {
                babylonMesh.parentId = meshNode.Parent.GetGuid().ToString();
            }

            // Misc.
            babylonMesh.isVisible      = meshNode._Node.Renderable == 1;
            babylonMesh.pickable       = meshNode._Node.GetBoolProperty("babylonjs_checkpickable");
            babylonMesh.receiveShadows = meshNode._Node.RcvShadows == 1;

            // Collisions
            babylonMesh.checkCollisions = meshNode._Node.GetBoolProperty("babylonjs_checkcollisions");

            // Position / rotation / scaling
            var wm = meshNode.GetWorldMatrix(0, meshNode.HasParent());

            babylonMesh.position = wm.Trans.ToArraySwitched();

            var parts = Loader.Global.AffineParts.Create();

            Loader.Global.DecompAffine(wm, parts);

            //var rotate = new float[3];

            //IntPtr xPtr = Marshal.AllocHGlobal(sizeof(float));
            //IntPtr yPtr = Marshal.AllocHGlobal(sizeof(float));
            //IntPtr zPtr = Marshal.AllocHGlobal(sizeof(float));
            //parts.Q.GetEuler(xPtr, yPtr, zPtr);

            //Marshal.Copy(xPtr, rotate, 0, 1);
            //Marshal.Copy(yPtr, rotate, 1, 1);
            //Marshal.Copy(zPtr, rotate, 2, 1);

            //var temp = -rotate[1];
            //rotate[0] = rotate[0] * parts.F;
            //rotate[1] = -rotate[2] * parts.F;
            //rotate[2] = temp * parts.F;

            //babylonMesh.rotation = rotate;

            babylonMesh.rotationQuaternion = parts.Q.ToArray();

            babylonMesh.scaling = parts.K.ToArraySwitched();

            if (wm.Parity)
            {
                vx1 = 2;
                vx2 = 1;
                vx3 = 0;
            }
            else
            {
                vx1 = 0;
                vx2 = 1;
                vx3 = 2;
            }

            // Pivot
            //var pivotMatrix = Matrix3.Identity._IMatrix3;
            //pivotMatrix.PreTranslate(meshNode._Node.ObjOffsetPos);
            //Loader.Global.PreRotateMatrix(pivotMatrix, meshNode._Node.ObjOffsetRot);
            //Loader.Global.ApplyScaling(pivotMatrix, meshNode._Node.ObjOffsetScale);
            //babylonMesh.localMatrix = pivotMatrix.ToArray();

            // Mesh
            var objectState  = meshNode._Node.EvalWorldState(0, false);
            var mesh         = objectState.Obj.GetMesh();
            var computedMesh = meshNode.GetMesh();

            if (mesh != null)
            {
                mesh.BuildNormals();

                if (mesh.NumFaces < 1)
                {
                    RaiseError(string.Format("Mesh {0} has no face", babylonMesh.name));
                }

                if (mesh.NumVerts < 3)
                {
                    RaiseError(string.Format("Mesh {0} has not enough vertices", babylonMesh.name));
                }

                if (mesh.NumVerts >= 65536)
                {
                    RaiseError(string.Format("Mesh {0} has too many vertices (more than 65535)", babylonMesh.name));
                }

                // Material
                var mtl            = meshNode.Material;
                var multiMatsCount = 1;

                if (mtl != null)
                {
                    babylonMesh.materialId = mtl.GetGuid().ToString();

                    if (!referencedMaterials.Contains(mtl))
                    {
                        referencedMaterials.Add(mtl);
                    }

                    multiMatsCount = Math.Max(mtl.NumSubMaterials, 1);
                }

                babylonMesh.visibility = meshNode._Node.GetVisibility(0, Interval.Forever._IInterval);

                var vertices = new List <GlobalVertex>();
                var indices  = new List <int>();
                var matIDs   = new List <int>();

                var hasUV  = mesh.NumTVerts > 0;
                var hasUV2 = mesh.GetNumMapVerts(2) > 0;

                for (var face = 0; face < mesh.NumFaces; face++)
                {
                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx1, vertices, hasUV, hasUV2));
                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx2, vertices, hasUV, hasUV2));
                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx3, vertices, hasUV, hasUV2));
                    matIDs.Add(mesh.Faces[face].MatID % multiMatsCount);
                }

                // Buffers
                babylonMesh.positions = vertices.SelectMany(v => v.Position.ToArraySwitched()).ToArray();
                babylonMesh.normals   = vertices.SelectMany(v => v.Normal.ToArraySwitched()).ToArray();
                if (hasUV)
                {
                    babylonMesh.uvs = vertices.SelectMany(v => v.UV.ToArray()).ToArray();
                }
                if (hasUV2)
                {
                    babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2.ToArray()).ToArray();
                }

                // Submeshes
                var sortedIndices = new List <int>();
                var subMeshes     = new List <BabylonSubMesh>();
                var indexStart    = 0;
                for (var index = 0; index < multiMatsCount; index++)
                {
                    var subMesh        = new BabylonSubMesh();
                    var indexCount     = 0;
                    var minVertexIndex = int.MaxValue;
                    var maxVertexIndex = int.MinValue;

                    subMesh.indexStart    = indexStart;
                    subMesh.materialIndex = index;

                    for (var face = 0; face < matIDs.Count; face++)
                    {
                        if (matIDs[face] == index)
                        {
                            var a = indices[3 * face];
                            var b = indices[3 * face + 1];
                            var c = indices[3 * face + 2];

                            sortedIndices.Add(a);
                            sortedIndices.Add(b);
                            sortedIndices.Add(c);
                            indexCount += 3;

                            if (a < minVertexIndex)
                            {
                                minVertexIndex = a;
                            }

                            if (b < minVertexIndex)
                            {
                                minVertexIndex = b;
                            }

                            if (c < minVertexIndex)
                            {
                                minVertexIndex = c;
                            }

                            if (a > maxVertexIndex)
                            {
                                maxVertexIndex = a;
                            }

                            if (b > maxVertexIndex)
                            {
                                maxVertexIndex = b;
                            }

                            if (c > maxVertexIndex)
                            {
                                maxVertexIndex = c;
                            }
                        }
                    }
                    subMesh.indexCount    = indexCount;
                    subMesh.verticesStart = minVertexIndex;
                    subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                    indexStart += indexCount;

                    subMeshes.Add(subMesh);
                }
                babylonMesh.subMeshes = subMeshes.ToArray();


                // Buffers - Indices
                babylonMesh.indices = sortedIndices.ToArray();
            }

            babylonScene.MeshesList.Add(babylonMesh);

            return(babylonMesh);
        }
Exemplo n.º 11
0
        private void ExtractGeometry(BabylonAbstractMesh babylonAbstractMesh, List <GlobalVertex> vertices, List <int> indices, List <BabylonSubMesh> subMeshes, List <int> boneIds, IIGameSkin skin, IIGameMesh unskinnedMesh, IMatrix3 invertedWorldMatrix, IMatrix3 offsetTM, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, bool optimizeVertices, int multiMatsCount, IIGameNode meshNode, ref List <int> faceIndexes)
        {
            Dictionary <GlobalVertex, List <GlobalVertex> > verticesAlreadyExported = null;

            if (optimizeVertices)
            {
                verticesAlreadyExported = new Dictionary <GlobalVertex, List <GlobalVertex> >();
            }

            var indexStart = 0;

            // Whether or not to store order in which faces are exported
            // Storage is used when exporting Morph Targets geometry
            // To ensure face order is identical, especially with multimaterials involved
            bool storeFaceIndexes = faceIndexes == null;

            if (storeFaceIndexes)
            {
                faceIndexes = new List <int>();
            }
            int indexInFaceIndexesArray = 0;

            for (int i = 0; i < multiMatsCount; ++i)
            {
                int materialId     = i;
                var indexCount     = 0;
                var minVertexIndex = int.MaxValue;
                var maxVertexIndex = int.MinValue;
                var subMesh        = new BabylonSubMesh {
                    indexStart = indexStart, materialIndex = i
                };

                if (multiMatsCount == 1)
                {
                    for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                    {
                        IFaceEx face = null;
                        if (storeFaceIndexes)
                        {
                            face = unskinnedMesh.GetFace(j);
                            // Store face index (j = face.MeshFaceIndex)
                            faceIndexes.Add(j);
                        }
                        else
                        {
                            face = unskinnedMesh.GetFace(faceIndexes[indexInFaceIndexesArray++]);
                        }
                        ExtractFace(skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                    }
                }
                else
                {
                    if (i == 0 || isMaterialDoubleSided == false)
                    {
                        ITab <IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
                        for (int j = 0; j < materialFaces.Count; ++j)
                        {
                            IFaceEx face = null;
                            if (storeFaceIndexes)
                            {
                                // Retreive face
#if MAX2017 || MAX2018 || MAX2019 || MAX2020
                                face = materialFaces[j];
#else
                                face = materialFaces[new IntPtr(j)];
#endif

                                // Store face index
                                faceIndexes.Add(face.MeshFaceIndex);
                            }
                            else
                            {
                                face = unskinnedMesh.GetFace(faceIndexes[indexInFaceIndexesArray++]);
                            }
                            ExtractFace(skin, unskinnedMesh, babylonAbstractMesh, invertedWorldMatrix, offsetTM, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                        }
                    }
                    else
                    {
                        // It's a double sided material
                        // The back faces are created at runtime

                        // WARNING - Nested multimaterial and double sided material are not supported

                        minVertexIndex = vertices.Count;
                        maxVertexIndex = vertices.Count * 2 - 1;

                        // Vertices
                        int nbVertices = vertices.Count;
                        for (int index = 0; index < nbVertices; index++)
                        {
                            GlobalVertex vertexOrg = vertices[index];

                            // Duplicate vertex
                            GlobalVertex vertexNew = new GlobalVertex(vertexOrg);

                            // Inverse back vertices normal
                            vertexNew.Normal  = vertexNew.Normal.MultiplyBy(-1);
                            vertexNew.Tangent = vertexNew.Tangent.MultiplyBy(-1);

                            vertices.Add(vertexNew);
                        }

                        // Faces
                        int nbIndices = indices.Count;
                        for (int index = 0; index < nbIndices; index += 3)
                        {
                            // Duplicate and flip faces
                            indices.Add(indices[index + 2] + nbIndices);
                            indices.Add(indices[index + 1] + nbIndices);
                            indices.Add(indices[index] + nbIndices);

                            indexCount += 3;
                        }
                    }
                }

                if (indexCount != 0)
                {
                    subMesh.indexCount    = indexCount;
                    subMesh.verticesStart = minVertexIndex;
                    subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                    indexStart += indexCount;

                    subMeshes.Add(subMesh);
                }
            }
        }
Exemplo n.º 12
0
        private void ExportMesh(IINode meshNode, BabylonScene babylonScene)
        {
            if (meshNode.IsInstance())
            {
                return;
            }

            if (meshNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            if (!ExportHiddenObjects && meshNode.IsHidden(NodeHideFlags.None, false))
            {
                return;
            }

            var babylonMesh = new BabylonMesh();
            int vx1, vx2, vx3;

            babylonMesh.name = meshNode.Name;
            babylonMesh.id   = meshNode.GetGuid().ToString();
            if (meshNode.HasParent())
            {
                babylonMesh.parentId = meshNode.ParentNode.GetGuid().ToString();
            }

            // Misc.
            babylonMesh.isVisible                = meshNode.Renderable == 1;
            babylonMesh.pickable                 = meshNode.GetBoolProperty("babylonjs_checkpickable");
            babylonMesh.receiveShadows           = meshNode.RcvShadows == 1;
            babylonMesh.showBoundingBox          = meshNode.GetBoolProperty("babylonjs_showboundingbox");
            babylonMesh.showSubMeshesBoundingBox = meshNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox");

            // Collisions
            babylonMesh.checkCollisions = meshNode.GetBoolProperty("babylonjs_checkcollisions");

            // Skin
            var skin = GetSkinModifier(meshNode);

            if (skin != null)
            {
                babylonMesh.skeletonId = skins.IndexOf(skin);
                bonesCount             = skin.NumBones;
            }

            // Position / rotation / scaling
            var wm = Tools.ExtractCoordinates(meshNode, babylonMesh, exportQuaternionsInsteadOfEulers);

            if (wm.Parity)
            {
                vx1 = 2;
                vx2 = 1;
                vx3 = 0;
            }
            else
            {
                vx1 = 0;
                vx2 = 1;
                vx3 = 2;
            }

            // Pivot
            var pivotMatrix = Tools.Identity;

            pivotMatrix.PreTranslate(meshNode.ObjOffsetPos);
            Loader.Global.PreRotateMatrix(pivotMatrix, meshNode.ObjOffsetRot);
            Loader.Global.ApplyScaling(pivotMatrix, meshNode.ObjOffsetScale);
            babylonMesh.pivotMatrix = pivotMatrix.ToArray();

            // Mesh
            var objectState = meshNode.EvalWorldState(0, false);
            var triObject   = objectState.Obj.GetMesh();
            var mesh        = triObject != null ? triObject.Mesh : null;

            RaiseMessage(meshNode.Name, 1);

            if (mesh != null)
            {
                mesh.BuildNormals();

                if (mesh.NumFaces < 1)
                {
                    RaiseError(string.Format("Mesh {0} has no face", babylonMesh.name), 2);
                }

                if (mesh.NumVerts < 3)
                {
                    RaiseError(string.Format("Mesh {0} has not enough vertices", babylonMesh.name), 2);
                }

                if (mesh.NumVerts >= 65536)
                {
                    RaiseError(string.Format("Mesh {0} has too many vertices (more than 65535)", babylonMesh.name), 2);
                }

                // Material
                var mtl            = meshNode.Mtl;
                var multiMatsCount = 1;

                if (mtl != null)
                {
                    babylonMesh.materialId = mtl.GetGuid().ToString();

                    if (!referencedMaterials.Contains(mtl))
                    {
                        referencedMaterials.Add(mtl);
                    }

                    multiMatsCount = Math.Max(mtl.NumSubMtls, 1);
                }

                babylonMesh.visibility = meshNode.GetVisibility(0, Tools.Forever);

                var vertices = new List <GlobalVertex>();
                var indices  = new List <int>();
                var matIDs   = new List <int>();

                var hasUV  = mesh.NumTVerts > 0;
                var hasUV2 = mesh.GetNumMapVerts(2) > 0;

                var optimizeVertices = meshNode.GetBoolProperty("babylonjs_optimizevertices");

                // Skin
                IISkinContextData skinContext = null;

                if (skin != null)
                {
                    skinContext = skin.GetContextInterface(meshNode);
                }

                // Compute normals
                VNormal[]             vnorms = Tools.ComputeNormals(mesh, optimizeVertices);
                List <GlobalVertex>[] verticesAlreadyExported = null;

                if (optimizeVertices)
                {
                    verticesAlreadyExported = new List <GlobalVertex> [mesh.NumVerts];
                }

                for (var face = 0; face < mesh.NumFaces; face++)
                {
                    indices.Add(CreateGlobalVertex(mesh, face, vx1, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported, skinContext));
                    indices.Add(CreateGlobalVertex(mesh, face, vx2, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported, skinContext));
                    indices.Add(CreateGlobalVertex(mesh, face, vx3, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported, skinContext));
                    matIDs.Add(mesh.Faces[face].MatID % multiMatsCount);
                    CheckCancelled();
                }

                if (vertices.Count >= 65536)
                {
                    RaiseError(string.Format("Mesh {0} has too many vertices: {1} (limit is 65535)", babylonMesh.name, vertices.Count), 2);

                    if (!optimizeVertices)
                    {
                        RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2);
                    }
                }

                RaiseMessage(string.Format("{0} vertices, {1} faces", vertices.Count, indices.Count / 3), 2);

                // Buffers
                babylonMesh.positions = vertices.SelectMany(v => v.Position.ToArraySwitched()).ToArray();
                babylonMesh.normals   = vertices.SelectMany(v => v.Normal.ToArraySwitched()).ToArray();
                if (hasUV)
                {
                    babylonMesh.uvs = vertices.SelectMany(v => v.UV.ToArray()).ToArray();
                }
                if (hasUV2)
                {
                    babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2.ToArray()).ToArray();
                }

                if (skin != null)
                {
                    babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
                    babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();
                }

                // Submeshes
                var sortedIndices = new List <int>();
                var subMeshes     = new List <BabylonSubMesh>();
                var indexStart    = 0;
                for (var index = 0; index < multiMatsCount; index++)
                {
                    var subMesh        = new BabylonSubMesh();
                    var indexCount     = 0;
                    var minVertexIndex = int.MaxValue;
                    var maxVertexIndex = int.MinValue;

                    subMesh.indexStart    = indexStart;
                    subMesh.materialIndex = index;

                    for (var face = 0; face < matIDs.Count; face++)
                    {
                        if (matIDs[face] == index)
                        {
                            var a = indices[3 * face];
                            var b = indices[3 * face + 1];
                            var c = indices[3 * face + 2];

                            sortedIndices.Add(a);
                            sortedIndices.Add(b);
                            sortedIndices.Add(c);
                            indexCount += 3;

                            if (a < minVertexIndex)
                            {
                                minVertexIndex = a;
                            }

                            if (b < minVertexIndex)
                            {
                                minVertexIndex = b;
                            }

                            if (c < minVertexIndex)
                            {
                                minVertexIndex = c;
                            }

                            if (a > maxVertexIndex)
                            {
                                maxVertexIndex = a;
                            }

                            if (b > maxVertexIndex)
                            {
                                maxVertexIndex = b;
                            }

                            if (c > maxVertexIndex)
                            {
                                maxVertexIndex = c;
                            }
                        }
                    }
                    if (indexCount != 0)
                    {
                        subMesh.indexCount    = indexCount;
                        subMesh.verticesStart = minVertexIndex;
                        subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                        indexStart += indexCount;

                        subMeshes.Add(subMesh);
                    }
                    CheckCancelled();
                }
                babylonMesh.subMeshes = subMeshes.ToArray();


                // Buffers - Indices
                babylonMesh.indices = sortedIndices.ToArray();

                triObject.Dispose();
            }

            // Instances
            var tabs = Loader.Global.NodeTab.Create();

            Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode, tabs);
            var instances = new List <BabylonAbstractMesh>();

            for (var index = 0; index < tabs.Count; index++)
            {
                var indexer = new IntPtr(index);
                var tab     = tabs[indexer];

                Marshal.FreeHGlobal(indexer);

                if (meshNode.GetGuid() == tab.GetGuid())
                {
                    continue;
                }

                tab.MarkAsInstance();

                var instance = new BabylonAbstractMesh {
                    name = tab.Name
                };

                Tools.ExtractCoordinates(tab, instance, exportQuaternionsInsteadOfEulers);
                var instanceAnimations = new List <BabylonAnimation>();
                GenerateCoordinatesAnimations(tab, instanceAnimations);
                instance.animations = instanceAnimations.ToArray();

                instances.Add(instance);
            }

            babylonMesh.instances = instances.ToArray();

            // Animations
            var animations = new List <BabylonAnimation>();

            GenerateCoordinatesAnimations(meshNode, animations);


            if (!ExportFloatController(meshNode.VisController, "visibility", animations))
            {
                ExportFloatAnimation("visibility", animations, key => new[] { meshNode.GetVisibility(key, Tools.Forever) });
            }

            babylonMesh.animations = animations.ToArray();

            if (meshNode.GetBoolProperty("babylonjs_autoanimate", 1))
            {
                babylonMesh.autoAnimate     = true;
                babylonMesh.autoAnimateFrom = (int)meshNode.GetFloatProperty("babylonjs_autoanimate_from");
                babylonMesh.autoAnimateTo   = (int)meshNode.GetFloatProperty("babylonjs_autoanimate_to", 100);
                babylonMesh.autoAnimateLoop = meshNode.GetBoolProperty("babylonjs_autoanimateloop", 1);
            }

            babylonScene.MeshesList.Add(babylonMesh);
        }