private BabylonShadowGenerator ExportShadowGenerator(IINode lightNode, BabylonScene babylonScene)
        {
            var maxLight = (lightNode.ObjectRef as ILightObject);
            var babylonShadowGenerator = new BabylonShadowGenerator();

            RaiseMessage("Exporting shadow map", 2);

            babylonShadowGenerator.lightId = lightNode.GetGuid().ToString();

            babylonShadowGenerator.mapSize = maxLight.GetMapSize(0, Tools.Forever);

            babylonShadowGenerator.bias = lightNode.GetFloatProperty("babylonjs_shadows_bias", 0.00005f);
            babylonShadowGenerator.forceBackFacesOnly = lightNode.GetBoolProperty("babylonjs_forcebackfaces");

            var shadowsType = lightNode.GetStringProperty("babylonjs_shadows_type", "Blurred Variance");

            switch (shadowsType)
            {
                case "Hard shadows":
                    break;
                case "Poisson Sampling":
                    babylonShadowGenerator.usePoissonSampling = true;
                    break;
                case "Variance":
                    babylonShadowGenerator.useVarianceShadowMap = true;
                    break;
                case"Blurred Variance":
                    babylonShadowGenerator.useBlurVarianceShadowMap = true;
                    babylonShadowGenerator.blurScale = lightNode.GetFloatProperty("babylonjs_shadows_blurScale", 2);
                    babylonShadowGenerator.blurBoxOffset = lightNode.GetFloatProperty("babylonjs_shadows_blurBoxOffset", 1);
                    break;
            }

            
            var list = new List<string>();

            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
            var checkExclusionList = maxLight.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST 

            foreach (var meshNode in Loader.Core.RootNode.NodesListBySuperClass(SClass_ID.Geomobject))
            {
#if MAX2017
                if (meshNode.CastShadows)
#else
                if (meshNode.CastShadows == 1)
#endif
                {
                    var inList = maxLight.ExclList.FindNode(meshNode) != -1;

                    if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion))
                    {
                        list.Add(meshNode.GetGuid().ToString());
                    }
                }
            }
            babylonShadowGenerator.renderList = list.ToArray();

            babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator);
            return babylonShadowGenerator;
        }
示例#2
0
        private void OnNodeAdded(IntPtr param0, IntPtr param1)
        {
            try
            {
                INotifyInfo obj = Loader.Global.NotifyInfo.Marshal(param1);

                IINode n = (IINode)obj.CallParam;
                //todo replace this with something like isXREFNODE
                //to have a distinction between added xref node and max node
                string guid = n.GetStringProperty("babylonjs_GUID", string.Empty);
                if (string.IsNullOrEmpty(guid))
                {
                    n.GetGuid(); // force to assigne a new guid if not exist yet for this node
                }

                IIContainerObject contaner = Loader.Global.ContainerManagerInterface.IsContainerNode(n);
                if (contaner != null)
                {
                    // a generic operation on a container is done (open/inherit)
                    contaner.ResolveContainer();
                }
            }
            catch
            {
                // Fails silently
            }
        }
        private BabylonShadowGenerator ExportShadowGenerator(IINode lightNode, BabylonScene babylonScene)
        {
            var maxLight = (lightNode.ObjectRef as ILightObject);
            var babylonShadowGenerator = new BabylonShadowGenerator();

            RaiseMessage("Exporting shadow map", 2);

            babylonShadowGenerator.lightId = lightNode.GetGuid().ToString();

            babylonShadowGenerator.mapSize            = maxLight.GetMapSize(0, Tools.Forever);
            babylonShadowGenerator.usePoissonSampling = maxLight.AbsMapBias >= 1;

            var list = new List <string>();

            var inclusion          = maxLight.ExclList.TestFlag(1); //NT_INCLUDE
            var checkExclusionList = maxLight.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST

            foreach (var meshNode in Loader.Core.RootNode.NodesListBySuperClass(SClass_ID.Geomobject))
            {
                if (meshNode.CastShadows == 1)
                {
                    var inList = maxLight.ExclList.FindNode(meshNode) != -1;

                    if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion))
                    {
                        list.Add(meshNode.GetGuid().ToString());
                    }
                }
            }
            babylonShadowGenerator.renderList = list.ToArray();

            babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator);
            return(babylonShadowGenerator);
        }
        private BabylonShadowGenerator ExportShadowGenerator(IINode lightNode, BabylonScene babylonScene)
        {
            var maxLight = (lightNode.ObjectRef as ILightObject);
            var babylonShadowGenerator = new BabylonShadowGenerator();

            RaiseMessage("Exporting shadow map", 2);

            babylonShadowGenerator.lightId = lightNode.GetGuid().ToString();

            babylonShadowGenerator.mapSize = maxLight.GetMapSize(0, Tools.Forever);
            babylonShadowGenerator.usePoissonSampling = maxLight.AbsMapBias >= 1;

            var list = new List<string>();

            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
            var checkExclusionList = maxLight.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST 

            foreach (var meshNode in Loader.Core.RootNode.NodesListBySuperClass(SClass_ID.Geomobject))
            {
                if (meshNode.CastShadows == 1)
                {
                    var inList = maxLight.ExclList.FindNode(meshNode) != -1;

                    if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion))
                    {
                        list.Add(meshNode.GetGuid().ToString());
                    }
                }
            }
            babylonShadowGenerator.renderList = list.ToArray();

            babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator);
            return babylonShadowGenerator;
        }
        private BabylonShadowGenerator ExportShadowGenerator(IINode lightNode, BabylonScene babylonScene)
        {
            var maxLight = (lightNode.ObjectRef as ILightObject);
            var babylonShadowGenerator = new BabylonShadowGenerator();

            RaiseMessage("Exporting shadow map", 2);

            babylonShadowGenerator.lightId = lightNode.GetGuid().ToString();

            babylonShadowGenerator.mapSize = maxLight.GetMapSize(0, Tools.Forever);

            babylonShadowGenerator.bias = lightNode.GetFloatProperty("babylonjs_shadows_bias", 0.00005f);
            babylonShadowGenerator.forceBackFacesOnly = lightNode.GetBoolProperty("babylonjs_forcebackfaces");

            var shadowsType = lightNode.GetStringProperty("babylonjs_shadows_type", "Blurred Variance");

            switch (shadowsType)
            {
            case "Hard shadows":
                break;

            case "Poisson Sampling":
                babylonShadowGenerator.usePoissonSampling = true;
                break;

            case "Variance":
                babylonShadowGenerator.useVarianceShadowMap = true;
                break;

            case "Blurred Variance":
                babylonShadowGenerator.useBlurVarianceShadowMap = true;
                babylonShadowGenerator.blurScale     = lightNode.GetFloatProperty("babylonjs_shadows_blurScale", 2);
                babylonShadowGenerator.blurBoxOffset = lightNode.GetFloatProperty("babylonjs_shadows_blurBoxOffset", 1);
                break;
            }


            var list = new List <string>();

            var inclusion          = maxLight.ExclList.TestFlag(1); //NT_INCLUDE
            var checkExclusionList = maxLight.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST

            foreach (var meshNode in Loader.Core.RootNode.NodesListBySuperClass(SClass_ID.Geomobject))
            {
                if (meshNode.CastShadows == 1)
                {
                    var inList = maxLight.ExclList.FindNode(meshNode) != -1;

                    if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion))
                    {
                        list.Add(meshNode.GetGuid().ToString());
                    }
                }
            }
            babylonShadowGenerator.renderList = list.ToArray();

            babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator);
            return(babylonShadowGenerator);
        }
示例#6
0
        public static List <Guid> ToGuids(this IList <uint> handles)
        {
            List <Guid> guids = new List <Guid>();

            foreach (uint handle in handles)
            {
                IINode node = Loader.Core.GetINodeByHandle(handle);
                Guid   guid = node.GetGuid();
                guids.Add(guid);
            }
            return(guids);
        }
示例#7
0
        private int ParseNewProperties(string guidPropPart)
        {
            int numFailed = 0;

            string[] guidProperties = guidPropPart.Split(s_GUIDTypeSeparator);
            string[] nodes          = new string[0];
            string[] materials      = new string[0];
            if (!string.IsNullOrWhiteSpace(guidProperties[0]))
            {
                nodes = guidProperties[0].Split(s_PropertySeparator);
            }

            if (!string.IsNullOrWhiteSpace(guidProperties[1]))
            {
                materials = guidProperties[1].Split(s_PropertySeparator);
            }

            int numNodeGUIDs = nodes.Length;
            int numMatGUIDs  = materials.Length;


            for (int i = 0; i < numNodeGUIDs; ++i)
            {
                Guid guid;
                if (!Guid.TryParse(nodes[i], out guid))
                {
                    uint id;
                    if (!uint.TryParse(nodes[i], out id))
                    {
                        ++numFailed;
                        continue;
                    }
                    //node is serialized in the old way ,force the reassignation of a new Guid on
                    IINode node = Loader.Core.GetINodeByHandle(id);
                    if (node != null)
                    {
                        guid = node.GetGuid();
                    }
                }
                nodeGuids.Add(guid);
            }

            for (int i = 0; i < numMatGUIDs; ++i)
            {
                Guid guid;
                if (Guid.TryParse(materials[i], out guid))
                {
                    materialsGuids.Add(guid);
                }
            }

            return(numFailed);
        }
示例#8
0
 private void OnNodeDeleted(IntPtr objPtr, INotifyInfo infoPtr)
 {
     try
     {
         IINode n = (IINode)infoPtr.CallParam;
         Tools.guids.Remove(n.GetGuid());
     }
     catch
     {
         // Fails silently
     }
 }
示例#9
0
        private void OnNodeDeleted(IntPtr objPtr, IntPtr param1)
        {
            try
            {
                INotifyInfo obj = Loader.Global.NotifyInfo.Marshal(param1);

                IINode n = (IINode)obj.CallParam;
                Tools.guids.Remove(n.GetGuid());
            }
            catch
            {
                // Fails silently
            }
        }
        public void RemoveNodeFromAnimationGroup(AnimationGroup info, uint nodeHandle)
        {
            if (info == null)
                return;

            IINode node = Loader.Core.GetINodeByHandle(nodeHandle);
            if (node == null)
            {
                return;
            }

            List<Guid> newGuids = info.NodeGuids.ToList();
            newGuids.Remove(node.GetGuid());
            info.NodeGuids = newGuids;
            info.SaveToData();
        }
示例#11
0
        public void HighlightAnimationGroupOfSelection()
        {
            AnimationListBox.ClearSelected();
            IINode node = Loader.Core.GetSelNode(0);

            if (node != null)
            {
                for (int i = 0; i < animationGroups.Count; i++)
                {
                    if (animationGroups[i].NodeGuids.Contains(node.GetGuid()))
                    {
                        AnimationListBox.SelectedItem = animationGroups[i];
                    }
                }
            }
        }
示例#12
0
        private void OnNodeAdded(IntPtr objPtr, INotifyInfo infoPtr)
        {
            try
            {
                IINode n = (IINode)infoPtr.CallParam;
                n.GetGuid(); // force to assigne a new guid if not exist yet for this node

                IIContainerObject contaner = Loader.Global.ContainerManagerInterface.IsContainerNode(n);
                if (contaner != null)
                {
                    // a generic operation on a container is done (open/inherit)
                    contaner.ResolveContainer();
                }
            }
            catch
            {
                // Fails silently
            }
        }
示例#13
0
        public void AutoAssignLodInAnimationGroup()
        {
            AnimationGroupList animationGroupList = new AnimationGroupList();

            animationGroupList.LoadFromData();

            var nodes = Loader.Core.RootNode.NodeTree();

            List <IINode> nodeToAdd = new List <IINode>();

            foreach (AnimationGroup anim in animationGroupList)
            {
                nodeToAdd.Clear();
                foreach (Guid guid in anim.NodeGuids)
                {
                    IINode n = Tools.GetINodeByGuid(guid);
                    if (n == null)
                    {
                        continue;
                    }
                    if (!Regex.IsMatch(n.Name, "(?i)x[0-9]_"))
                    {
                        continue;
                    }
                    string noLodName = n.Name.Substring(3);
                    foreach (IINode node in nodes)
                    {
                        if (Regex.IsMatch(node.Name, $"(?i)x[0-9]_{noLodName}$"))
                        {
                            nodeToAdd.Add(node);
                        }
                    }
                }

                foreach (IINode n in nodeToAdd)
                {
                    List <Guid> newGuids = anim.NodeGuids.ToList();
                    newGuids.Add(n.GetGuid());
                    anim.NodeGuids = newGuids;
                }
                anim.SaveToData();
            }
        }
示例#14
0
        private void OnNodeAdded(IntPtr param0, IntPtr param1)
        {
            try
            {
                INotifyInfo obj = Loader.Global.NotifyInfo.Marshal(param1);

                IINode n = (IINode)obj.CallParam;
                n.GetGuid(); // force to assigne a new guid if not exist yet for this node

                IIContainerObject contaner = Loader.Global.ContainerManagerInterface.IsContainerNode(n);
                if (contaner != null)
                {
                    // a generic operation on a container is done (open/inherit)
                    Tools.guids = new Dictionary <Guid, IAnimatable>();
                }
            }
            catch
            {
                // Fails silently
            }
        }
示例#15
0
        private int ParseOldProperties(string guidPropPart)
        {
            IsOldType = true; //force it to be saved in the new format
            string[] properties = guidPropPart.Split(s_PropertySeparator);

            int numFailed = 0;

            int numNodeIDs = properties.Length;

            if (nodeGuids.Capacity < numNodeIDs)
            {
                nodeGuids.Capacity = numNodeIDs;
            }


            for (int i = 0; i < numNodeIDs; ++i)
            {
                Guid guid;
                if (!Guid.TryParse(properties[i], out guid))
                {
                    uint id;
                    if (!uint.TryParse(properties[i], out id))
                    {
                        ++numFailed;
                        continue;
                    }
                    //node is serialized in the old way ,force the reassignation of a new Guid on
                    IINode node = Loader.Core.GetINodeByHandle(id);
                    if (node != null)
                    {
                        guid = node.GetGuid();
                    }
                }
                nodeGuids.Add(guid);
            }

            return(numFailed);
        }
        private void ExportAnimationGroups(GLTF gltf, BabylonScene babylonScene)
        {
            AnimationGroupList animationList = new AnimationGroupList();

            animationList.LoadFromData();

            gltf.AnimationsList.Clear();
            gltf.AnimationsList.Capacity = Math.Max(gltf.AnimationsList.Capacity, animationList.Count);

            foreach (AnimationGroup animGroup in animationList)
            {
                GLTFAnimation gltfAnimation = new GLTFAnimation();
                gltfAnimation.name = animGroup.Name;
                foreach (uint nodeHandle in animGroup.NodeHandles)
                {
                    // todo: make something a little more efficient..
                    IINode      maxNode     = Loader.Core.RootNode.FindChildNode(nodeHandle);
                    string      id          = maxNode.GetGuid().ToString();
                    BabylonNode babylonNode = babylonNodes.Find(node => node.id.Equals(id));

                    if (babylonNode != null && nodeToGltfNodeMap.TryGetValue(babylonNode, out GLTFNode gltfNode))
                    {
                        ExportNodeAnimation(gltfAnimation, animGroup.FrameStart, animGroup.FrameEnd, gltf, babylonNode, gltfNode, babylonScene);
                    }

                    // export all bones that match this id
                    foreach (KeyValuePair <BabylonBone, GLTFNode> pair in boneToGltfNodeMap)
                    {
                        if (pair.Key.id.Equals(id))
                        {
                            ExportBoneAnimation(gltfAnimation, animGroup.FrameStart, animGroup.FrameEnd, gltf, pair.Key, pair.Value);
                        }
                    }
                }
                gltf.AnimationsList.Add(gltfAnimation);
            }
        }
        private void ExportCamera(IINode cameraNode, BabylonScene babylonScene)
        {
            if (cameraNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            var maxCamera = (cameraNode.ObjectRef as ICameraObject);
            var babylonCamera = new BabylonCamera();

            RaiseMessage(cameraNode.Name, 1);
            babylonCamera.name = cameraNode.Name;
            babylonCamera.id = cameraNode.GetGuid().ToString();
            if (cameraNode.HasParent())
            {
                babylonCamera.parentId = cameraNode.ParentNode.GetGuid().ToString();
            }

            babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever));
            babylonCamera.minZ = maxCamera.GetEnvRange(0, 0, Tools.Forever);
            babylonCamera.maxZ = maxCamera.GetEnvRange(0, 1, Tools.Forever);

            if (babylonCamera.minZ == 0.0f)
            {
                babylonCamera.minZ = 0.1f;
            }

            // Control
            babylonCamera.speed = cameraNode.GetFloatProperty("babylonjs_speed", 1.0f);
            babylonCamera.inertia = cameraNode.GetFloatProperty("babylonjs_inertia", 0.9f);

            // Collisions
            babylonCamera.checkCollisions = cameraNode.GetBoolProperty("babylonjs_checkcollisions");
            babylonCamera.applyGravity = cameraNode.GetBoolProperty("babylonjs_applygravity");
            babylonCamera.ellipsoid = cameraNode.GetVector3Property("babylonjs_ellipsoid");

            // Position
            var wm = cameraNode.GetWorldMatrix(0, cameraNode.HasParent());
            var position = wm.Trans;
            babylonCamera.position = position.ToArraySwitched();

            // Target
            var target = cameraNode.Target;
            if (target != null)
            {
                babylonCamera.lockedTargetId = target.GetGuid().ToString();
            }
            else
            {
                var dir = wm.GetRow(2).MultiplyBy(-1);
                babylonCamera.target = position.Add(dir).ToArraySwitched();
            }

            // Animations
            var animations = new List<BabylonAnimation>();
            if (!ExportVector3Controller(cameraNode.TMController.PositionController, "position", animations))
            {
                ExportVector3Animation("position", animations, key =>
                {
                    var worldMatrix = cameraNode.GetWorldMatrix(key, cameraNode.HasParent());
                    return worldMatrix.Trans.ToArraySwitched();
                });
            }

            ExportFloatAnimation("fov", animations, key => new[] {Tools.ConvertFov(maxCamera.GetFOV(key, Tools.Forever))});

            babylonCamera.animations = animations.ToArray();

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

            babylonScene.CamerasList.Add(babylonCamera);
        }
示例#18
0
        private void ExportAnimationGroups(GLTF gltf, BabylonScene babylonScene)
        {
            // Retreive and parse animation group data
            AnimationGroupList animationList = InitAnimationGroups();

            gltf.AnimationsList.Clear();
            gltf.AnimationsList.Capacity = Math.Max(gltf.AnimationsList.Capacity, animationList.Count);

            if (animationList.Count <= 0)
            {
                RaiseMessage("GLTFExporter.Animation | No AnimationGroups: exporting all animations together.", 1);
                GLTFAnimation gltfAnimation = new GLTFAnimation();
                gltfAnimation.name = "All Animations";

                int minFrame = Loader.Core.AnimRange.Start / Loader.Global.TicksPerFrame;
                int maxFrame = Loader.Core.AnimRange.End / Loader.Global.TicksPerFrame;

                foreach (var pair in nodeToGltfNodeMap)
                {
                    ExportNodeAnimation(gltfAnimation, minFrame, maxFrame, gltf, pair.Key, pair.Value, babylonScene);
                }
                foreach (var pair in boneToGltfNodeMap)
                {
                    ExportBoneAnimation(gltfAnimation, minFrame, maxFrame, gltf, pair.Key, pair.Value);
                }

                if (gltfAnimation.ChannelList.Count > 0)
                {
                    gltf.AnimationsList.Add(gltfAnimation);
                }
                else
                {
                    RaiseMessage("GLTFExporter.Animation | No animation data for this animation, it is ignored.", 2);
                }
            }
            else
            {
                foreach (AnimationGroup animGroup in animationList)
                {
                    RaiseMessage("GLTFExporter.Animation | " + animGroup.Name, 1);

                    GLTFAnimation gltfAnimation = new GLTFAnimation();
                    gltfAnimation.name = animGroup.Name;

                    int startFrame = animGroup.FrameStart;
                    int endFrame   = animGroup.FrameEnd;

                    foreach (uint nodeHandle in animGroup.NodeHandles)
                    {
                        // todo: make something a little more efficient..
                        IINode maxNode = Loader.Core.RootNode.FindChildNode(nodeHandle);

                        // node could have been deleted, silently ignore it
                        if (maxNode == null)
                        {
                            continue;
                        }

                        string      id          = maxNode.GetGuid().ToString();
                        BabylonNode babylonNode = babylonNodes.Find(node => node.id.Equals(id));

                        if (babylonNode != null && nodeToGltfNodeMap.TryGetValue(babylonNode, out GLTFNode gltfNode))
                        {
                            ExportNodeAnimation(gltfAnimation, startFrame, endFrame, gltf, babylonNode, gltfNode, babylonScene);
                        }

                        // export all bones that match this id
                        foreach (KeyValuePair <BabylonBone, GLTFNode> pair in boneToGltfNodeMap)
                        {
                            if (pair.Key.id.Equals(id))
                            {
                                ExportBoneAnimation(gltfAnimation, startFrame, endFrame, gltf, pair.Key, pair.Value);
                            }
                        }
                    }

                    if (gltfAnimation.ChannelList.Count > 0)
                    {
                        gltf.AnimationsList.Add(gltfAnimation);
                    }
                    else
                    {
                        RaiseMessage("No data exported for this animation, it is ignored.", 2);
                    }
                }
            }
        }
示例#19
0
        private void confirmButton_Click(object sender, EventArgs e)
        {
            if (currentInfo == null)
            {
                return;
            }

            AnimationGroup confirmedInfo = currentInfo;

            string newName = nameTextBox.Text;

            int newFrameStart;

            if (!int.TryParse(startTextBox.Text, out newFrameStart))
            {
                newFrameStart = confirmedInfo.FrameStart;
            }
            int newFrameEnd;

            if (!int.TryParse(endTextBox.Text, out newFrameEnd))
            {
                newFrameEnd = confirmedInfo.FrameEnd;
            }

            List <uint> newHandles;
            bool        nodesChanged = MaxNodeTree.ApplyQueuedChanges(out newHandles);

            bool changed = newName != confirmedInfo.Name || newFrameStart != confirmedInfo.FrameStart || newFrameEnd != confirmedInfo.FrameEnd || nodesChanged;

            if (!changed)
            {
                return;
            }

            confirmedInfo.Name       = newName;
            confirmedInfo.FrameStart = newFrameStart;
            confirmedInfo.FrameEnd   = newFrameEnd;

            if (nodesChanged)
            {
                confirmedInfo.NodeGuids = newHandles.ToGuids();
                if (confirmedInfo.AnimationGroupNodes == null)
                {
                    confirmedInfo.AnimationGroupNodes = new List <AnimationGroupNode>();
                }

                foreach (uint handle in newHandles)
                {
                    IINode node = Loader.Core.GetINodeByHandle(handle);
                    if (node != null)
                    {
                        string             name       = node.Name;
                        string             parentName = node.ParentNode.Name;
                        AnimationGroupNode nodeData   = new AnimationGroupNode(node.GetGuid(), name, parentName);
                        confirmedInfo.AnimationGroupNodes.Add(nodeData);
                    }
                }
            }

            ResetChangedTextBoxColors();
            MaxNodeTree.SelectedNode = null;

            InfoChanged?.Invoke(confirmedInfo);
            ConfirmPressed?.Invoke(confirmedInfo);
        }
        private void ExportLight(IINode lightNode, BabylonScene babylonScene)
        {
            if (lightNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            var maxLight = (lightNode.ObjectRef as ILightObject);
            var babylonLight = new BabylonLight();

            RaiseMessage(lightNode.Name, 1);
            babylonLight.name = lightNode.Name;
            babylonLight.id = lightNode.GetGuid().ToString();

            // Type
            var lightState = Loader.Global.LightState.Create();
            maxLight.EvalLightState(0, Tools.Forever, lightState);
            var directionScale = -1;

            switch (lightState.Type)
            {
                case LightType.OmniLgt:
                    babylonLight.type = 0;
                    break;
                case LightType.SpotLgt:
                    babylonLight.type = 2;
                    babylonLight.angle = (float)(maxLight.GetFallsize(0, Tools.Forever) * Math.PI / 180.0f);
                    babylonLight.exponent = 1;
                    break;
                case LightType.DirectLgt:
                    babylonLight.type = 1;
                    break;
                case LightType.AmbientLgt:
                    babylonLight.type = 3;
                    babylonLight.groundColor = new float[] { 0, 0, 0 };
                    directionScale = 1;
                    break;
            }

            // Shadows
            if (maxLight.ShadowMethod == 1)
            {
                if (lightState.Type == LightType.DirectLgt)
                {
                    ExportShadowGenerator(lightNode, babylonScene);
                }
                else
                {
                    RaiseWarning("Shadows maps are only supported for directional lights", 2);
                }
            }

            // Position
            var wm = lightNode.GetWorldMatrix(0, false);
            var position = wm.Trans;
            babylonLight.position = position.ToArraySwitched();

            // Direction
            var target = lightNode.Target;
            if (target != null)
            {
                var targetWm = target.GetObjTMBeforeWSM(0, Tools.Forever);
                var targetPosition = targetWm.Trans;

                var direction = targetPosition.Subtract(position);
                babylonLight.direction = direction.ToArraySwitched();
            }
            else
            {
                var dir = wm.GetRow(2).MultiplyBy(directionScale);
                babylonLight.direction = dir.ToArraySwitched();
            }

            // Exclusion
            var maxScene = Loader.Core.RootNode;
            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
            var checkExclusionList = maxLight.ExclList.TestFlag(2); //NT_AFFECT_ILLUM

            if (checkExclusionList)
            {
                var excllist = new List<string>();
                var incllist = new List<string>();

                foreach (var meshNode in maxScene.NodesListBySuperClass(SClass_ID.Geomobject))
                {
                    if (meshNode.CastShadows == 1)
                    {
                        var inList = maxLight.ExclList.FindNode(meshNode) != -1;

                        if (inList)
                        {
                            if (inclusion)
                            {
                                incllist.Add(meshNode.GetGuid().ToString());
                            }
                            else
                            {
                                excllist.Add(meshNode.GetGuid().ToString());
                            }
                        }
                    }
                }

                babylonLight.includedOnlyMeshesIds = incllist.ToArray();
                babylonLight.excludedMeshesIds = excllist.ToArray();
            }

            // Other fields
            babylonLight.intensity = maxLight.GetIntensity(0, Tools.Forever);

            babylonLight.diffuse = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
            babylonLight.specular = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };

            if (maxLight.UseAtten)
            {
                babylonLight.range = maxLight.GetAtten(0, 1, Tools.Forever);
            }

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

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

            ExportVector3Animation("direction", animations, key =>
            {
                var targetNode = lightNode.Target;
                if (targetNode != null)
                {
                    var targetWm = target.GetObjTMBeforeWSM(0, Tools.Forever);
                    var targetPosition = targetWm.Trans;

                    var direction = targetPosition.Subtract(position);
                    return direction.ToArraySwitched();
                }
                
                var dir = wm.GetRow(2).MultiplyBy(directionScale);
                return dir.ToArraySwitched();
            });

            ExportFloatAnimation("intensity", animations, key => new[] { maxLight.GetIntensity(key, Tools.Forever) });

            babylonLight.animations = animations.ToArray();

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

            babylonScene.LightsList.Add(babylonLight);
        }
        private void ExportLight(IINode lightNode, BabylonScene babylonScene)
        {
            if (lightNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            var maxLight     = (lightNode.ObjectRef as ILightObject);
            var babylonLight = new BabylonLight();

            RaiseMessage(lightNode.Name, 1);
            babylonLight.name = lightNode.Name;
            babylonLight.id   = lightNode.GetGuid().ToString();

            // Type
            var lightState = Loader.Global.LightState.Create();

            maxLight.EvalLightState(0, Tools.Forever, lightState);
            var directionScale = -1;

            switch (lightState.Type)
            {
            case LightType.OmniLgt:
                babylonLight.type = 0;
                break;

            case LightType.SpotLgt:
                babylonLight.type     = 2;
                babylonLight.angle    = (float)(maxLight.GetFallsize(0, Tools.Forever) * Math.PI / 180.0f);
                babylonLight.exponent = 1;
                break;

            case LightType.DirectLgt:
                babylonLight.type = 1;
                break;

            case LightType.AmbientLgt:
                babylonLight.type        = 3;
                babylonLight.groundColor = new float[] { 0, 0, 0 };
                directionScale           = 1;
                break;
            }

            // Shadows
            if (maxLight.ShadowMethod == 1)
            {
                if (lightState.Type == LightType.DirectLgt)
                {
                    ExportShadowGenerator(lightNode, babylonScene);
                }
                else
                {
                    RaiseWarning("Shadows maps are only supported for directional lights", 2);
                }
            }

            // Position
            var wm       = lightNode.GetWorldMatrix(0, false);
            var position = wm.Trans;

            babylonLight.position = position.ToArraySwitched();

            // Direction
            var target = lightNode.Target;

            if (target != null)
            {
                var targetWm       = target.GetObjTMBeforeWSM(0, Tools.Forever);
                var targetPosition = targetWm.Trans;

                var direction = targetPosition.Subtract(position);
                babylonLight.direction = direction.ToArraySwitched();
            }
            else
            {
                var dir = wm.GetRow(2).MultiplyBy(directionScale);
                babylonLight.direction = dir.ToArraySwitched();
            }

            // Exclusion
            var maxScene           = Loader.Core.RootNode;
            var inclusion          = maxLight.ExclList.TestFlag(1); //NT_INCLUDE
            var checkExclusionList = maxLight.ExclList.TestFlag(2); //NT_AFFECT_ILLUM

            if (checkExclusionList)
            {
                var excllist = new List <string>();
                var incllist = new List <string>();

                foreach (var meshNode in maxScene.NodesListBySuperClass(SClass_ID.Geomobject))
                {
                    if (meshNode.CastShadows == 1)
                    {
                        var inList = maxLight.ExclList.FindNode(meshNode) != -1;

                        if (inList)
                        {
                            if (inclusion)
                            {
                                incllist.Add(meshNode.GetGuid().ToString());
                            }
                            else
                            {
                                excllist.Add(meshNode.GetGuid().ToString());
                            }
                        }
                    }
                }

                babylonLight.includedOnlyMeshesIds = incllist.ToArray();
                babylonLight.excludedMeshesIds     = excllist.ToArray();
            }

            // Other fields
            babylonLight.intensity = maxLight.GetIntensity(0, Tools.Forever);

            babylonLight.diffuse  = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
            babylonLight.specular = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };

            if (maxLight.UseAtten)
            {
                babylonLight.range = maxLight.GetAtten(0, 1, Tools.Forever);
            }

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

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

            ExportVector3Animation("direction", animations, key =>
            {
                var targetNode = lightNode.Target;
                if (targetNode != null)
                {
                    var targetWm       = target.GetObjTMBeforeWSM(0, Tools.Forever);
                    var targetPosition = targetWm.Trans;

                    var direction = targetPosition.Subtract(position);
                    return(direction.ToArraySwitched());
                }

                var dir = wm.GetRow(2).MultiplyBy(directionScale);
                return(dir.ToArraySwitched());
            });

            ExportFloatAnimation("intensity", animations, key => new[] { maxLight.GetIntensity(key, Tools.Forever) });

            babylonLight.animations = animations.ToArray();

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

            babylonScene.LightsList.Add(babylonLight);
        }
示例#22
0
        public void LoadFromJson(string jsonContent, bool merge = false)
        {
            List <string> animationPropertyNameList = Loader.Core.RootNode.GetStringArrayProperty(s_AnimationListPropertyName).ToList();

            if (!merge)
            {
                animationPropertyNameList = new List <string>();
                Clear();
            }

            List <AnimationGroup> animationGroupsData = JsonConvert.DeserializeObject <List <AnimationGroup> >(jsonContent);

            foreach (AnimationGroup animData in animationGroupsData)
            {
                List <Guid> nodeGuids = new List <Guid>();

                if (animData.AnimationGroupNodes != null)
                {
                    string missingNodes = "";
                    string movedNodes   = "";
                    foreach (AnimationGroupNode nodeData in animData.AnimationGroupNodes)
                    {
                        //check here if something changed between export\import
                        // a node handle is reassigned the moment the node is created
                        // it is no possible to have consistency at 100% sure between two file
                        // we need to prevent artists
                        IINode node = Loader.Core.GetINodeByName(nodeData.Name);
                        if (node == null)
                        {
                            //node is missing
                            missingNodes += nodeData.Name + "\n";
                            continue;
                        }

                        if (node.ParentNode.Name != nodeData.ParentName)
                        {
                            //node has been moved in hierarchy
                            movedNodes += node.Name + "\n";
                            continue;
                        }

                        nodeGuids.Add(node.GetGuid());
                    }

                    if (!string.IsNullOrEmpty(movedNodes))
                    {
                        //skip restoration of evaluated animation group
                        nodeGuids = new List <Guid>();
                        MessageBox.Show(string.Format("{0} has been moved in hierarchy,{1} import skipped", movedNodes, animData.Name));
                    }

                    if (!string.IsNullOrEmpty(missingNodes))
                    {
                        //skip restoration of evaluated animation group
                        nodeGuids = new List <Guid>();
                        MessageBox.Show(string.Format("{0} does not exist,{1} import skipped", missingNodes, animData.Name));
                    }
                }

                animData.NodeGuids = nodeGuids;
                string nodes = string.Join(AnimationGroup.s_PropertySeparator.ToString(), animData.NodeGuids);

                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendFormat(AnimationGroup.s_PropertyFormat, animData.Name, animData.TicksStart, animData.TicksEnd, nodes);

                Loader.Core.RootNode.SetStringProperty(animData.SerializedId.ToString(), stringBuilder.ToString());
            }

            foreach (AnimationGroup animData in animationGroupsData)
            {
                string id = animData.SerializedId.ToString();

                if (merge)
                {
                    //if json are merged check if the same animgroup is already in list
                    //and skip in that case
                    if (!animationPropertyNameList.Contains(id))
                    {
                        animationPropertyNameList.Add(animData.SerializedId.ToString());
                    }
                }
                else
                {
                    animationPropertyNameList.Add(animData.SerializedId.ToString());
                }
            }

            Loader.Core.RootNode.SetStringArrayProperty(s_AnimationListPropertyName, animationPropertyNameList);

            LoadFromData(Loader.Core.RootNode);
        }
示例#23
0
        private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene)
        {
            IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>();

            // Retrieve and parse animation group data
            AnimationGroupList animationList = AnimationGroupList.InitAnimationGroups(logger);

            foreach (AnimationGroup animGroup in animationList)
            {
                logger?.RaiseMessage("Exporter.animationGroups | " + animGroup.Name, 1);
                BabylonAnimationGroup animationGroup = new BabylonAnimationGroup
                {
                    name               = animGroup.Name,
                    from               = animGroup.FrameStart,
                    to                 = animGroup.FrameEnd,
                    keepNonAnimated    = animGroup.KeepNonAnimated,
                    targetedAnimations = new List <BabylonTargetedAnimation>()
                };

                // add animations of each nodes contained in the animGroup
                foreach (Guid guid in animGroup.NodeGuids)
                {
                    IINode maxNode = Tools.GetINodeByGuid(guid);

                    // node could have been deleted, silently ignore it
                    if (maxNode == null)
                    {
                        continue;
                    }

                    if (exportParameters.exportAsSubmodel && !maxNode.Selected)
                    {
                        continue;
                    }


                    // Helpers can be exported as dummies and as bones
                    string nodeId = maxNode.GetGuid().ToString();
                    string boneId = isGltfExported?maxNode.GetGuid().ToString(): maxNode.GetGuid().ToString() + "-bone";   // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs

                    // Node
                    BabylonNode node = null;
                    babylonScene.NodeMap.TryGetValue(nodeId, out node);
                    if (node != null)
                    {
                        if (node.animations != null && node.animations.Length != 0)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(node, animationGroup.from, animationGroup.to);

                            if (!animGroup.KeepStaticAnimation)
                            {
                                RemoveStaticAnimations(ref animations);
                            }

                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = nodeId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                    }

                    // bone
                    BabylonBone bone  = null;
                    int         index = 0;
                    while (index < babylonScene.SkeletonsList.Count && bone == null)
                    {
                        BabylonSkeleton skel = babylonScene.SkeletonsList[index];
                        bone = skel.bones.FirstOrDefault(b => b.id == boneId);
                        index++;
                    }

                    if (bone != null)
                    {
                        if (bone.animation != null)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(bone, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = boneId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                    }
                }

                // add animations of each nodes contained in the animGroup
                foreach (Guid guid in animGroup.MaterialGuids)
                {
                    IMtl maxMtl = Tools.GetIMtlByGuid(guid);

                    // mat could have been deleted, silently ignore it
                    if (maxMtl == null)
                    {
                        continue;
                    }

                    string matId = maxMtl.GetGuid().ToString();

                    // Material
                    BabylonMaterial material = null;
                    material = babylonScene.MaterialsList.FirstOrDefault(x => x.id == matId);
                    if (material != null)
                    {
                        if (material.animations != null && material.animations.Length != 0)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(material, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = matId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                    }
                }

                if (animationGroup.targetedAnimations.Count > 0)
                {
                    animationGroups.Add(animationGroup);
                }
            }

            return(animationGroups);
        }
示例#24
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);
        }
示例#25
0
        private void confirmButton_Click(object sender, EventArgs e)
        {
            if (currentInfo == null)
            {
                return;
            }

            AnimationGroup confirmedInfo = currentInfo;

            string newName = nameTextBox.Text;

            bool newKeepEmpty       = keepStaticAnimBox.Checked;
            bool newKeepNonAnimated = keepNonAnimatedBox.Checked;

            int newFrameStart;

            if (!int.TryParse(startTextBox.Text, out newFrameStart))
            {
                newFrameStart = confirmedInfo.FrameStart;
            }
            int newFrameEnd;

            if (!int.TryParse(endTextBox.Text, out newFrameEnd))
            {
                newFrameEnd = confirmedInfo.FrameEnd;
            }

            List <uint>  newHandles;
            bool         nodesChanged = MaxNodeTree.ApplyQueuedChanges(out newHandles);
            IList <Guid> newMaterialGUIDs;
            bool         materialsChanged = maxMaterialView.ApplyMaterialsChanges(out newMaterialGUIDs);

            bool changed = newKeepEmpty != confirmedInfo.KeepStaticAnimation ||
                           newName != confirmedInfo.Name ||
                           newFrameStart != confirmedInfo.FrameStart ||
                           newFrameEnd != confirmedInfo.FrameEnd ||
                           nodesChanged ||
                           materialsChanged ||
                           newKeepNonAnimated != confirmedInfo.KeepNonAnimated;

            if (!changed)
            {
                return;
            }

            confirmedInfo.Name                = newName;
            confirmedInfo.FrameStart          = newFrameStart;
            confirmedInfo.FrameEnd            = newFrameEnd;
            confirmedInfo.KeepStaticAnimation = newKeepEmpty;
            confirmedInfo.KeepNonAnimated     = newKeepNonAnimated;

            if (nodesChanged)
            {
                confirmedInfo.NodeGuids = newHandles.ToGuids();
                if (confirmedInfo.AnimationGroupNodes == null)
                {
                    confirmedInfo.AnimationGroupNodes = new List <AnimationGroupNode>();
                }

                foreach (uint handle in newHandles)
                {
                    IINode node = Loader.Core.GetINodeByHandle(handle);
                    if (node != null)
                    {
                        string             name       = node.Name;
                        string             parentName = node.ParentNode.Name;
                        AnimationGroupNode nodeData   = new AnimationGroupNode(node.GetGuid(), name, parentName);
                        confirmedInfo.AnimationGroupNodes.Add(nodeData);
                    }
                }
            }

            if (materialsChanged)
            {
                confirmedInfo.MaterialGuids = newMaterialGUIDs;

                if (confirmedInfo.AnimationGroupMaterials == null)
                {
                    confirmedInfo.AnimationGroupMaterials = new List <AnimationGroupMaterial>();
                }

                foreach (Guid guid in newMaterialGUIDs)
                {
                    IMtl mat = Tools.GetIMtlByGuid(guid);
                    if (mat != null)
                    {
                        string name = mat.Name;
                        AnimationGroupMaterial matData = new AnimationGroupMaterial(guid, name);
                        confirmedInfo.AnimationGroupMaterials.Add(matData);
                    }
                }
            }

            ResetChangedTextBoxColors();
            MaxNodeTree.SelectedNode = null;

            InfoChanged?.Invoke(confirmedInfo);
            ConfirmPressed?.Invoke(confirmedInfo);
        }
示例#26
0
        private BabylonNode ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
        {
            if (IsMeshExportable(meshNode) == false)
            {
                return(null);
            }

            logger?.RaiseMessage(meshNode.Name, 1);

            if (!exportParameters.keepInstances)
            {
                return(ExportMasterMesh(scene, meshNode, babylonScene));
            }
            else
            {
                // Instances
    #if MAX2020 || MAX2021 || MAX2022
                var tabs = Loader.Global.INodeTab.Create();
    #else
                var tabs = Loader.Global.NodeTab.Create();
    #endif
                Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs);
                if (tabs.Count > 1)
                {
                    IINode Master = TabToList <IINode>(tabs)[tabs.Count - 1];

                    List <IINode> Instances = TabToList <IINode>(tabs).FindAll(x => x.Handle != Master.Handle);
                    foreach (IINode instanceNode in tabs.ToIEnumerable())
                    {
                        //this make sure every instance node is indexed in guid dictionary
                        Tools.GetGuid(instanceNode);
                    }

                    BabylonMesh babylonMasterMesh = babylonScene.MeshesList.Find(mesh => mesh.id == Master.GetGuid().ToString());
                    if (babylonMasterMesh == null)
                    {
                        return(ExportMasterMesh(scene, meshNode, babylonScene));
                    }
                    else
                    {
                        return(ExportInstanceMesh(scene, meshNode, babylonScene, babylonMasterMesh));
                    }
                }

                return(ExportMasterMesh(scene, meshNode, babylonScene));
            }
        }
示例#27
0
        public void LoadFromData(string propertyName, IINode dataNode)
        {
            if (!Guid.TryParse(propertyName, out serializedId))
            {
                throw new Exception("Invalid ID, can't deserialize.");
            }

            string propertiesString = string.Empty;

            if (!dataNode.GetUserPropString(propertyName, ref propertiesString))
            {
                return;
            }

            string[] properties = propertiesString.Split(s_PropertySeparator);

            if (properties.Length < 4)
            {
                throw new Exception("Invalid number of properties, can't deserialize.");
            }

            // set dirty explicitly just before we start loading, set to false when loading is done
            // if any exception is thrown, it will have a correct value
            IsDirty = true;

            name = properties[0];
            if (!int.TryParse(properties[1], out ticksStart))
            {
                throw new Exception("Failed to parse FrameStart property.");
            }
            if (!int.TryParse(properties[2], out ticksEnd))
            {
                throw new Exception("Failed to parse FrameEnd property.");
            }

            if (string.IsNullOrEmpty(properties[3]))
            {
                return;
            }

            int numNodeIDs = properties.Length - 3;

            if (nodeGuids.Capacity < numNodeIDs)
            {
                nodeGuids.Capacity = numNodeIDs;
            }
            int numFailed = 0;

            for (int i = 0; i < numNodeIDs; ++i)
            {
                Guid guid;
                if (!Guid.TryParse(properties[3 + i], out guid))
                {
                    uint id;
                    if (!uint.TryParse(properties[3 + i], out id))
                    {
                        ++numFailed;
                        continue;
                    }
                    //node is serialized in the old way ,force the reassignation of a new Guid on
                    IINode node = Loader.Core.GetINodeByHandle(id);
                    if (node != null)
                    {
                        guid = node.GetGuid();
                    }
                }
                nodeGuids.Add(guid);
            }

            AnimationGroupNodes = new List <AnimationGroupNode>();
            foreach (Guid nodeGuid in nodeGuids)
            {
                IINode node = Tools.GetINodeByGuid(nodeGuid);

                if (node != null)
                {
                    string             name       = node.Name;
                    string             parentName = node.ParentNode.Name;
                    AnimationGroupNode nodeData   = new AnimationGroupNode(nodeGuid, name, parentName);
                    AnimationGroupNodes.Add(nodeData);
                }
            }

            if (numFailed > 0)
            {
                throw new Exception(string.Format("Failed to parse {0} node ids.", numFailed));
            }

            IsDirty = false;
        }
示例#28
0
        private void ExportCamera(IINode cameraNode, BabylonScene babylonScene)
        {
            if (cameraNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            var maxCamera     = (cameraNode.ObjectRef as ICameraObject);
            var babylonCamera = new BabylonCamera();

            RaiseMessage(cameraNode.Name, 1);
            babylonCamera.name = cameraNode.Name;
            babylonCamera.id   = cameraNode.GetGuid().ToString();
            if (cameraNode.HasParent())
            {
                babylonCamera.parentId = cameraNode.ParentNode.GetGuid().ToString();
            }

            babylonCamera.fov  = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever));
            babylonCamera.minZ = maxCamera.GetEnvRange(0, 0, Tools.Forever);
            babylonCamera.maxZ = maxCamera.GetEnvRange(0, 1, Tools.Forever);

            if (babylonCamera.minZ == 0.0f)
            {
                babylonCamera.minZ = 0.1f;
            }

            // Control
            babylonCamera.speed   = cameraNode.GetFloatProperty("babylonjs_speed", 1.0f);
            babylonCamera.inertia = cameraNode.GetFloatProperty("babylonjs_inertia", 0.9f);

            // Collisions
            babylonCamera.checkCollisions = cameraNode.GetBoolProperty("babylonjs_checkcollisions");
            babylonCamera.applyGravity    = cameraNode.GetBoolProperty("babylonjs_applygravity");
            babylonCamera.ellipsoid       = cameraNode.GetVector3Property("babylonjs_ellipsoid");

            // Position
            var wm       = cameraNode.GetWorldMatrix(0, cameraNode.HasParent());
            var position = wm.Trans;

            babylonCamera.position = position.ToArraySwitched();

            // Target
            var target = cameraNode.Target;

            if (target != null)
            {
                babylonCamera.lockedTargetId = target.GetGuid().ToString();
            }
            else
            {
                var dir = wm.GetRow(2).MultiplyBy(-1);
                babylonCamera.target = position.Add(dir).ToArraySwitched();
            }

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

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

            ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov(maxCamera.GetFOV(key, Tools.Forever)) });

            babylonCamera.animations = animations.ToArray();

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

            babylonScene.CamerasList.Add(babylonCamera);
        }
示例#29
0
        private IList <BabylonAnimationGroup> ExportAnimationGroups(BabylonScene babylonScene)
        {
            IList <BabylonAnimationGroup> animationGroups = new List <BabylonAnimationGroup>();

            // Retrieve and parse animation group data
            AnimationGroupList animationList = InitAnimationGroups();

            foreach (AnimationGroup animGroup in animationList)
            {
                RaiseMessage("Exporter.animationGroups | " + animGroup.Name, 1);

                BabylonAnimationGroup animationGroup = new BabylonAnimationGroup
                {
                    name = animGroup.Name,
                    from = animGroup.FrameStart,
                    to   = animGroup.FrameEnd,
                    targetedAnimations = new List <BabylonTargetedAnimation>()
                };

                // add animations of each nodes contained in the animGroup
                foreach (uint nodeHandle in animGroup.NodeHandles)
                {
                    IINode maxNode = Loader.Core.RootNode.FindChildNode(nodeHandle);

                    // node could have been deleted, silently ignore it
                    if (maxNode == null)
                    {
                        continue;
                    }


                    // Helpers can be exported as dummies and as bones
                    string nodeId = maxNode.GetGuid().ToString();
                    string boneId = maxNode.GetGuid().ToString() + "-bone";   // the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs


                    // Node
                    BabylonNode node = babylonScene.MeshesList.FirstOrDefault(m => m.id == nodeId);
                    if (node == null)
                    {
                        node = babylonScene.CamerasList.FirstOrDefault(c => c.id == nodeId);
                    }
                    if (node == null)
                    {
                        node = babylonScene.LightsList.FirstOrDefault(l => l.id == nodeId);
                    }

                    if (node != null)
                    {
                        if (node.animations != null && node.animations.Length != 0)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(node, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = nodeId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                        else if (exportNonAnimated)
                        {
                            BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                            {
                                animation = CreatePositionAnimation(animationGroup.from, animationGroup.to, node.position),
                                targetId  = node.id
                            };

                            animationGroup.targetedAnimations.Add(targetedAnimation);
                        }
                    }

                    // bone
                    BabylonBone bone  = null;
                    int         index = 0;
                    while (index < babylonScene.SkeletonsList.Count && bone == null)
                    {
                        BabylonSkeleton skel = babylonScene.SkeletonsList[index];
                        bone = skel.bones.FirstOrDefault(b => b.id == boneId);
                        index++;
                    }

                    if (bone != null)
                    {
                        if (bone.animation != null)
                        {
                            IList <BabylonAnimation> animations = GetSubAnimations(bone, animationGroup.from, animationGroup.to);
                            foreach (BabylonAnimation animation in animations)
                            {
                                BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                                {
                                    animation = animation,
                                    targetId  = boneId
                                };

                                animationGroup.targetedAnimations.Add(targetedAnimation);
                            }
                        }
                        else if (exportNonAnimated)
                        {
                            BabylonTargetedAnimation targetedAnimation = new BabylonTargetedAnimation
                            {
                                animation = CreateMatrixAnimation(animationGroup.from, animationGroup.to, bone.matrix),
                                targetId  = bone.id
                            };

                            animationGroup.targetedAnimations.Add(targetedAnimation);
                        }
                    }
                }

                if (animationGroup.targetedAnimations.Count > 0)
                {
                    animationGroups.Add(animationGroup);
                }
            }

            return(animationGroups);
        }
示例#30
0
        private void ExportMesh(IINode meshNode, BabylonScene babylonScene)
        {
            if (meshNode.IsInstance())
            {
                return;
            }

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

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

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

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

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

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

            // Skin
            var skin = GetSkinModifier(meshNode);

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

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

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

            // Pivot
            var pivotMatrix = Tools.Identity;

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

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

            RaiseMessage(meshNode.Name, 1);

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

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

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

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

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

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

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

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

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

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

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

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

                // Skin
                IISkinContextData skinContext = null;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        indexStart += indexCount;

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


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

                triObject.Dispose();
            }

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

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

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

                Marshal.FreeHGlobal(indexer);

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

                tab.MarkAsInstance();

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

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

                instances.Add(instance);
            }

            babylonMesh.instances = instances.ToArray();

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

            GenerateCoordinatesAnimations(meshNode, animations);


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

            babylonMesh.animations = animations.ToArray();

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

            babylonScene.MeshesList.Add(babylonMesh);
        }