示例#1
0
        private void ConvertUnityEmptyObjectToBabylon(GameObject gameObject)
        {
            BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) };

            var transform = gameObject.transform;

            babylonMesh.parentId = GetParentID(transform);

            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();

            babylonScene.MeshesList.Add(babylonMesh);

            // Animations
            ExportAnimations(transform, babylonMesh);

            if (IsRotationQuaternionAnimated(babylonMesh))
            {
                babylonMesh.rotationQuaternion = transform.localRotation.ToFloat();
            }
        }
        public static BabylonMesh Clone(this BabylonMesh mesh, BabylonScene scene)
        {
            string gid = mesh.geometryId;

            if (gid == null)
            {
                // we may create the geometry into the scene
                gid = mesh.id;
                // ensure geometries object exist
                scene.geometries = scene.geometries ?? new BabylonGeometries();
                // add new geometry object to the scene
                if (!scene.geometries.Contains(gid))
                {
                    scene.geometries.Add(new BabylonVertexData(gid, mesh));
                }
                // and update the mesh to ref this geometry.
                mesh.geometryId = gid;
                mesh.ClearLocalGeometry();
            }

            BabylonMesh newMesh = new BabylonMesh()
            {
                materialId = mesh.materialId,
                geometryId = mesh.geometryId,
                subMeshes  = mesh.subMeshes
            };

            return(newMesh);
        }
        private static void ExportSkeletonAnimationClips(Animator animator, bool autoPlay, BabylonSkeleton skeleton, Transform[] bones, BabylonMesh babylonMesh)
        {
            AnimationClip clip = null;
            AnimatorController ac = animator.runtimeAnimatorController as AnimatorController;
            if (ac == null)
            {
                return;
            }
            var layer = ac.layers[0];
            if (layer == null)
            {
                return;
            }
            AnimatorStateMachine sm = layer.stateMachine;
            if (sm.states.Length > 0)
            {
                // Only the first state is supported so far.
                var state = sm.states[0].state;
                clip = state.motion as AnimationClip;
            }

            if (clip == null)
            {
                return;
            }

            ExportSkeletonAnimationClipData(animator, autoPlay, skeleton, bones, babylonMesh, clip);
        }
        private BabylonMesh ConvertUnityEmptyObjectToBabylon(GameObject gameObject, ref UnityMetaData metaData, ref List<BabylonExport.Entities.BabylonParticleSystem> particleSystems, ref List<UnityFlareSystem> lensFlares, ref string componentTags, BabylonMesh collisionMesh = null, Collider collider = null)
        {
            BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) };
            metaData.type = "Game";
            if (!String.IsNullOrEmpty(componentTags))
            {
                babylonMesh.tags = componentTags;
            }

            var transform = gameObject.transform;

            babylonMesh.parentId = GetParentID(transform);

            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();

            babylonMesh.isVisible = false;
            babylonMesh.visibility = 0;
            babylonMesh.checkCollisions = false;

            // Collision mesh (No detail mesh fallback)
            string collisionMeshId = null;
            if (collider != null && collisionMesh != null)
            {
                collisionMeshId = collisionMesh.id;
                collisionMesh.parentId = babylonMesh.id;
                collisionMesh.visibility = collider.isTrigger ? 0.25f : 0.5f;
                collisionMesh.checkCollisions = (exportationOptions.ExportCollisions && collider.isTrigger == false);
            }
            metaData.properties["collisionMeshId"] = collisionMeshId;

            babylonMesh.metadata = metaData;
            babylonScene.MeshesList.Add(babylonMesh);

            // Animations
            ExportAnimations(transform, babylonMesh);
            if (IsRotationQuaternionAnimated(babylonMesh))
            {
                babylonMesh.rotationQuaternion = transform.localRotation.ToFloat();
            }

            // Lens Flares
            ParseLensFlares(gameObject, babylonMesh.id, ref lensFlares);

            // Particles Systems
            ParseParticleSystems(gameObject, babylonMesh.id, ref particleSystems);

            return babylonMesh;
        }
示例#5
0
        internal static bool MeshesShareSkin(BabylonMesh matchingSkinnedMesh, BabylonMesh babylonMesh)
        {
            // check if the skinning matrix indices are equivalent
            if (!babylonMesh.matricesIndices.SequenceEqual(matchingSkinnedMesh.matricesIndices))
            {
                return(false);
            }

            // finally, compare the skinning matrix weights within a tolerance threshold.
            var skinDifference = babylonMesh.matricesWeights.Zip(matchingSkinnedMesh.matricesWeights, (first, second) => first - second).ToArray();

            return(skinDifference.All(value => Math.Abs(value) < BabylonMesh.SkinningWeightToleranceThreshold));
        }
        private void ConvertUnitySkyboxToBabylon(Camera camera, float progress)
        {
            // Skybox
            if ((camera.clearFlags & CameraClearFlags.Skybox) == CameraClearFlags.Skybox)
            {
                if (RenderSettings.skybox != null)
                {
                    if (RenderSettings.skybox.shader.name == "Skybox/Cubemap")
                    {
                        var cubeMap = RenderSettings.skybox.GetTexture("_Tex") as Cubemap;
                        if (cubeMap != null)
                        {
                            var skytex = new BabylonTexture();
                            CopyTextureCube("sceneSkybox.hdr", cubeMap, skytex);
                            skytex.coordinatesMode = 5;
                            skytex.level = RenderSettings.reflectionIntensity;

                            BabylonMesh skybox = new BabylonMesh();
                            skybox.indices = new[] { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 };
                            skybox.positions = new[] { 50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f };
                            skybox.uvs = new[] { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
                            skybox.normals = new[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0,0f };

                            var skyboxMaterial = new BabylonPBRMaterial()
                            {
                                name = "sceneSkyboxMaterial",
                                id = Guid.NewGuid().ToString(),
                                albedo = new[] { 1.0f, 1.0f, 1.0f, 1.0f },
                                reflectivity = new[] { 0.0f, 0.0f, 0.0f },
                                microSurface = 1.0f,
                                directIntensity = 0.0f,
                                specularIntensity = 0.0f,
                                environmentIntensity = 1.0f
                            };
                            skyboxMaterial.backFaceCulling = false;
                            skybox.materialId = skyboxMaterial.id;
                            skybox.infiniteDistance = true;
                            skyboxMaterial.reflectionTexture = skytex;
                            
                            babylonScene.MeshesList.Add(skybox);
                            babylonScene.MaterialsList.Add(skyboxMaterial);
                            babylonScene.AddTextureCube("sceneSkyboxMaterial");
                        }
                    }
                }
            }
        }
示例#7
0
        private static void ExportSkeletonAnimation(SkinnedMeshRenderer skinnedMesh, BabylonMesh babylonMesh, BabylonSkeleton skeleton)
        {
            var animator = skinnedMesh.rootBone.gameObject.GetComponent<Animator>();
            if (animator != null)
            {
                ExportSkeletonAnimationClips(animator, true, skeleton, skinnedMesh.bones, babylonMesh);
            }
            else
            {
                var parent = skinnedMesh.rootBone.parent;
                while (parent != null)
                {
                    animator = parent.gameObject.GetComponent<Animator>();
                    if (animator != null)
                    {
                        ExportSkeletonAnimationClips(animator, true, skeleton, skinnedMesh.bones, babylonMesh);
                        break;
                    }

                    parent = parent.parent;
                }
            }
        }
示例#8
0
 public BabylonMorphTargetManager(BabylonMesh sourceMesh)
 {
     id = NB_BABYLON_MORPH_TARGET_MANAGER++;
     this.sourceMesh = sourceMesh;
 }
        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);
        }
示例#10
0
        private BabylonMesh ConvertUnityTerrainToBabylon(Terrain terrain, GameObject gameObject, float progress, ref UnityMetaData metaData, ref List<BabylonExport.Entities.BabylonParticleSystem> particleSystems, ref List<UnityFlareSystem> lensFlares, ref string componentTags)
        {
            ExporterWindow.ReportProgress(progress, "Exporting terrain: " + gameObject.name);
            var transform = gameObject.transform;
            float[] position = transform.localPosition.ToFloat();
            float[] rotation = new float[3];
            rotation[0] = transform.localRotation.eulerAngles.x * (float)Math.PI / 180;
            rotation[1] = transform.localRotation.eulerAngles.y * (float)Math.PI / 180;
            rotation[2] = transform.localRotation.eulerAngles.z * (float)Math.PI / 180;
            float[] scaling = transform.localScale.ToFloat();

            BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) };
            metaData.type = "Terrain";
            if (!String.IsNullOrEmpty(componentTags))
            {
                babylonMesh.tags = componentTags;
            }
            babylonMesh.tags += " [TERRAIN]";
            if (!String.IsNullOrEmpty(babylonMesh.tags))
            {
                babylonMesh.tags = babylonMesh.tags.Trim();
            }
            babylonMesh.parentId = GetParentID(transform);
            babylonMesh.position = Vector3.zero.ToFloat();
            babylonMesh.rotation = rotation;
            babylonMesh.scaling = scaling;
            babylonMesh.isVisible = true;
            babylonMesh.visibility = 1;
            babylonMesh.checkCollisions = false;
            metaData.properties["collisionMeshId"] = null;

            var generator = gameObject.GetComponent<BabylonTerrainGenerator>();
            if (generator != null && terrain != null)
            {
                // TODO: Terrain tree information
                object treeInstances = null;
                object treePrototypes = null;

                // Terrain metadata infomation
                Vector3 terrainSize = terrain.terrainData.size;
                metaData.properties.Add("width", terrainSize.x);
                metaData.properties.Add("length", terrainSize.z);
                metaData.properties.Add("height", terrainSize.y);
                metaData.properties.Add("position", position);
                metaData.properties.Add("rotation", rotation);
                metaData.properties.Add("scaling", scaling);
                metaData.properties.Add("thickness", terrain.terrainData.thickness);
                metaData.properties.Add("detailWidth", terrain.terrainData.detailWidth);
                metaData.properties.Add("detailHeight", terrain.terrainData.detailHeight);
                metaData.properties.Add("heightmapWidth", terrain.terrainData.heightmapWidth);
                metaData.properties.Add("heightmapHeight", terrain.terrainData.heightmapHeight);
                metaData.properties.Add("wavingGrassAmount", terrain.terrainData.wavingGrassAmount);
                metaData.properties.Add("wavingGrassSpeed", terrain.terrainData.wavingGrassSpeed);
                metaData.properties.Add("wavingGrassStrength", terrain.terrainData.wavingGrassStrength);
                metaData.properties.Add("wavingGrassTint", terrain.terrainData.wavingGrassTint.ToFloat());
                metaData.properties.Add("treeInstanceCount", terrain.terrainData.treeInstanceCount);
                metaData.properties.Add("treeInstances", treeInstances);
                metaData.properties.Add("treePrototypes", treePrototypes);
                metaData.properties.Add("physicsState", generator.physicsActive);
                metaData.properties.Add("physicsMass", generator.physicsMass);
                metaData.properties.Add("physicsFriction", generator.physicsFriction);
                metaData.properties.Add("physicsRestitution", generator.physicsRestitution);
                metaData.properties.Add("physicsImpostor", (int)generator.physicsImpostor);
                metaData.properties.Add("groundTessellation", generator.groundTessellation);

                // Generate detailed mesh
                ExporterWindow.ReportProgress(progress, "Generating terrain mesh: " + gameObject.name);
                BabylonTerrainData terrainMeshData = Unity3D2Babylon.Tools.CreateTerrainData(terrain.terrainData, (int)generator.terrainResolution, transform.localPosition, true);
                Tools.GenerateBabylonMeshTerrainData(terrainMeshData, babylonMesh, false, babylonScene, transform);
                if (generator.surfaceMaterial != null)
                {
                    babylonMesh.materialId = DumpMaterial(generator.surfaceMaterial, terrain.lightmapIndex, terrain.lightmapScaleOffset, generator.coordinatesIndex).id;
                }

                // Generate collision heightmap
                var terrainCollider = gameObject.GetComponent<TerrainCollider>();
                if (terrainCollider != null && terrainCollider.enabled)
                {
                    ExporterWindow.ReportProgress(progress, "Generating terrain heightmap: " + gameObject.name);
                    float minheight = float.MaxValue;
                    float maxheight = float.MinValue;
                    int hwidth = terrain.terrainData.heightmapWidth;
                    int hheight = terrain.terrainData.heightmapHeight;
                    float[,] rawHeights = terrain.terrainData.GetHeights(0, 0, hwidth, hheight);
                    Texture2D heightMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false);
                    for (int y = 0; y < hheight; y++)
                    {
                        for (int x = 0; x < hwidth; x++)
                        {
                            float inverted = rawHeights[y, x];
                            minheight = Mathf.Min(minheight, inverted);
                            maxheight = Mathf.Max(maxheight, inverted);
                        }
                    }
                    List<Color32> pixels = new List<Color32>();
                    for (int y = 0; y < hheight; y++)
                    {
                        for (int x = 0; x < hwidth; x++)
                        {
                            float inverted = rawHeights[y, x];
                            if (generator.heightmapStrength > 0)
                            {
                                float threadhold = minheight + generator.floorThreashold;
                                if (inverted > threadhold)
                                {
                                    inverted += (generator.heightmapStrength / 10.0f);
                                }
                            }
                            byte[] packed = BitConverter.GetBytes(inverted);
                            if (packed != null && packed.Length >= 4)
                            {
                                pixels.Add(new Color32(packed[0], packed[1], packed[2], packed[3]));
                            }
                        }
                    }
                    heightMap.SetPixels32(pixels.ToArray());
                    heightMap.Apply();
                    byte[] heightmapBytes = heightMap.EncodeToPNG();
                    metaData.properties.Add("heightmapBase64", ("data:image/png;base64," + Convert.ToBase64String(heightmapBytes)));
                }
            }
            else
            {
                UnityEngine.Debug.LogWarning("No valid terrain or generator found for: " + gameObject.name);
            }

            babylonMesh.metadata = metaData;
            babylonScene.MeshesList.Add(babylonMesh);
            SceneBuilder.Metadata.properties["hasTerrainMeshes"] = true;

            // Animations
            ExportAnimations(transform, babylonMesh);
            if (IsRotationQuaternionAnimated(babylonMesh))
            {
                babylonMesh.rotationQuaternion = transform.localRotation.ToFloat();
            }

            // Lens Flares
            ParseLensFlares(gameObject, babylonMesh.id, ref lensFlares);

            // Particles Systems
            ParseParticleSystems(gameObject, babylonMesh.id, ref particleSystems);

            return babylonMesh;
        }
示例#11
0
        private BabylonMesh ConvertUnityMeshToBabylon(Mesh mesh, Transform transform, GameObject gameObject, float progress, ref UnityMetaData metaData, ref List<BabylonExport.Entities.BabylonParticleSystem> particleSystems, ref List<UnityFlareSystem> lensFlares, ref string componentTags, BabylonMesh collisionMesh = null, Collider collider = null)
        {
            BabylonMesh babylonMesh = new BabylonMesh();
            metaData.type = "Mesh";
            if (!String.IsNullOrEmpty(componentTags))
            {
                babylonMesh.tags = componentTags;
            }

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

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

            var renderer = gameObject.GetComponent<Renderer>();
            if (renderer != null)
            {
                babylonMesh.receiveShadows = renderer.receiveShadows;
            }

            babylonMesh.parentId = GetParentID(transform);

            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();
            babylonMesh.checkCollisions = false;

            // Collision mesh (With detail mesh fallback)
            string collisionMeshId = null;
            if (collider != null)
            {
                if (collisionMesh != null)
                {
                    collisionMeshId = collisionMesh.id;
                    collisionMesh.parentId = babylonMesh.id;
                    collisionMesh.visibility = collider.isTrigger ? 0.25f : 0.5f;
                    collisionMesh.checkCollisions = (exportationOptions.ExportCollisions && collider.isTrigger == false);
                }
                else
                {
                    babylonMesh.checkCollisions = exportationOptions.ExportCollisions;
                }
            }
            metaData.properties["collisionMeshId"] = collisionMeshId;

            if (mesh != null)
            {
                Tools.GenerateBabylonMeshData(mesh, babylonMesh, babylonScene, transform);
                int index = 0;
                if (mesh.boneWeights.Length == mesh.vertexCount)
                {
                    babylonMesh.matricesIndices = new int[mesh.vertexCount];
                    babylonMesh.matricesWeights = new float[mesh.vertexCount * 4];
                    index = 0;
                    foreach (BoneWeight bw in mesh.boneWeights)
                    {
                        babylonMesh.matricesIndices[index] = (bw.boneIndex3 << 24) | (bw.boneIndex2 << 16) | (bw.boneIndex1 << 8) | bw.boneIndex0;
                        babylonMesh.matricesWeights[index * 4 + 0] = bw.weight0;
                        babylonMesh.matricesWeights[index * 4 + 1] = bw.weight1;
                        babylonMesh.matricesWeights[index * 4 + 2] = bw.weight2;
                        babylonMesh.matricesWeights[index * 4 + 3] = bw.weight3;
                        var totalWeight = bw.weight0 + bw.weight1 + bw.weight2 + bw.weight3;
                        if (Mathf.Abs(totalWeight - 1.0f) > 0.01f)
                        {
                            throw new Exception("Total bone weights is not normalized for: " + mesh);
                        }
                        index++;
                    }
                }
                index = 0;
                if (renderer != null && renderer.sharedMaterial != null)
                {
                    // Validate Multi Materials
                    if (mesh.subMeshCount > 1)
                    {
                        BabylonMultiMaterial bMultiMat;

                        string multiMatName = "";
                        for (int i = 0; i < renderer.sharedMaterials.Length; i++)
                        {
                            multiMatName += renderer.sharedMaterials[i].name;
                        }
                    

                        if (!multiMatDictionary.ContainsKey(multiMatName))
                        {
                            bMultiMat = new BabylonMultiMaterial
                            {
                                materials = new string[mesh.subMeshCount],
                                id = Guid.NewGuid().ToString(),
                                name = multiMatName
                            };

                            for (int i = 0; i < renderer.sharedMaterials.Length; i++)
                            {
                                var sharedMaterial = renderer.sharedMaterials[i];
                                BabylonMaterial babylonMaterial;

                                babylonMaterial = DumpMaterial(sharedMaterial, renderer.lightmapIndex, renderer.lightmapScaleOffset);

                                bMultiMat.materials[i] = babylonMaterial.id;
                            }
                            if (mesh.subMeshCount > 1)
                            {
                                multiMatDictionary.Add(bMultiMat.name, bMultiMat);
                            }
                        }
                        else
                        {
                            bMultiMat = multiMatDictionary[multiMatName];
                        }

                        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.lightmapIndex, renderer.lightmapScaleOffset).id;
                    }
                }

                babylonMesh.metadata = metaData;
                babylonScene.MeshesList.Add(babylonMesh);

                // Animations
                ExportAnimations(transform, babylonMesh);
                if (IsRotationQuaternionAnimated(babylonMesh))
                {
                    babylonMesh.rotationQuaternion = transform.localRotation.ToFloat();
                }

                // Lens Flares
                ParseLensFlares(gameObject, babylonMesh.id, ref lensFlares);

                // Particles Systems
                ParseParticleSystems(gameObject, babylonMesh.id, ref particleSystems);

                // Babylon Physics
                if (exportationOptions.ExportPhysics)
                {
                    var physics = gameObject.GetComponent<BabylonPhysicsState>();
                    if (physics != null)
                    {
                        babylonMesh.physicsMass = physics.mass;
                        babylonMesh.physicsFriction = physics.friction;
                        babylonMesh.physicsRestitution = physics.restitution;
                        babylonMesh.physicsImpostor = (int)physics.imposter;
                    }
                }
            }
            return babylonMesh;
        }
        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 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();
            }
        }
示例#14
0
        private void ConvertUnityMeshToBabylon(Mesh mesh, Transform transform, GameObject gameObject, float progress)
        {
            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);

            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();

            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;
                }
            }
        }
示例#15
0
        private void ExportMesh(IINode meshNode, BabylonScene babylonScene)
        {
            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 = 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();

            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();
            }


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

            if (!ExportVector3Controller(meshNode.TMController.PositionController, "position", animations))
            {
                ExportVector3Animation("position", animations, key =>
                {
                    var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());
                    return worldMatrix.Trans.ToArraySwitched();
                });
            }

            if (!ExportQuaternionController(meshNode.TMController.RotationController, "rotationQuaternion", animations))
            {
                ExportQuaternionAnimation("rotationQuaternion", animations, key =>
                {
                    var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());

                    var affineParts = Loader.Global.AffineParts.Create();
                    Loader.Global.DecompAffine(worldMatrix, affineParts);

                    return affineParts.Q.ToArray();
                });
            }

            if (!ExportVector3Controller(meshNode.TMController.ScaleController, "scaling", animations))
            {
                ExportVector3Animation("scaling", animations, key =>
                {
                    var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());

                    var affineParts = Loader.Global.AffineParts.Create();
                    Loader.Global.DecompAffine(worldMatrix, affineParts);

                    return affineParts.K.ToArraySwitched();
                });
            }

            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);
        }
        private static void ExportSkeletonAnimationClipData(Animator animator, bool autoPlay, BabylonSkeleton skeleton, Transform[] bones, BabylonMesh babylonMesh, AnimationClip clip)
        {
            var frameTime = 1.0f / clip.frameRate;
            int animationFrameCount = (int)(clip.length * clip.frameRate);

            if (autoPlay)
            {
                babylonMesh.autoAnimate = true;
                babylonMesh.autoAnimateFrom = 0;
                babylonMesh.autoAnimateTo = animationFrameCount;
                babylonMesh.autoAnimateLoop = true;
            }

            foreach (var bone in skeleton.bones)
            {
                var keys = new List<BabylonAnimationKey>();
                var transform = bones.Single(b => b.name == bone.name);

                AnimationMode.BeginSampling();
                for (var i = 0; i < animationFrameCount; i++)
                {
                    clip.SampleAnimation(animator.gameObject, i * frameTime);

                    var local = (transform.parent.localToWorldMatrix.inverse * transform.localToWorldMatrix);
                    float[] matrix = new[] {
                        local[0, 0], local[1, 0], local[2, 0], local[3, 0],
                        local[0, 1], local[1, 1], local[2, 1], local[3, 1],
                        local[0, 2], local[1, 2], local[2, 2], local[3, 2],
                        local[0, 3], local[1, 3], local[2, 3], local[3, 3]
                    };

                    var key = new BabylonAnimationKey
                    {
                        frame = i,
                        values = matrix,
                    };
                    keys.Add(key);
                }
                AnimationMode.EndSampling();

                var babylonAnimation = new BabylonAnimation
                {
                    name = bone.name + "Animation",
                    property = "_matrix",
                    dataType = (int)BabylonAnimation.DataType.Matrix,
                    loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
                    framePerSecond = (int)clip.frameRate,
                    keys = keys.ToArray()
                };

                bone.animation = babylonAnimation;
            }
        }
示例#17
0
        public void ConvertFromUnity()
        {
            ExporterWindow.ReportProgress(0, "Starting exportation process...");
            gameObjects = Object.FindObjectsOfType(typeof(GameObject)) as GameObject[];
            if (gameObjects.Length == 0)
            {
                ExporterWindow.ShowMessage("No gameobject! - Please add at least a gameobject to export");
                return;
            }

            // Create scene metadata
            SceneBuilder.Metadata = new SceneMetaData();

            // Parse all scene game objects
            var index = 0;
            var itemsCount = gameObjects.Length;
            var particleSystems = new List<BabylonExport.Entities.BabylonParticleSystem>();
            var lensFlareSystems = new List<UnityFlareSystem>();
            ExporterWindow.ReportProgress(0, "Exporting game objects from scene...");
            babylonScene.physicsEngine = (exportationOptions.DefaultPhysicsEngine == 1) ? "oimo" : "cannon";
            try
            {
                bool foundController = false;
                foreach (var gameObject in gameObjects)
                {
                    var progress = ((float)index / itemsCount);
                    index++;

                    // Unity metadata
                    var metaData = new UnityMetaData();
                    metaData.objectId = GetID(gameObject);
                    metaData.objectName = gameObject.name;
                    metaData.tagName = gameObject.tag;
                    metaData.layerIndex = gameObject.layer;
                    metaData.layerName = LayerMask.LayerToName(gameObject.layer);

                    // Export hooking
                    var exportObject = gameObject;
                    var exportOptions = exportationOptions;
                    BabylonScene sceneBuilder = babylonScene;
                    if (SceneController != null)
                    {
                        SceneController.OnExportGameObject(ref exportOptions, ref exportObject, ref metaData, ref sceneBuilder, OutputPath);
                    }

                    // Components tags
                    string componentTags = String.Empty;
                    if (!String.IsNullOrEmpty(gameObject.tag) && !gameObject.tag.Equals("Untagged", StringComparison.OrdinalIgnoreCase))
                    {
                        componentTags = gameObject.tag;
                    }

                    // Navigation area
                    metaData.areaIndex = -1;
                    bool navigationStatic = GameObjectUtility.AreStaticEditorFlagsSet(gameObject, StaticEditorFlags.NavigationStatic);
                    if (navigationStatic)
                    {
                        metaData.areaIndex = GameObjectUtility.GetNavMeshArea(gameObject);
                    }

                    // Navigation agent
                    metaData.navAgent = null;
                    var navigationAgent = gameObject.GetComponent<NavMeshAgent>();
                    if (navigationAgent != null)
                    {
                        componentTags += " [NAVAGENT]";
                        Dictionary<string, object> agentInfo = new Dictionary<string, object>();
                        agentInfo.Add("name", navigationAgent.name);
                        agentInfo.Add("radius", navigationAgent.radius);
                        agentInfo.Add("height", navigationAgent.height);
                        agentInfo.Add("speed", navigationAgent.speed);
                        agentInfo.Add("acceleration", navigationAgent.acceleration);
                        agentInfo.Add("angularSpeed", navigationAgent.angularSpeed);
                        agentInfo.Add("areaMask", navigationAgent.areaMask);
                        agentInfo.Add("autoBraking", navigationAgent.autoBraking);
                        agentInfo.Add("autoTraverseOffMeshLink", navigationAgent.autoTraverseOffMeshLink);
                        agentInfo.Add("avoidancePriority", navigationAgent.avoidancePriority);
                        agentInfo.Add("baseOffset", navigationAgent.baseOffset);
                        agentInfo.Add("obstacleAvoidanceType", navigationAgent.obstacleAvoidanceType.ToString());
                        agentInfo.Add("stoppingDistance", navigationAgent.stoppingDistance);
                        metaData.navAgent = agentInfo;
                    }

                    // Navigation link
                    metaData.meshLink = null;
                    var navigationLink = gameObject.GetComponent<OffMeshLink>();
                    if (navigationLink != null)
                    {
                        componentTags += " [MESHLINK]";
                        Dictionary<string, object> linkInfo = new Dictionary<string, object>();
                        linkInfo.Add("name", navigationLink.name);
                        linkInfo.Add("activated", navigationLink.activated);
                        linkInfo.Add("area", navigationLink.area);
                        linkInfo.Add("autoUpdatePositions", navigationLink.autoUpdatePositions);
                        linkInfo.Add("biDirectional", navigationLink.biDirectional);
                        linkInfo.Add("costOverride", navigationLink.costOverride);
                        linkInfo.Add("occupied", navigationLink.occupied);
                        linkInfo.Add("start", GetTransformPropertyValue(navigationLink.startTransform));
                        linkInfo.Add("end", GetTransformPropertyValue(navigationLink.endTransform));
                        metaData.meshLink = linkInfo;
                    }

                    // Navigation obstacle
                    metaData.meshObstacle = null;
                    var navigationObstacle = gameObject.GetComponent<NavMeshObstacle>();
                    if (navigationObstacle != null)
                    {
                        componentTags += " [MESHOBSTACLE]";
                        Dictionary<string, object> obstacleInfo = new Dictionary<string, object>();
                        obstacleInfo.Add("name", navigationObstacle.name);
                        obstacleInfo.Add("carving", navigationObstacle.carving);
                        obstacleInfo.Add("carveOnlyStationary", navigationObstacle.carveOnlyStationary);
                        obstacleInfo.Add("carvingMoveThreshold", navigationObstacle.carvingMoveThreshold);
                        obstacleInfo.Add("carvingTimeToStationary", navigationObstacle.carvingTimeToStationary);
                        obstacleInfo.Add("shape", navigationObstacle.shape.ToString());
                        obstacleInfo.Add("radius", navigationObstacle.radius);
                        obstacleInfo.Add("center", navigationObstacle.center.ToFloat());
                        obstacleInfo.Add("size", navigationObstacle.size.ToFloat());
                        metaData.meshObstacle = obstacleInfo;
                    }

                    // Tags component
                    var tagsComponent = gameObject.GetComponent<BabylonTagsComponent>();
                    if (tagsComponent != null)
                    {
                        if (!String.IsNullOrEmpty(tagsComponent.babylonTags))
                        {
                            componentTags += (" " + tagsComponent.babylonTags);
                        }
                    }

                    // Script components
                    var gameComponents = gameObject.GetComponents<BabylonScriptComponent>();
                    if (gameComponents != null)
                    {
                        var components = new List<object>();
                        foreach (var gameComponent in gameComponents)
                        {
                            Type componentType = gameComponent.GetType();
                            string componentName = componentType.FullName;
                            var component = new UnityScriptComponent();
                            MonoScript componentScript = MonoScript.FromMonoBehaviour(gameComponent);
                            component.order = MonoImporter.GetExecutionOrder(componentScript);
                            component.name = componentName;
                            component.klass = gameComponent.babylonClass;
                            component.update = (gameComponent.updateOption == BabylonTickOptions.EnableTick);
                            component.controller = (gameComponent is BabylonSceneController);
                            if (component.controller == true)
                            {
                                component.order = -1;
                                if (foundController == false)
                                {
                                    foundController = true;
                                    componentTags += " [CONTROLLER]";
                                    object userInterface = null;
                                    BabylonSceneController scx = (gameComponent as BabylonSceneController);
                                    EmbeddedAsset guiAsset = scx.sceneOptions.graphicUserInterface;
                                    if (guiAsset != null && scx.sceneOptions.userInterfaceMode != BabylonGuiMode.None)
                                    {
                                        userInterface = GetEmbeddedAssetPropertyValue(guiAsset);
                                    }
                                    SceneBuilder.Metadata.properties.Add("autoDraw", scx.sceneOptions.autoDrawInterface);
                                    SceneBuilder.Metadata.properties.Add("interfaceMode", scx.sceneOptions.userInterfaceMode.ToString());
                                    SceneBuilder.Metadata.properties.Add("userInterface", userInterface);
                                    SceneBuilder.Metadata.properties.Add("controllerPresent", true);
                                    SceneBuilder.Metadata.properties.Add("controllerObjectId", metaData.objectId);
                                }
                                else
                                {
                                    Debug.LogError("Duplicate scene controller detected: " + component.name);
                                }
                            }
                            FieldInfo[] componentFields = componentType.GetFields();
                            if (componentFields != null)
                            {
                                foreach (var componentField in componentFields)
                                {
                                    var componentAttribute = (BabylonPropertyAttribute)Attribute.GetCustomAttribute(componentField, typeof(BabylonPropertyAttribute));
                                    if (componentAttribute != null && componentField.Name != "babylonClass")
                                    {
                                        component.properties.Add(componentField.Name, GetComponentPropertyValue(componentField, gameComponent));
                                    }
                                }
                            }
                            gameComponent.OnExportProperties(ref exportOptions, ref exportObject, ref component.properties, OutputPath);
                            components.Add(component);
                        }
                        if (components.Count > 0)
                        {
                            metaData.components = components;
                        }
                    }

                    // Format tags
                    if (!String.IsNullOrEmpty(componentTags))
                    {
                        componentTags = componentTags.Trim();
                    }

                    // Audio sources
                    var audioComponents = gameObject.GetComponents<BabylonAudioSource>();
                    if (audioComponents != null)
                    {
                        foreach (var item in audioComponents)
                        {
                            if (item != null && item.exportAudio && item.sound != null)
                            {
                                string soundPath = AssetDatabase.GetAssetPath(item.sound);
                                if (!String.IsNullOrEmpty(soundPath))
                                {
                                    string soundName = Path.GetFileName(soundPath).Replace(" ", "");
                                    string outputFile = Path.Combine(OutputPath, soundName);
                                    if (File.Exists(soundPath))
                                    {
                                        File.Copy(soundPath, outputFile, true);
                                        var sound = new BabylonSound();
                                        sound.name = soundName;
                                        sound.volume = item.options.volume;
                                        sound.playbackRate = item.options.playbackRate;
                                        sound.autoplay = item.options.autoplay;
                                        sound.loop = item.options.loop;
                                        sound.soundTrackId = item.options.soundTrackId;
                                        sound.spatialSound = item.options.spatialSound;
                                        sound.position = item.options.position.ToFloat();
                                        sound.refDistance = item.options.refDistance;
                                        sound.rolloffFactor = item.options.rolloffFactor;
                                        sound.maxDistance = item.options.maxDistance;
                                        sound.distanceModel = item.options.distanceModel;
                                        sound.panningModel = item.options.panningModel;
                                        sound.isDirectional = item.options.isDirectional;
                                        sound.coneInnerAngle = item.options.coneInnerAngle;
                                        sound.coneOuterAngle = item.options.coneOuterAngle;
                                        sound.coneOuterGain = item.options.coneOuterGain;
                                        sound.localDirectionToMesh = item.options.directionToMesh.ToFloat();
                                        babylonScene.SoundsList.Add(sound);
                                    }
                                    else
                                    {
                                        Debug.LogError("Fail to locate audio file: " + soundPath);
                                    }
                                }
                                else
                                {
                                    Debug.LogError("Null audio clip path for: " + item.sound.name);
                                }
                            }
                        }
                    }

                    // Terrain meshes
                    var terrainMesh = gameObject.GetComponent<Terrain>();
                    if (terrainMesh != null)
                    {
                        ConvertUnityTerrainToBabylon(terrainMesh, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags);
                        continue;
                    }

                    // Collision meshes
                    BabylonMesh collisionMesh = null;
                    var collider = gameObject.GetComponent<Collider>();
                    if (collider != null)
                    {
                        if (collider.enabled)
                        {
                            int segments = 12;
                            BabylonColliderDetail detail = (BabylonColliderDetail)exportationOptions.DefaultColliderDetail;
                            var collisionData = new UnityMetaData();
                            collisionData.objectId = Guid.NewGuid().ToString();
                            collisionData.objectName = gameObject.name + "_Metadata";
                            if (collider is MeshCollider)
                            {
                                var meshCollider = collider as MeshCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[MESHCOLLIDER]";
                                // Generate Mesh Collider Geometry
                                if(!meshCollider.sharedMesh)
                                {
                                    UnityEngine.Debug.LogWarning(meshCollider.gameObject+" has a Mesh Collider component without a mesh");
                                }
                                else
                                {
                                    Tools.GenerateBabylonMeshData(meshCollider.sharedMesh, collisionMesh);
                                }
                                collisionMesh.position = Vector3.zero.ToFloat();
                                collisionMesh.rotation = Vector3.zero.ToFloat();
                                float factorX = 1f, factorY = 1f, factorZ = 1f;
                                if (meshCollider.inflateMesh && meshCollider.skinWidth > 0f)
                                {
                                    Vector3 localScale = gameObject.transform.localScale;
                                    factorX += (meshCollider.skinWidth / localScale.x);
                                    factorY += (meshCollider.skinWidth / localScale.y);
                                    factorZ += (meshCollider.skinWidth / localScale.z);
                                }
                                collisionMesh.scaling = new Vector3(factorX, factorY, factorZ).ToFloat();
                                // Export Mesh Collider Metadata
                                collisionData.tagName = "MeshCollider";
                                collisionData.properties.Add("type", "Mesh");
                                collisionData.properties.Add("convex", meshCollider.convex);
                                collisionData.properties.Add("inflateMesh", meshCollider.inflateMesh);
                                collisionData.properties.Add("skinWidth", meshCollider.skinWidth);
                            }
                            else if (collider is CapsuleCollider)
                            {
                                var capsuleCollider = collider as CapsuleCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[CAPSULECOLLIDER]";
                                switch (detail)
                                {
                                    case BabylonColliderDetail.FullResolution:
                                        segments = 48;
                                        break;
                                    case BabylonColliderDetail.HighResolution:
                                        segments = 32;
                                        break;
                                    case BabylonColliderDetail.MediumResolution:
                                        segments = 24;
                                        break;
                                    case BabylonColliderDetail.LowResolution:
                                        segments = 12;
                                        break;
                                    case BabylonColliderDetail.VeryLowResolution:
                                        segments = 8;
                                        break;
                                    case BabylonColliderDetail.MinimumResolution:
                                        segments = 6;
                                        break;
                                    default:
                                        segments = 12;
                                        break;
                                }
                                // Generate Capsule Collider Geometry
                                Mesh capsuleMesh = Tools.CreateCapsuleMesh(capsuleCollider.height, capsuleCollider.radius, segments);
                                Tools.GenerateBabylonMeshData(capsuleMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = capsuleCollider.center.x;
                                collisionMesh.position[1] = capsuleCollider.center.y;
                                collisionMesh.position[2] = capsuleCollider.center.z;
                                collisionMesh.rotation = new float[3];
                                collisionMesh.rotation[0] = (capsuleCollider.direction == 2) ? 90f * (float)Math.PI / 180f : 0f;
                                collisionMesh.rotation[1] = 0f;
                                collisionMesh.rotation[2] = (capsuleCollider.direction == 0) ? 90f * (float)Math.PI / 180f : 0f;
                                collisionMesh.scaling = new Vector3(1, 1, 1).ToFloat();
                                // Export Capsule Collider Metadata
                                collisionData.tagName = "CapsuleCollider";
                                collisionData.properties.Add("type", "Capsule");
                                collisionData.properties.Add("center", capsuleCollider.center.ToFloat());
                                collisionData.properties.Add("radius", capsuleCollider.radius);
                                collisionData.properties.Add("height", capsuleCollider.height);
                                collisionData.properties.Add("direction", capsuleCollider.direction);
                            }
                            else if (collider is SphereCollider)
                            {
                                var sphereCollider = collider as SphereCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[SPHERECOLLIDER]";
                                switch (detail)
                                {
                                    case BabylonColliderDetail.FullResolution:
                                        segments = 48;
                                        break;
                                    case BabylonColliderDetail.HighResolution:
                                        segments = 32;
                                        break;
                                    case BabylonColliderDetail.MediumResolution:
                                        segments = 24;
                                        break;
                                    case BabylonColliderDetail.LowResolution:
                                        segments = 12;
                                        break;
                                    case BabylonColliderDetail.VeryLowResolution:
                                        segments = 8;
                                        break;
                                    case BabylonColliderDetail.MinimumResolution:
                                        segments = 6;
                                        break;
                                    default:
                                        segments = 12;
                                        break;
                                }
                                // Generate Sphere Collider Geometry
                                Mesh sphereMesh = Tools.CreateSphereMesh(sphereCollider.radius, segments);
                                Tools.GenerateBabylonMeshData(sphereMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = sphereCollider.center.x;
                                collisionMesh.position[1] = sphereCollider.center.y;
                                collisionMesh.position[2] = sphereCollider.center.z;
                                collisionMesh.rotation = Vector3.zero.ToFloat();
                                collisionMesh.scaling = new Vector3(1f, 1f, 1f).ToFloat();
                                // Export Sphere Collider Metadata
                                collisionData.tagName = "SphereCollider";
                                collisionData.properties.Add("type", "Sphere");
                                collisionData.properties.Add("center", sphereCollider.center.ToFloat());
                                collisionData.properties.Add("radius", sphereCollider.radius);
                            }
                            else if (collider is WheelCollider)
                            {
                                var wheelCollider = collider as WheelCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[WHEELCOLLIDER]";
                                switch (detail)
                                {
                                    case BabylonColliderDetail.FullResolution:
                                        segments = 128;
                                        break;
                                    case BabylonColliderDetail.HighResolution:
                                        segments = 64;
                                        break;
                                    case BabylonColliderDetail.MediumResolution:
                                        segments = 48;
                                        break;
                                    case BabylonColliderDetail.LowResolution:
                                        segments = 32;
                                        break;
                                    case BabylonColliderDetail.VeryLowResolution:
                                        segments = 24;
                                        break;
                                    case BabylonColliderDetail.MinimumResolution:
                                        segments = 16;
                                        break;
                                    default:
                                        segments = 32;
                                        break;
                                }
                                // Generate Wheel Collider Geometry
                                Mesh wheelMesh = Tools.CreateWheelMesh(wheelCollider.suspensionDistance, wheelCollider.radius, segments);
                                Tools.GenerateBabylonMeshData(wheelMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = wheelCollider.center.x;
                                collisionMesh.position[1] = wheelCollider.center.y;
                                collisionMesh.position[2] = wheelCollider.center.z;
                                collisionMesh.rotation = new float[3];
                                collisionMesh.rotation[0] = 0f;
                                collisionMesh.rotation[1] = 0f;
                                collisionMesh.rotation[2] = 90f * (float)Math.PI / 180;
                                collisionMesh.scaling = new Vector3(1f, 1f, 1f).ToFloat();
                                // Export Wheel Collider Metadata
                                collisionData.tagName = "WheelCollider";
                                collisionData.properties.Add("type", "Wheel");
                                collisionData.properties.Add("center", wheelCollider.center.ToFloat());
                                collisionData.properties.Add("radius", wheelCollider.radius);
                            }
                            else if (collider is BoxCollider)
                            {
                                var boxCollider = collider as BoxCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[BOXCOLLIDER]";
                                // Generate Box Collider Geometry
                                Mesh boxMesh = Tools.CreateBoxMesh(boxCollider.size.x, boxCollider.size.y, boxCollider.size.z);
                                Tools.GenerateBabylonMeshData(boxMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = boxCollider.center.x;
                                collisionMesh.position[1] = boxCollider.center.y;
                                collisionMesh.position[2] = boxCollider.center.z;
                                collisionMesh.rotation = Vector3.zero.ToFloat();
                                collisionMesh.scaling = new Vector3(1f, 1f, 1f).ToFloat();
                                // Export Box Collider Metadata
                                collisionData.tagName = "BoxCollider";
                                collisionData.properties.Add("type", "Box");
                                collisionData.properties.Add("center", boxCollider.center.ToFloat());
                                collisionData.properties.Add("size", boxCollider.size.ToFloat());
                            }
                            if (collisionMesh != null)
                            {
                                collisionMesh.id = Guid.NewGuid().ToString();
                                collisionMesh.name = gameObject.name + "_Collider";
                                // Default Check Collisions False
                                collisionMesh.checkCollisions = false;
                                collisionMesh.isVisible = false;
                                collisionData.properties.Add("parrentId", metaData.objectId);
                                collisionData.properties.Add("transform", GetTransformPropertyValue(gameObject.transform));
                                collisionMesh.metadata = collisionData;
                                babylonScene.MeshesList.Add(collisionMesh);
                                SceneBuilder.Metadata.properties["hasCollisionMeshes"] = true;
                            }
                        }
                    }

                    // Static meshes
                    var meshFilter = gameObject.GetComponent<MeshFilter>();
                    if (meshFilter != null)
                    {
                        ConvertUnityMeshToBabylon(meshFilter.sharedMesh, meshFilter.transform, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags, collisionMesh, collider);
                        continue;
                    }

                    // Skinned meshes
                    var skinnedMesh = gameObject.GetComponent<SkinnedMeshRenderer>();
                    if (skinnedMesh != null)
                    {
                        var babylonMesh = ConvertUnityMeshToBabylon(skinnedMesh.sharedMesh, skinnedMesh.transform, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags, collisionMesh, collider);
                        var skeleton = ConvertUnitySkeletonToBabylon(skinnedMesh.bones, skinnedMesh.sharedMesh.bindposes, skinnedMesh.transform, gameObject, progress);
                        babylonMesh.skeletonId = skeleton.id;
                        ExportSkeletonAnimation(skinnedMesh, babylonMesh, skeleton);
                        continue;
                    }

                    // Scene lights
                    var light = gameObject.GetComponent<Light>();
                    if (light != null)
                    {
                        ConvertUnityLightToBabylon(light, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags);
                        continue;
                    }

                    // Scene cameras
                    var camera = gameObject.GetComponent<Camera>();
                    if (camera != null)
                    {
                        ConvertUnityCameraToBabylon(camera, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags);
                        if (SceneController != null && SceneController.skyboxOptions.exportSkybox)
                        {
                            ConvertUnitySkyboxToBabylon(camera, progress);
                        }
                        continue;
                    }

                    // Empty objects
                    ConvertUnityEmptyObjectToBabylon(gameObject, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags, collisionMesh, collider);
                }

                // Materials
                foreach (var mat in materialsDictionary)
                {
                    babylonScene.MaterialsList.Add(mat.Value);
                }
                foreach (var multiMat in multiMatDictionary)
                {
                    babylonScene.MultiMaterialsList.Add(multiMat.Value);
                }

                // Collisions
                if (exportationOptions.ExportCollisions)
                {
                    babylonScene.workerCollisions = exportationOptions.WorkerCollisions;
                    if (SceneController != null) {
                        babylonScene.gravity = SceneController.sceneOptions.defaultGravity.ToFloat();
                    }
                }

                // Babylon Physics
                if (exportationOptions.ExportPhysics)
                {
                    babylonScene.physicsEnabled = true;
                    if (SceneController != null) {
                        babylonScene.physicsGravity = SceneController.sceneOptions.defaultGravity.ToFloat();
                    }
                }

                // Scene Controller
                if (SceneController != null)
                {
                    Color ambientColor = SceneController.sceneOptions.ambientColor;
                    float ambientLevel = SceneController.lightingOptions.lightLevel;
                    Color ambientSpecular = SceneController.lightingOptions.specularColor;
                    babylonScene.autoClear = SceneController.sceneOptions.autoClear;
                    int fogmode = 0;
                    if (RenderSettings.fog)
                    {
                        switch (RenderSettings.fogMode)
                        {
                            case FogMode.Exponential:
                                fogmode = 1;
                                break;
                            case FogMode.ExponentialSquared:
                                fogmode = 2;
                                break;
                            case FogMode.Linear:
                                fogmode = 3;
                                break;
                        }
                    }
                    babylonScene.fogMode = fogmode;
                    babylonScene.fogDensity = RenderSettings.fogDensity;
                    babylonScene.fogColor = RenderSettings.fogColor.ToFloat();
                    babylonScene.fogStart = RenderSettings.fogStartDistance;
                    babylonScene.fogEnd = RenderSettings.fogEndDistance;
                    if (exportationOptions.DefaultLightmapMode != (int)BabylonLightmapMode.FullLightBaking && SceneController.lightingOptions.lightMode == BabylonAmbientLighting.UnityAmbientLighting)
                    {
                        var ambientLight = new BabylonLight
                        {
                            name = "Ambient Light",
                            id = Guid.NewGuid().ToString(),
                            parentId = null,
                            metadata = null,
                            position = null,
                            exponent = 1.0f,
                            angle = 0.0f,
                            type = 3
                        };
                        var ambientDirection = new Vector3(0.0f, 1.0f, 0.0f);
                        Color ambientDiffuse = (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Skybox) ? RenderSettings.ambientSkyColor : RenderSettings.ambientLight;
                        ambientLight.intensity = RenderSettings.ambientIntensity * ambientLevel;
                        ambientLight.direction = ambientDirection.ToFloat(); ;
                        ambientLight.diffuse = ambientDiffuse.ToFloat();
                        ambientLight.specular = ambientSpecular.ToFloat();
                        ambientLight.groundColor = RenderSettings.ambientGroundColor.ToFloat();
                        babylonScene.ambientColor = ambientColor.ToFloat();
                        babylonScene.LightsList.Add(ambientLight);
                        ExporterWindow.ReportProgress(0, "Exporting ambient light intensity at: " + ambientLight.intensity.ToString());
                    }
                    if (SceneController.sceneOptions.navigationMesh == BabylonNavigationMesh.EnableNavigation)
                    {
                        ExporterWindow.ReportProgress(0, "Parsing scene navigation mesh...");
                        NavMeshTriangulation triangulatedNavMesh = NavMesh.CalculateTriangulation();
                        if (triangulatedNavMesh.vertices != null && triangulatedNavMesh.vertices.Length > 0 && triangulatedNavMesh.indices != null && triangulatedNavMesh.indices.Length > 0)
                        {
                            int vertexCount = triangulatedNavMesh.vertices.Length;
                            if (vertexCount <= SceneBuilder.MAX_VERTEX_COUNT)
                            {
                                ExporterWindow.ReportProgress(0, "Generating navigation mesh vertices: " + vertexCount.ToString());
                                var navData = new UnityMetaData();
                                navData.type = "NavMesh";
                                navData.objectId = Guid.NewGuid().ToString();
                                navData.objectName = "Navigation_Mesh";
                                var areaTable = new List<object>();
                                string[] areaNavigation = GameObjectUtility.GetNavMeshAreaNames();
                                foreach (string areaName in areaNavigation)
                                {
                                    var bag = new Dictionary<string, object>();
                                    int areaIndex = NavMesh.GetAreaFromName(areaName);
                                    float areaCost = NavMesh.GetAreaCost(areaIndex);
                                    bag.Add("index", areaIndex);
                                    bag.Add("area", areaName);
                                    bag.Add("cost", areaCost);
                                    areaTable.Add(bag);
                                }
                                navData.properties.Add("table", areaTable);
                                navData.properties.Add("areas", triangulatedNavMesh.areas);

                                Mesh mesh = new Mesh();
                                mesh.name = "sceneNavigationMesh";
                                mesh.vertices = triangulatedNavMesh.vertices;
                                mesh.triangles = triangulatedNavMesh.indices;
                                mesh.RecalculateNormals();

                                BabylonMesh babylonMesh = new BabylonMesh();
                                babylonMesh.tags = "[NAVMESH]";
                                babylonMesh.metadata = navData;
                                babylonMesh.name = mesh.name;
                                babylonMesh.id = Guid.NewGuid().ToString();
                                babylonMesh.parentId = null;
                                babylonMesh.position = Vector3.zero.ToFloat();
                                babylonMesh.rotation = Vector3.zero.ToFloat();
                                babylonMesh.scaling = new Vector3(1, 1, 1).ToFloat();
                                babylonMesh.isVisible = false;
                                babylonMesh.visibility = 0.75f;
                                babylonMesh.checkCollisions = false;
                                Tools.GenerateBabylonMeshData(mesh, babylonMesh);
                                babylonScene.MeshesList.Add(babylonMesh);
                                SceneBuilder.Metadata.properties["hasNavigationMesh"] = true;
                            }
                            else
                            {
                                UnityEngine.Debug.LogError("Navigation mesh exceeds max (65000) vertex limit: " + vertexCount.ToString());
                            }
                        }
                    }
                    if (SceneController.sceneOptions.particleSystems)
                    {
                        if (particleSystems != null && particleSystems.Count > 0)
                        {
                            babylonScene.particleSystems = particleSystems.ToArray();
                        }
                    }
                    if (SceneController.sceneOptions.lensFlareSystems)
                    {
                        if (lensFlareSystems != null && lensFlareSystems.Count > 0)
                        {
                            var lfs_buffer = new List<BabylonLensFlareSystem>();
                            foreach (var ulfs in lensFlareSystems)
                            {
                                var lfs = new BabylonLensFlareSystem();
                                lfs.borderLimit = ulfs.borderLimit;
                                lfs.emitterId = ulfs.emitterId;
                                var lfx = new List<BabylonLensFlare>();
                                foreach (var ulf in ulfs.lensFlares)
                                {
                                    var lf = new BabylonLensFlare();
                                    lf.textureName = ulf.textureName;
                                    lf.position = ulf.position;
                                    lf.color = ulf.color;
                                    lf.size = ulf.size;
                                    lfx.Add(lf);
                                }
                                lfs.flares = lfx.ToArray();
                                lfs_buffer.Add(lfs);
                            }
                            babylonScene.lensFlareSystems = lfs_buffer.ToArray();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
            }
            finally
            {
                babylonScene.metadata = SceneBuilder.Metadata;
            }
        }
        private void ConvertUnitySkyboxToBabylon(Camera camera, float progress)
        {
            // Skybox
            bool png = (exportationOptions.DefaultImageFormat == (int)BabylonImageFormat.PNG);
            string fext = (png == true) ? ".png" : ".jpg";

            if ((camera.clearFlags & CameraClearFlags.Skybox) == CameraClearFlags.Skybox)
            {
                if (RenderSettings.skybox != null)
                {
                    BabylonTexture skytex = null;
                    if (RenderSettings.skybox.shader.name == "Skybox/Cubemap")
                    {
                        var cubeMap = RenderSettings.skybox.GetTexture("_Tex") as Cubemap;
                        if (cubeMap != null)
                        {
                            var srcTexturePath = AssetDatabase.GetAssetPath(cubeMap);
                            if (srcTexturePath.EndsWith(".hdr", StringComparison.OrdinalIgnoreCase))
                            {
                                var hdr = new BabylonHDRCubeTexture();
                                hdr.size = cubeMap.width;
                                skytex = hdr;
                                CopyTextureCube(String.Format("{0}Skybox.hdr", SceneName), cubeMap, skytex, true);
                            }
                            else
                            {
                                skytex = new BabylonTexture();
                                CopyTextureCube(String.Format("{0}Skybox.hdr", SceneName), cubeMap, skytex, false);
                                if (png) skytex.extensions = new string[] { "_px.png", "_py.png", "_pz.png", "_nx.png", "_ny.png", "_nz.png" };
                            }
                        }
                    }
                    else if (RenderSettings.skybox.shader.name == "Skybox/6 Sided")
                    {
                        var frontTexture = RenderSettings.skybox.GetTexture("_FrontTex") as Texture2D;
                        var backTexture = RenderSettings.skybox.GetTexture("_BackTex") as Texture2D;
                        var leftTexture = RenderSettings.skybox.GetTexture("_LeftTex") as Texture2D;
                        var rightTexture = RenderSettings.skybox.GetTexture("_RightTex") as Texture2D;
                        var upTexture = RenderSettings.skybox.GetTexture("_UpTex") as Texture2D;
                        var downTexture = RenderSettings.skybox.GetTexture("_DownTex") as Texture2D;
                        if (frontTexture != null && backTexture != null && leftTexture != null && rightTexture != null && upTexture != null && downTexture != null)
                        {
                            skytex = new BabylonTexture();
                            skytex.name = String.Format("{0}Skybox", SceneName);

                            var frontTextureName = String.Format("{0}_pz{1}", skytex.name, fext);
                            var frontTexturePath = Path.Combine(babylonScene.OutputPath, frontTextureName);
                            CopyTextureFace(frontTexturePath, frontTextureName, frontTexture);

                            var backTextureName = String.Format("{0}_nz{1}", skytex.name, fext);
                            var backTexturePath = Path.Combine(babylonScene.OutputPath, backTextureName);
                            CopyTextureFace(backTexturePath, backTextureName, backTexture);

                            var leftTextureName = String.Format("{0}_px{1}", skytex.name, fext);
                            var leftTexturePath = Path.Combine(babylonScene.OutputPath, leftTextureName);
                            CopyTextureFace(leftTexturePath, leftTextureName, leftTexture);

                            var rightTextureName = String.Format("{0}_nx{1}", skytex.name, fext);
                            var rightTexturePath = Path.Combine(babylonScene.OutputPath, rightTextureName);
                            CopyTextureFace(rightTexturePath, rightTextureName, rightTexture);

                            var upTextureName = String.Format("{0}_py{1}", skytex.name, fext);
                            var upTexturePath = Path.Combine(babylonScene.OutputPath, upTextureName);
                            CopyTextureFace(upTexturePath, upTextureName, upTexture);

                            var downTextureName = String.Format("{0}_ny{1}", skytex.name, fext);
                            var downTexturePath = Path.Combine(babylonScene.OutputPath, downTextureName);
                            CopyTextureFace(downTexturePath, downTexturePath, downTexture);
                            if (png) skytex.extensions = new string[] { "_px.png", "_py.png", "_pz.png", "_nx.png", "_ny.png", "_nz.png" };
                        }
                    }
                    if (skytex != null)
                    {
                        skytex.isCube = true;
                        skytex.coordinatesMode = 5;
                        skytex.level = (SceneController != null) ? SceneController.skyboxOptions.lightIntensity : 1.0f;

                        var skybox = new BabylonMesh();
                        skybox.name = "sceneSkyboxMesh";
                        skybox.id = Guid.NewGuid().ToString();
                        skybox.indices = new[] { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 };
                        skybox.positions = new[] { 50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f };
                        skybox.uvs = new[] { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
                        skybox.normals = new[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0, 0f };

                        if (SceneController != null)
                        {
                            Color skycolor = SceneController.skyboxOptions.albedoColor;
                            Color skyreflect = SceneController.skyboxOptions.reflectivityColor;
                            var skyboxMaterial = new BabylonPBRMaterial()
                            {
                                name = "sceneSkyboxMaterial",
                                id = Guid.NewGuid().ToString(),
                                albedo = skycolor.ToFloat(),
                                reflectivity = skyreflect.ToFloat(),
                                microSurface = SceneController.skyboxOptions.microSurface,
                                cameraContrast = SceneController.skyboxOptions.cameraContrast,
                                cameraExposure = SceneController.skyboxOptions.cameraExposure,
                                directIntensity = SceneController.skyboxOptions.directIntensity,
                                emissiveIntensity = SceneController.skyboxOptions.emissiveIntensity,
                                specularIntensity = SceneController.skyboxOptions.specularIntensity,
                                environmentIntensity = SceneController.skyboxOptions.environmentIntensity
                            };

                            skyboxMaterial.reflectionTexture = skytex;
                            skyboxMaterial.backFaceCulling = false;
                            skyboxMaterial.disableLighting = true;
                            skybox.materialId = skyboxMaterial.id;
                            skybox.infiniteDistance = true;

                            babylonScene.MeshesList.Add(skybox);
                            babylonScene.MaterialsList.Add(skyboxMaterial);
                            babylonScene.AddTextureCube("sceneSkyboxMaterial");
                        }
                    }
                }
            }
        }
        private BabylonMesh ExportMesh(Node meshNode, BabylonScene babylonScene, CancellationToken token)
        {
            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;
            babylonMesh.showBoundingBox = meshNode._Node.GetBoolProperty("babylonjs_showboundingbox");
            babylonMesh.showSubMeshesBoundingBox = meshNode._Node.GetBoolProperty("babylonjs_showsubmeshesboundingbox");

            // 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.pivotMatrix = 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;

                var noOptimize = meshNode._Node.GetBoolProperty("babylonjs_nooptimize");

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

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

                // 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;
                            }
                        }
                    }
                    if (indexCount != 0)
                    {

                        subMesh.indexCount = indexCount;
                        subMesh.verticesStart = minVertexIndex;
                        subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                        indexStart += indexCount;

                        subMeshes.Add(subMesh);
                    }
                    if (token.IsCancellationRequested) token.ThrowIfCancellationRequested();
                }
                babylonMesh.subMeshes = subMeshes.ToArray();


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


            // Animations
            var animations = new List<BabylonAnimation>();
            ExportVector3Animation("position", animations, key =>
            {
                var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());
                return worldMatrix.Trans.ToArraySwitched();
            });

            ExportQuaternionAnimation("rotationQuaternion", animations, key =>
            {
                var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());

                var affineParts = Loader.Global.AffineParts.Create();
                Loader.Global.DecompAffine(worldMatrix, affineParts);

                return affineParts.Q.ToArray();
            });

            ExportVector3Animation("scaling", animations, key =>
            {
                var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());

                var affineParts = Loader.Global.AffineParts.Create();
                Loader.Global.DecompAffine(worldMatrix, affineParts);

                return affineParts.K.ToArraySwitched();
            });

            ExportFloatAnimation("visibility", animations, key => new []{meshNode._Node.GetVisibility(key, Interval.Forever._IInterval)});


            babylonMesh.animations = animations.ToArray();

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

            babylonScene.MeshesList.Add(babylonMesh);

            return babylonMesh;
        }