private BabylonAbstractMesh ConvertUnityMeshToInstance(GameObject gameObject)
        {
            BabylonAbstractMesh babylonMesh = new BabylonAbstractMesh();

            Transform transform = gameObject.transform;
            babylonMesh.name = gameObject.name;
            babylonMesh.position = new float[3];
            babylonMesh.position[0] = transform.position.x;
            babylonMesh.position[1] = transform.position.y;
            babylonMesh.position[2] = transform.position.z;

            babylonMesh.rotation = new float[3];
            babylonMesh.rotation[0] = transform.rotation.eulerAngles.x * (float)Math.PI / 180;
            babylonMesh.rotation[1] = transform.rotation.eulerAngles.y * (float)Math.PI / 180;
            babylonMesh.rotation[2] = transform.rotation.eulerAngles.z * (float)Math.PI / 180;

            babylonMesh.scaling = new float[3];
            babylonMesh.scaling[0] = transform.localScale.x;
            babylonMesh.scaling[1] = transform.localScale.y;
            babylonMesh.scaling[2] = transform.localScale.z;
            return babylonMesh;
        }
        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", 0);
                
                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.
            babylonMesh.isVisible = meshNode.MaxNode.Renderable == 1;
            babylonMesh.pickable = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable");
            babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1;
            babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox");
            babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox");
            babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1;
            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;
            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(string.Format("Mesh {0} has no face", babylonMesh.name), 2);
                }

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

                if (unskinnedMesh.NumberOfVerts >= 65536)
                {
                    RaiseWarning(string.Format("Mesh {0} 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.", babylonMesh.name), 2);
                }

                // 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)
                {
                    var indexer = new IntPtr(i);
                    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 == null ? 0 : meshNode.NodeMaterial.GetMaterialID(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)
                        {
                            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)
                        {
                            var faceIndexer = new IntPtr(j);
                            var face = materialFaces[faceIndexer];

                            Marshal.FreeHGlobal(faceIndexer);
                            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(string.Format("Mesh {0} has {1} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", 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 => 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();
                }

                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++)
            {
                var indexer = new IntPtr(index);
                var tab = tabs[indexer];

                Marshal.FreeHGlobal(indexer);

                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);
        }
 private void RotationToEulerAngles(BabylonAbstractMesh babylonMesh, IQuat rotation)
 {
     float rotx = 0, roty = 0, rotz = 0;
     unsafe
     {
         rotation.GetEuler(new IntPtr(&rotx), new IntPtr(&roty), new IntPtr(&rotz));
     }
     babylonMesh.rotation = new[] { rotx, roty, rotz };
 }
示例#4
0
        public static IMatrix3 ExtractCoordinates(IINode meshNode, BabylonAbstractMesh babylonMesh, bool exportQuaternionsInsteadOfEulers)
        {
            var wm = meshNode.GetWorldMatrix(0, meshNode.HasParent());
            babylonMesh.position = wm.Trans.ToArraySwitched();

            var parts = Loader.Global.AffineParts.Create();
            Loader.Global.DecompAffine(wm, parts);

            if (exportQuaternionsInsteadOfEulers)
            {
                babylonMesh.rotationQuaternion = parts.Q.ToArray();
            }
            else
            {
                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.scaling = parts.K.ToArraySwitched();

            return wm;
        }
        private void ConvertTransform(BabylonMesh babylonMesh, Transform transform, GameObject gameObject, BabylonAbstractMesh[] instances = null)
        {
            Action SetTransformFromGameobject = () =>
            {
                babylonMesh.position = transform.localPosition.ToFloat();

                babylonMesh.rotation = new float[3];
                babylonMesh.rotation[0] = transform.localRotation.eulerAngles.x * (float)Math.PI / 180;
                babylonMesh.rotation[1] = transform.localRotation.eulerAngles.y * (float)Math.PI / 180;
                babylonMesh.rotation[2] = transform.localRotation.eulerAngles.z * (float)Math.PI / 180;

                babylonMesh.scaling = transform.localScale.ToFloat();
            };

            Action SetTransformFromFirstInstance = () =>
            {
                BabylonAbstractMesh first = instances[0];

                babylonMesh.position = new float[3];
                babylonMesh.position[0] = first.position[0];
                babylonMesh.position[1] = first.position[1];
                babylonMesh.position[2] = first.position[2];

                babylonMesh.rotation = new float[3];
                babylonMesh.rotation[0] = first.rotation[0];
                babylonMesh.rotation[1] = first.rotation[1];
                babylonMesh.rotation[2] = first.rotation[2];

                babylonMesh.scaling = new float[3];
                babylonMesh.scaling[0] = first.scaling[0];
                babylonMesh.scaling[1] = first.scaling[1];
                babylonMesh.scaling[2] = first.scaling[2];
            };

            //Check if this is a prefab
            if (instances != null)
            {
                /*
                    Unity3D prefabs don't have transforms (position, rotation, scale) because they are just a template and are not drawn on screen          
                    but Babylon.js meshes must have a transform because they are drawn on the screen
                    so what we do is take the first instance
                    copy its transform (position, rotation, scale) into the prefab mesh
                    then remove that first instance
                */

                babylonMesh.instances = new BabylonAbstractMesh[instances.Length - 1];

                //Effectively remove first instance from list of all instances
                for (int i = 0; i < instances.Length - 1; i++)
                {
                    babylonMesh.instances[i] = instances[i + 1];
                }

                //If this is the root object then copy values directly from first instance
                if (GetParentID(transform) == null)
                {
                    SetTransformFromFirstInstance();
                }
                else
                {
                    GameObject parent = gameObject.transform.parent.gameObject;
                    if ((parent.GetComponent<Light>() == null) && (parent.GetComponent<Camera>() == null))
                    {
                        SetTransformFromGameobject();
                    } else
                    {
                        SetTransformFromFirstInstance();
                    }
                }
            }
            else
            {
                SetTransformFromGameobject();
            }
        }
        private void ConvertUnityMeshToBabylon(Mesh mesh, Transform transform, GameObject gameObject, float progress, BabylonAbstractMesh[] instances = null)
        {
            BabylonMesh babylonMesh = new BabylonMesh();
            var renderer = gameObject.GetComponent<Renderer>();

            ExporterWindow.ReportProgress(progress, "Exporting mesh: " + gameObject.name);

            babylonMesh.name = gameObject.name;
            babylonMesh.id = GetID(transform.gameObject);
            babylonMesh.receiveShadows = renderer.receiveShadows;

            babylonMesh.parentId = GetParentID(transform);
            ConvertTransform(babylonMesh, transform, gameObject, instances);

            babylonMesh.positions = new float[mesh.vertexCount * 3];

            for (int i = 0; i < mesh.vertices.Length; i++)
            {
                babylonMesh.positions[i * 3] = mesh.vertices[i].x;
                babylonMesh.positions[(i * 3) + 1] = mesh.vertices[i].y;
                babylonMesh.positions[(i * 3) + 2] = mesh.vertices[i].z;

                // Computing world extends
                var worldPosition = transform.TransformPoint(mesh.vertices[i]);

                if (worldPosition.x > babylonScene.MaxVector.X)
                {
                    babylonScene.MaxVector.X = worldPosition.x;
                }
                if (worldPosition.y > babylonScene.MaxVector.Y)
                {
                    babylonScene.MaxVector.Y = worldPosition.y;
                }
                if (worldPosition.z > babylonScene.MaxVector.Z)
                {
                    babylonScene.MaxVector.Z = worldPosition.z;
                }

                if (worldPosition.x < babylonScene.MinVector.X)
                {
                    babylonScene.MinVector.X = worldPosition.x;
                }
                if (worldPosition.y < babylonScene.MinVector.Y)
                {
                    babylonScene.MinVector.Y = worldPosition.y;
                }
                if (worldPosition.z < babylonScene.MinVector.Z)
                {
                    babylonScene.MinVector.Z = worldPosition.z;
                }
            }

            babylonMesh.normals = new float[mesh.vertexCount * 3];

            for (int i = 0; i < mesh.normals.Length; i++)
            {
                babylonMesh.normals[i * 3] = mesh.normals[i].x;
                babylonMesh.normals[(i * 3) + 1] = mesh.normals[i].y;
                babylonMesh.normals[(i * 3) + 2] = mesh.normals[i].z;
            }

            babylonMesh.uvs = new float[mesh.vertexCount * 2];

            for (int i = 0; i < mesh.uv.Length; i++)
            {
                babylonMesh.uvs[i * 2] = mesh.uv[i].x;
                babylonMesh.uvs[(i * 2) + 1] = mesh.uv[i].y;
            }

            if (mesh.uv2 != null)
            {
                babylonMesh.uvs2 = new float[mesh.vertexCount * 2];

                for (int i = 0; i < mesh.uv2.Length; i++)
                {
                    babylonMesh.uvs2[i * 2] = mesh.uv2[i].x;
                    babylonMesh.uvs2[(i * 2) + 1] = mesh.uv2[i].y;
                }
            }

            babylonMesh.indices = new int[mesh.triangles.Length];

            for (int i = 0; i < mesh.triangles.Length; i += 3)
            {
                babylonMesh.indices[i] = mesh.triangles[i + 2];
                babylonMesh.indices[i + 1] = mesh.triangles[i + 1];
                babylonMesh.indices[i + 2] = mesh.triangles[i];
            }

            if (mesh.subMeshCount > 1) // Multimaterials
            {
                BabylonMultiMaterial bMultiMat;
                if (!multiMatDictionary.ContainsKey(renderer.sharedMaterial.name))
                {
                    bMultiMat = new BabylonMultiMaterial
                    {
                        materials = new string[mesh.subMeshCount],
                        id = Guid.NewGuid().ToString(),
                        name = renderer.sharedMaterial.name
                    };

                    for (int i = 0; i < renderer.sharedMaterials.Length; i++)
                    {
                        var bMat = DumpMaterial(renderer.sharedMaterials[i], renderer);
                        bMultiMat.materials[i] = bMat.id;
                    }
                    if (mesh.subMeshCount > 1)
                    {
                        multiMatDictionary.Add(bMultiMat.name, bMultiMat);
                    }
                }
                else
                {
                    bMultiMat = multiMatDictionary[renderer.sharedMaterial.name];
                }

                babylonMesh.materialId = bMultiMat.id;
                babylonMesh.subMeshes = new BabylonSubMesh[mesh.subMeshCount];

                var offset = 0;
                for (int materialIndex = 0; materialIndex < mesh.subMeshCount; materialIndex++)
                {
                    var unityTriangles = mesh.GetTriangles(materialIndex);

                    babylonMesh.subMeshes[materialIndex] = new BabylonSubMesh
                    {
                        verticesStart = 0,
                        verticesCount = mesh.vertexCount,
                        materialIndex = materialIndex,
                        indexStart = offset,
                        indexCount = unityTriangles.Length
                    };

                    offset += unityTriangles.Length;
                }
            }
            else
            {
                babylonMesh.materialId = DumpMaterial(renderer.sharedMaterial, renderer).id;
            }

            babylonScene.MeshesList.Add(babylonMesh);

            // Animations
            ExportAnimations(transform, babylonMesh);

            if (IsRotationQuaternionAnimated(babylonMesh))
            {
                babylonMesh.rotationQuaternion = transform.localRotation.ToFloat();
            }

            // Collisions
            if (exportationOptions.ExportCollisions)
            {
                var collider = gameObject.GetComponent<Collider>();

                if (collider != null)
                {
                    babylonMesh.checkCollisions = true;
                }
            }
        }
        private void ConvertUnityEmptyObjectToBabylon(GameObject gameObject, BabylonAbstractMesh[] instances = null)
        {
            BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) };

            var transform = gameObject.transform;

            babylonMesh.parentId = GetParentID(transform);
            ConvertTransform(babylonMesh, transform, gameObject, instances);

            babylonScene.MeshesList.Add(babylonMesh);

            // Animations
            ExportAnimations(transform, babylonMesh);

            if (IsRotationQuaternionAnimated(babylonMesh))
            {
                babylonMesh.rotationQuaternion = transform.localRotation.ToFloat();
            }
        }
        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);
        }