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; }
private BabylonShadowGenerator ExportShadowGenerator(Node lightNode, BabylonScene babylonScene) { var maxLight = (lightNode.Object as Light); var babylonShadowGenerator = new BabylonShadowGenerator(); RaiseMessage("Exporting shadow map", true, false, true); babylonShadowGenerator.lightId = lightNode.GetGuid().ToString(); babylonShadowGenerator.mapSize = maxLight.GetMapSize(0, Interval.Forever); var maxScene = Kernel.Scene; var list = new List<string>(); var inclusion = maxLight._Light.ExclList.TestFlag(1); //NT_INCLUDE var checkExclusionList = maxLight._Light.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST foreach (var meshNode in maxScene.NodesListBySuperClass(SuperClassID.GeometricObject)) { if (meshNode._Node.CastShadows == 1) { var inList = maxLight._Light.ExclList.FindNode(meshNode._Node) != -1; if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion)) { list.Add(meshNode.GetGuid().ToString()); } } } babylonShadowGenerator.renderList = list.ToArray(); babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator); return babylonShadowGenerator; }
public SceneBuilder(string outputPath, string sceneName, ExportationOptions exportationOptions, BabylonSceneController controller, string scriptPath) { OutputPath = outputPath; SceneName = string.IsNullOrEmpty(sceneName) ? "scene" : sceneName; SceneController = controller; SceneJavascriptPath = scriptPath; materialsDictionary = new Dictionary<string, BabylonMaterial>(); multiMatDictionary = new Dictionary<string, BabylonMultiMaterial>(); uniqueGuids = new Dictionary<int, string>(); babylonScene = new BabylonScene(OutputPath); babylonScene.producer = new BabylonProducer { file = Path.GetFileName(outputPath), version = "Unity3D", name = SceneName, exporter_version = "0.8.1" }; this.exportationOptions = exportationOptions; this.ManifestData = String.Empty; if (SceneController != null) { this.ManifestData = "{" + String.Format("\n\t\"version\" : {0},\n\t\"enableSceneOffline\" : {1},\n\t\"enableTexturesOffline\" : {2}\n", SceneController.manifestOptions.manifestVersion, SceneController.manifestOptions.storeSceneOffline.ToString().ToLower(), SceneController.manifestOptions.storeTextureOffline.ToString().ToLower()) + "}"; } }
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; }
public SceneBuilder(string outputPath, string sceneName, ExportationOptions exportationOptions) { OutputPath = outputPath; SceneName = string.IsNullOrEmpty(sceneName) ? "scene" : sceneName; materialsDictionary = new Dictionary<string, BabylonMaterial>(); multiMatDictionary = new Dictionary<string, BabylonMultiMaterial>(); uniqueGuids = new Dictionary<int, string>(); babylonScene = new BabylonScene(OutputPath); this.exportationOptions = exportationOptions; }
void ExportDefaultLight(BabylonScene babylonScene) { var babylonLight = new BabylonLight(); babylonLight.name = "Default light"; babylonLight.id = Guid.NewGuid().ToString(); babylonLight.type = 3; babylonLight.groundColor = new float[] { 0, 0, 0 }; babylonLight.direction = new[] { 0, 1.0f, 0 }; babylonLight.intensity = 1; babylonLight.diffuse = new[] { 1.0f, 1.0f, 1.0f }; babylonLight.specular = new[] { 1.0f, 1.0f, 1.0f }; babylonScene.LightsList.Add(babylonLight); }
private string GetParentID(IIGameNode parentNode, BabylonScene babylonScene, IIGameScene scene) { var parentType = parentNode.IGameObject.IGameType; var parentId = parentNode.MaxNode.GetGuid().ToString(); switch (parentType) { case Autodesk.Max.IGameObject.ObjectTypes.Light: case Autodesk.Max.IGameObject.ObjectTypes.Mesh: case Autodesk.Max.IGameObject.ObjectTypes.Camera: break; default: if (babylonScene.MeshesList.All(m => m.id != parentId)) { ExportMesh(scene, parentNode, babylonScene); } break; } return parentId; }
public SceneBuilder(string outputPath, string sceneName, ExportationOptions exportationOptions) { OutputPath = outputPath; SceneName = string.IsNullOrEmpty(sceneName) ? "scene" : sceneName; materialsDictionary = new Dictionary<string, BabylonMaterial>(); multiMatDictionary = new Dictionary<string, BabylonMultiMaterial>(); uniqueGuids = new Dictionary<int, string>(); babylonScene = new BabylonScene(OutputPath); babylonScene.producer = new BabylonProducer { file = Path.GetFileName(outputPath), version = "Unity3D", name = SceneName, exporter_version = "0.8" }; this.exportationOptions = exportationOptions; }
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 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); }
private BabylonMesh ExportMesh(Node meshNode, BabylonScene babylonScene, CancellationToken token) { var babylonMesh = new BabylonMesh(); int vx1, vx2, vx3; RaiseMessage(meshNode.Name, true); babylonMesh.name = meshNode.Name; babylonMesh.id = meshNode.GetGuid().ToString(); if (meshNode.HasParent()) { babylonMesh.parentId = meshNode.Parent.GetGuid().ToString(); } // Misc. babylonMesh.isVisible = meshNode._Node.Renderable == 1; babylonMesh.pickable = meshNode._Node.GetBoolProperty("babylonjs_checkpickable"); babylonMesh.receiveShadows = meshNode._Node.RcvShadows == 1; babylonMesh.showBoundingBox = meshNode._Node.GetBoolProperty("babylonjs_showboundingbox"); babylonMesh.showSubMeshesBoundingBox = meshNode._Node.GetBoolProperty("babylonjs_showsubmeshesboundingbox"); // Collisions babylonMesh.checkCollisions = meshNode._Node.GetBoolProperty("babylonjs_checkcollisions"); // Position / rotation / scaling var wm = meshNode.GetWorldMatrix(0, meshNode.HasParent()); babylonMesh.position = wm.Trans.ToArraySwitched(); var parts = Loader.Global.AffineParts.Create(); Loader.Global.DecompAffine(wm, parts); //var rotate = new float[3]; //IntPtr xPtr = Marshal.AllocHGlobal(sizeof(float)); //IntPtr yPtr = Marshal.AllocHGlobal(sizeof(float)); //IntPtr zPtr = Marshal.AllocHGlobal(sizeof(float)); //parts.Q.GetEuler(xPtr, yPtr, zPtr); //Marshal.Copy(xPtr, rotate, 0, 1); //Marshal.Copy(yPtr, rotate, 1, 1); //Marshal.Copy(zPtr, rotate, 2, 1); //var temp = -rotate[1]; //rotate[0] = rotate[0] * parts.F; //rotate[1] = -rotate[2] * parts.F; //rotate[2] = temp * parts.F; //babylonMesh.rotation = rotate; babylonMesh.rotationQuaternion = parts.Q.ToArray(); babylonMesh.scaling = parts.K.ToArraySwitched(); if (wm.Parity) { vx1 = 2; vx2 = 1; vx3 = 0; } else { vx1 = 0; vx2 = 1; vx3 = 2; } // Pivot var pivotMatrix = Matrix3.Identity._IMatrix3; pivotMatrix.PreTranslate(meshNode._Node.ObjOffsetPos); Loader.Global.PreRotateMatrix(pivotMatrix, meshNode._Node.ObjOffsetRot); Loader.Global.ApplyScaling(pivotMatrix, meshNode._Node.ObjOffsetScale); babylonMesh.pivotMatrix = pivotMatrix.ToArray(); // Mesh var objectState = meshNode._Node.EvalWorldState(0, false); var mesh = objectState.Obj.GetMesh(); var computedMesh = meshNode.GetMesh(); if (mesh != null) { mesh.BuildNormals(); if (mesh.NumFaces < 1) { RaiseError(string.Format("Mesh {0} has no face", babylonMesh.name)); } if (mesh.NumVerts < 3) { RaiseError(string.Format("Mesh {0} has not enough vertices", babylonMesh.name)); } if (mesh.NumVerts >= 65536) { RaiseError(string.Format("Mesh {0} has too many vertices (more than 65535)", babylonMesh.name)); } // Material var mtl = meshNode.Material; var multiMatsCount = 1; if (mtl != null) { babylonMesh.materialId = mtl.GetGuid().ToString(); if (!referencedMaterials.Contains(mtl)) { referencedMaterials.Add(mtl); } multiMatsCount = Math.Max(mtl.NumSubMaterials, 1); } babylonMesh.visibility = meshNode._Node.GetVisibility(0, Interval.Forever._IInterval); var vertices = new List<GlobalVertex>(); var indices = new List<int>(); var matIDs = new List<int>(); var hasUV = mesh.NumTVerts > 0; var hasUV2 = mesh.GetNumMapVerts(2) > 0; var noOptimize = meshNode._Node.GetBoolProperty("babylonjs_nooptimize"); for (var face = 0; face < mesh.NumFaces; face++) { indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx1, vertices, hasUV, hasUV2, noOptimize)); indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx2, vertices, hasUV, hasUV2, noOptimize)); indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx3, vertices, hasUV, hasUV2, noOptimize)); matIDs.Add(mesh.Faces[face].MatID % multiMatsCount); if (token.IsCancellationRequested) token.ThrowIfCancellationRequested(); } if (vertices.Count >= 65536) { RaiseError(string.Format("Mesh {0} has too many vertices: {1} (limit is 65535)", babylonMesh.name, vertices.Count)); } // Buffers babylonMesh.positions = vertices.SelectMany(v => v.Position.ToArraySwitched()).ToArray(); babylonMesh.normals = vertices.SelectMany(v => v.Normal.ToArraySwitched()).ToArray(); if (hasUV) { babylonMesh.uvs = vertices.SelectMany(v => v.UV.ToArray()).ToArray(); } if (hasUV2) { babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2.ToArray()).ToArray(); } // Submeshes var sortedIndices = new List<int>(); var subMeshes = new List<BabylonSubMesh>(); var indexStart = 0; for (var index = 0; index < multiMatsCount; index++) { var subMesh = new BabylonSubMesh(); var indexCount = 0; var minVertexIndex = int.MaxValue; var maxVertexIndex = int.MinValue; subMesh.indexStart = indexStart; subMesh.materialIndex = index; for (var face = 0; face < matIDs.Count; face++) { if (matIDs[face] == index) { var a = indices[3 * face]; var b = indices[3 * face + 1]; var c = indices[3 * face + 2]; sortedIndices.Add(a); sortedIndices.Add(b); sortedIndices.Add(c); indexCount += 3; if (a < minVertexIndex) { minVertexIndex = a; } if (b < minVertexIndex) { minVertexIndex = b; } if (c < minVertexIndex) { minVertexIndex = c; } if (a > maxVertexIndex) { maxVertexIndex = a; } if (b > maxVertexIndex) { maxVertexIndex = b; } if (c > maxVertexIndex) { maxVertexIndex = c; } } } if (indexCount != 0) { subMesh.indexCount = indexCount; subMesh.verticesStart = minVertexIndex; subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1; indexStart += indexCount; subMeshes.Add(subMesh); } if (token.IsCancellationRequested) token.ThrowIfCancellationRequested(); } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = sortedIndices.ToArray(); } // Animations var animations = new List<BabylonAnimation>(); ExportVector3Animation("position", animations, key => { var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent()); return worldMatrix.Trans.ToArraySwitched(); }); ExportQuaternionAnimation("rotationQuaternion", animations, key => { var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent()); var affineParts = Loader.Global.AffineParts.Create(); Loader.Global.DecompAffine(worldMatrix, affineParts); return affineParts.Q.ToArray(); }); ExportVector3Animation("scaling", animations, key => { var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent()); var affineParts = Loader.Global.AffineParts.Create(); Loader.Global.DecompAffine(worldMatrix, affineParts); return affineParts.K.ToArraySwitched(); }); ExportFloatAnimation("visibility", animations, key => new []{meshNode._Node.GetVisibility(key, Interval.Forever._IInterval)}); babylonMesh.animations = animations.ToArray(); if (meshNode._Node.GetBoolProperty("babylonjs_autoanimate")) { babylonMesh.autoAnimate = true; babylonMesh.autoAnimateFrom = (int)meshNode._Node.GetFloatProperty("babylonjs_autoanimate_from"); babylonMesh.autoAnimateTo = (int)meshNode._Node.GetFloatProperty("babylonjs_autoanimate_to"); babylonMesh.autoAnimateLoop = meshNode._Node.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.MeshesList.Add(babylonMesh); return babylonMesh; }
private BabylonTexture ExportTexture(IStdMat2 stdMat, int index, BabylonScene babylonScene, Boolean allowCube = false) { if (!stdMat.MapEnabled(index)) { return null; } var babylonTexture = new BabylonTexture(); var texMap = stdMat.GetSubTexmap(index); var texture = texMap.GetParamBlock(0).Owner as IBitmapTex; if (texture == null) { return null; } babylonTexture.hasAlpha = (texture.AlphaSource != 3); babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2); babylonTexture.level = stdMat.GetTexmapAmt(index, 0); var uvGen = texture.UVGen; switch (uvGen.GetCoordMapping(0)) { case 1: //MAP_SPHERICAL babylonTexture.coordinatesMode = 1; break; case 2: //MAP_PLANAR babylonTexture.coordinatesMode = 2; break; default: babylonTexture.coordinatesMode = 0; break; } babylonTexture.coordinatesIndex = uvGen.MapChannel - 1; if (uvGen.MapChannel > 2) { RaiseWarning(string.Format("Unsupported map channel, Only channel 1 and 2 are supported."), 2); } babylonTexture.uOffset = uvGen.GetUOffs(0); babylonTexture.vOffset = uvGen.GetVOffs(0); babylonTexture.uScale = uvGen.GetUScl(0); babylonTexture.vScale = uvGen.GetVScl(0); if (Path.GetExtension(texture.MapName).ToLower() == ".dds") { babylonTexture.vScale *= -1; // Need to invert Y-axis for DDS texture } babylonTexture.uAng = uvGen.GetUAng(0); babylonTexture.vAng = uvGen.GetVAng(0); babylonTexture.wAng = uvGen.GetWAng(0); babylonTexture.wrapU = 0; // CLAMP if ((uvGen.TextureTiling & 1) != 0) // WRAP { babylonTexture.wrapU = 1; } else if ((uvGen.TextureTiling & 4) != 0) // MIRROR { babylonTexture.wrapU = 2; } babylonTexture.wrapV = 0; // CLAMP if ((uvGen.TextureTiling & 2) != 0) // WRAP { babylonTexture.wrapV = 1; } else if ((uvGen.TextureTiling & 8) != 0) // MIRROR { babylonTexture.wrapV = 2; } babylonTexture.name = Path.GetFileName(texture.MapName); // Animations var animations = new List<BabylonAnimation>(); ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) }); ExportFloatAnimation("vOffset", animations, key => new[] { uvGen.GetVOffs(key) }); ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) }); ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) }); ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) }); ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) }); ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) }); babylonTexture.animations = animations.ToArray(); // Copy texture to output try { if (File.Exists(texture.MapName)) { if (CopyTexturesToOutput) { File.Copy(texture.MapName, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true); } babylonTexture.isCube = IsTextureCube(texture.MapName); } else { var texturepath = Path.Combine(Path.GetDirectoryName(Loader.Core.CurFilePath), babylonTexture.name); if (File.Exists(texturepath)) { if (CopyTexturesToOutput) { File.Copy(texturepath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true); } babylonTexture.isCube = IsTextureCube(texturepath); } else { RaiseWarning(string.Format("Texture {0} not found.", babylonTexture.name), 2); } } } catch { // silently fails } if (babylonTexture.isCube && !allowCube) { RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 2); } return babylonTexture; }
private void ExportMaterial(Material materialNode, BabylonScene babylonScene) { var name = materialNode._Mtl.Name; var id = materialNode.GetGuid().ToString(); RaiseMessage(name, true); if (materialNode.NumSubMaterials > 0) { var babylonMultimaterial = new BabylonMultiMaterial(); babylonMultimaterial.name = name; babylonMultimaterial.id = id; var guids = new List<string>(); for (var index = 0; index < materialNode.NumSubMaterials; index++) { var subMat = materialNode.GetSubMaterial(index) as Material; if (subMat != null) { guids.Add(subMat.GetGuid().ToString()); if (!referencedMaterials.Contains(subMat)) { referencedMaterials.Add(subMat); ExportMaterial(subMat, babylonScene); } } else { guids.Add(Guid.Empty.ToString()); } } babylonMultimaterial.materials = guids.ToArray(); babylonScene.MultiMaterialsList.Add(babylonMultimaterial); return; } var babylonMaterial = new BabylonMaterial(); babylonMaterial.name = name; babylonMaterial.id = id; babylonMaterial.ambient = materialNode.GetAmbient(0).ToArray(); babylonMaterial.diffuse = materialNode.GetDiffuse(0).ToArray(); babylonMaterial.specular = materialNode.GetSpecular(0).Scale(materialNode.GetShinyStrength(0)); babylonMaterial.specularPower = materialNode.GetShininess(0) * 256; babylonMaterial.emissive = materialNode.SelfIlluminationColorOn ? materialNode.GetSelfIllumColor(0).ToArray() : materialNode.GetDiffuse(0).Scale(materialNode.GetSelfIllumination(0)); babylonMaterial.alpha = 1.0f - materialNode.GetTransparency(0); var stdMat = materialNode._Mtl.GetParamBlock(0).Owner as IStdMat2; if (stdMat != null) { // Textures babylonMaterial.ambientTexture = ExportTexture(stdMat, 0, babylonScene); // Ambient babylonMaterial.diffuseTexture = ExportTexture(stdMat, 1, babylonScene); // Diffuse babylonMaterial.specularTexture = ExportTexture(stdMat, 2, babylonScene); // Specular babylonMaterial.emissiveTexture = ExportTexture(stdMat, 5, babylonScene); // Emissive babylonMaterial.opacityTexture = ExportTexture(stdMat, 6, babylonScene); // Opacity babylonMaterial.bumpTexture = ExportTexture(stdMat, 8, babylonScene); // Bump babylonMaterial.reflectionTexture = ExportTexture(stdMat, 9, babylonScene); // Reflection // Constraints if (babylonMaterial.diffuseTexture != null) { babylonMaterial.emissive = new [] { 1.0f, 1.0f, 1.0f }; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new float[]{0, 0, 0}; } if (babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.name == babylonMaterial.opacityTexture.name && babylonMaterial.diffuseTexture.hasAlpha && !babylonMaterial.opacityTexture.getAlphaFromRGB) { // This is a alpha testing purpose babylonMaterial.opacityTexture = null; babylonMaterial.diffuseTexture.hasAlpha = true; RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", true); RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", true); } } babylonScene.MaterialsList.Add(babylonMaterial); }
private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene) { var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) }; babylonSkeleton.name = "skeleton #" + babylonSkeleton.id; RaiseMessage(babylonSkeleton.name, 1); var skinIndex = skins.IndexOf(skin); var bones = new List<BabylonBone>(); var gameBones = new List<IIGameNode>(); var boneIds = new List<int>(); var bindPoseInfos = new List<BonePoseInfo>(); for(int i = 0; i < skin.TotalSkinBoneCount; ++i) { bones.Add(null); gameBones.Add(null); boneIds.Add(-1); bindPoseInfos.Add(null); } for (var index = 0; index < skin.TotalSkinBoneCount; index++) { var gameBone = skin.GetIGameBone(index, false); var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID); gameBones[sortedIndex] = (gameBone); boneIds[sortedIndex] =(gameBone.NodeID); bones[sortedIndex]=(new BabylonBone { index = sortedIndex, name = gameBone.Name }); var boneInitMatrix = gameBone.GetObjectTM(0); bindPoseInfos[sortedIndex] = (new BonePoseInfo { AbsoluteTransform = boneInitMatrix }); } // fix hierarchy an generate animation keys var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations"); for (var index = 0; index < skin.TotalSkinBoneCount; index++) { var gameBone = gameBones[index]; var parent = gameBone.NodeParent; var babBone = bones[index]; if (parent != null) { babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID); } if (babBone.parentBoneIndex == -1) { bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform; } else { var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex]; bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse); } babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray(); var babylonAnimation = new BabylonAnimation { name = gameBone.Name + "Animation", property = "_matrix", dataType = (int)BabylonAnimation.DataType.Matrix, loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.Global.FrameRate }; var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List<BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var objectTM = gameBone.GetObjectTM(key); var parentNode = gameBone.NodeParent; IGMatrix mat; if (parentNode == null || babBone.parentBoneIndex == -1) { mat = objectTM; } else { mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse); } var current = mat.ToArray(); if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current))) { keys.Add(new BabylonAnimationKey { frame = key / Ticks, values = current }); } previous = current; } babylonAnimation.keys = keys.ToArray(); babBone.animation = babylonAnimation; } babylonSkeleton.needInitialSkinMatrix = true; babylonSkeleton.bones = bones.ToArray(); babylonScene.SkeletonsList.Add(babylonSkeleton); }
private void ExportMaterial(IIGameMaterial materialNode, BabylonScene babylonScene) { var name = materialNode.MaterialName; var id = materialNode.MaxMaterial.GetGuid().ToString(); RaiseMessage(name, 1); if (materialNode.SubMaterialCount > 0) { var babylonMultimaterial = new BabylonMultiMaterial { name = name, id = id }; var guids = new List<string>(); for (var index = 0; index < materialNode.SubMaterialCount; index++) { var subMat = materialNode.GetSubMaterial(index); if (subMat != null) { guids.Add(subMat.MaxMaterial.GetGuid().ToString()); if (!referencedMaterials.Contains(subMat)) { referencedMaterials.Add(subMat); ExportMaterial(subMat, babylonScene); } } else { guids.Add(Guid.Empty.ToString()); } } babylonMultimaterial.materials = guids.ToArray(); babylonScene.MultiMaterialsList.Add(babylonMultimaterial); return; } var babylonMaterial = new BabylonStandardMaterial { name = name, id = id, ambient = materialNode.MaxMaterial.GetAmbient(0, false).ToArray(), diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(), specular = materialNode.MaxMaterial.GetSpecular(0, false).Scale(materialNode.MaxMaterial.GetShinStr(0, false)), specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256, emissive = materialNode.MaxMaterial.GetSelfIllumColorOn(0, false) ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray() : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)), alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false) }; var stdMat = materialNode.MaxMaterial.GetParamBlock(0).Owner as IStdMat2; if (stdMat != null) { babylonMaterial.backFaceCulling = !stdMat.TwoSided; babylonMaterial.wireframe = stdMat.Wire; // Textures BabylonFresnelParameters fresnelParameters; babylonMaterial.ambientTexture = ExportTexture(stdMat, 0, out fresnelParameters, babylonScene); // Ambient babylonMaterial.diffuseTexture = ExportTexture(stdMat, 1, out fresnelParameters, babylonScene); // Diffuse if (fresnelParameters != null) { babylonMaterial.diffuseFresnelParameters = fresnelParameters; } babylonMaterial.specularTexture = ExportTexture(stdMat, 2, out fresnelParameters, babylonScene); // Specular babylonMaterial.emissiveTexture = ExportTexture(stdMat, 5, out fresnelParameters, babylonScene); // Emissive if (fresnelParameters != null) { babylonMaterial.emissiveFresnelParameters = fresnelParameters; if (babylonMaterial.emissive[0] == 0 && babylonMaterial.emissive[1] == 0 && babylonMaterial.emissive[2] == 0 && babylonMaterial.emissiveTexture == null) { babylonMaterial.emissive = new float[] { 1, 1, 1 }; } } babylonMaterial.opacityTexture = ExportTexture(stdMat, 6, out fresnelParameters, babylonScene, false, true); // Opacity if (fresnelParameters != null) { babylonMaterial.opacityFresnelParameters = fresnelParameters; if (babylonMaterial.alpha == 1 && babylonMaterial.opacityTexture == null) { babylonMaterial.alpha = 0; } } babylonMaterial.bumpTexture = ExportTexture(stdMat, 8, out fresnelParameters, babylonScene); // Bump babylonMaterial.reflectionTexture = ExportTexture(stdMat, 9, out fresnelParameters, babylonScene, true); // Reflection if (fresnelParameters != null) { if (babylonMaterial.reflectionTexture == null) { RaiseWarning("Fallout cannot be used with reflection channel without a texture", 2); } else { babylonMaterial.reflectionFresnelParameters = fresnelParameters; } } // Constraints if (babylonMaterial.diffuseTexture != null) { babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f }; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new float[] { 0, 0, 0 }; } if (babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.name == babylonMaterial.opacityTexture.name && babylonMaterial.diffuseTexture.hasAlpha && !babylonMaterial.opacityTexture.getAlphaFromRGB) { // This is a alpha testing purpose babylonMaterial.opacityTexture = null; babylonMaterial.diffuseTexture.hasAlpha = true; RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", 2); RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", 2); } } babylonScene.MaterialsList.Add(babylonMaterial); }
public async Task ExportAsync(string outputFile, bool generateManifest, Form callerForm) { IsCancelled = false; RaiseMessage("Exportation started", Color.Blue); ReportProgressChanged(0); var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile)); var maxScene = Loader.Core.RootNode; alreadyExportedTextures.Clear(); if (!Directory.Exists(babylonScene.OutputPath)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); // Save scene RaiseMessage("Saving 3ds max file"); if (AutoSave3dsMaxFile) { var forceSave = Loader.Core.FileSave; if (callerForm != null) { callerForm.BringToFront(); } } // Global babylonScene.autoClear = true; babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); babylonScene.gravity = maxScene.GetVector3Property("babylonjs_gravity"); exportQuaternionsInsteadOfEulers = maxScene.GetBoolProperty("babylonjs_exportquaternions", 1); // Cameras BabylonCamera mainCamera = null; RaiseMessage("Exporting cameras"); foreach (var cameraNode in maxScene.NodesListBySuperClass(SClass_ID.Camera)) { ExportCamera(cameraNode, babylonScene); if (mainCamera == null && babylonScene.CamerasList.Count > 0) { mainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = mainCamera.id; RaiseMessage("Active camera set to " + mainCamera.name, Color.Green, 1, true); } } if (mainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Fog for (var index = 0; index < Loader.Core.NumAtmospheric; index++) { var atmospheric = Loader.Core.GetAtmospheric(index); if (atmospheric.Active(0) && atmospheric.ClassName == "Fog") { var fog = atmospheric as IStdFog; if (fog != null) { RaiseMessage("Exporting fog"); babylonScene.fogColor = fog.GetColor(0).ToArray(); babylonScene.fogDensity = fog.GetDensity(0); babylonScene.fogMode = fog.GetType_ == 0 ? 3 : 1; if (mainCamera != null) { babylonScene.fogStart = mainCamera.minZ*fog.GetNear(0); babylonScene.fogEnd = mainCamera.maxZ*fog.GetFar(0); } } } } // Meshes ReportProgressChanged(10); RaiseMessage("Exporting meshes"); var meshes = maxScene.NodesListBySuperClasses(new[] { SClass_ID.Geomobject, SClass_ID.Helper }); var progressionStep = 80.0f / meshes.Count(); var progression = 10.0f; foreach (var meshNode in meshes) { Tools.PreparePipeline(meshNode, true); ExportMesh(meshNode, babylonScene); Tools.PreparePipeline(meshNode, false); progression += progressionStep; ReportProgressChanged((int)progression); CheckCancelled(); } RaiseMessage(string.Format("Total: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // Materials RaiseMessage("Exporting materials"); var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials foreach (var mat in matsToExport) { ExportMaterial(mat, babylonScene); CheckCancelled(); } RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1); // Lights RaiseMessage("Exporting lights"); foreach (var lightNode in maxScene.NodesListBySuperClass(SClass_ID.Light)) { ExportLight(lightNode, babylonScene); CheckCancelled(); } if (babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", 1); RaiseWarning("A default hemispheric light was added for your convenience", 1); ExportDefaultLight(babylonScene); } else { RaiseMessage(string.Format("Total: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } // Skeletons if (skins.Count > 0) { RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); skin.Dispose(); } } // Output RaiseMessage("Saving to output file"); babylonScene.Prepare(false); var jsonSerializer = JsonSerializer.Create(); var sb = new StringBuilder(); var sw = new StringWriter(sb, CultureInfo.InvariantCulture); await Task.Run(() => { using (var jsonWriter = new JsonTextWriterOptimized(sw)) { jsonWriter.Formatting = Formatting.None; jsonSerializer.Serialize(jsonWriter, babylonScene); } File.WriteAllText(outputFile, sb.ToString()); if (generateManifest) { File.WriteAllText(outputFile + ".manifest", "{\r\n\"version\" : 1,\r\n\"enableSceneOffline\" : true,\r\n\"enableTexturesOffline\" : true\r\n}"); } }); ReportProgressChanged(100); watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
private void ExportLight(IIGameScene scene, IIGameNode lightNode, BabylonScene babylonScene) { if (lightNode.MaxNode.GetBoolProperty("babylonjs_noexport")) { return; } var gameLight = lightNode.IGameObject.AsGameLight(); var initialized = gameLight.InitializeData; var babylonLight = new BabylonLight(); RaiseMessage(lightNode.Name, 1); babylonLight.name = lightNode.Name; babylonLight.id = lightNode.MaxNode.GetGuid().ToString(); if (lightNode.NodeParent != null) { babylonLight.parentId = GetParentID(lightNode.NodeParent, babylonScene, scene); } // Type var maxLight = (lightNode.MaxNode.ObjectRef as ILightObject); var lightState = Loader.Global.LightState.Create(); maxLight.EvalLightState(0, Tools.Forever, lightState); 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 }; break; } // Shadows if (maxLight.ShadowMethod == 1) { if (lightState.Type == LightType.DirectLgt || lightState.Type == LightType.SpotLgt) { ExportShadowGenerator(lightNode.MaxNode, babylonScene); } else { RaiseWarning("Shadows maps are only supported for directional and spot lights", 2); } } // Position var wm = lightNode.GetObjectTM(0); if (lightNode.NodeParent != null) { var parentWorld = lightNode.NodeParent.GetObjectTM(0); wm.MultiplyBy(parentWorld.Inverse); } var position = wm.Translation; babylonLight.position = new[] { position.X, position.Y, position.Z }; // Direction var target = gameLight.LightTarget; if (target != null) { var targetWm = target.GetObjectTM(0); var targetPosition = targetWm.Translation; var direction = targetPosition.Subtract(position).Normalize; babylonLight.direction = new[] { direction.X, direction.Y, direction.Z }; } else { var vDir = Loader.Global.Point3.Create(0, -1, 0); vDir = wm.ExtractMatrix3().VectorTransform(vDir).Normalize; babylonLight.direction = new[] { vDir.X, vDir.Y, vDir.Z }; } var maxScene = Loader.Core.RootNode; // Exclusion 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>(); ExportVector3Animation("position", animations, key => { var mat = lightNode.GetObjectTM(key); if (lightNode.NodeParent != null) { var parentWorld = lightNode.NodeParent.GetObjectTM(key); mat.MultiplyBy(parentWorld.Inverse); } var pos = mat.Translation; return new[] { pos.X, pos.Y, pos.Z }; }); ExportVector3Animation("direction", animations, key => { var wmLight = lightNode.GetObjectTM(key); if (lightNode.NodeParent != null) { var parentWorld = lightNode.NodeParent.GetObjectTM(key); wmLight.MultiplyBy(parentWorld.Inverse); } var positionLight = wmLight.Translation; var lightTarget = gameLight.LightTarget; if (lightTarget != null) { var targetWm = lightTarget.GetObjectTM(key); var targetPosition = targetWm.Translation; var direction = targetPosition.Subtract(positionLight).Normalize; return new[] { direction.X, direction.Y, direction.Z }; } else { var vDir = Loader.Global.Point3.Create(0, -1, 0); vDir = wmLight.ExtractMatrix3().VectorTransform(vDir).Normalize; return new[] { vDir.X, vDir.Y, vDir.Z }; } }); ExportFloatAnimation("intensity", animations, key => new[] { maxLight.GetIntensity(key, Tools.Forever) }); babylonLight.animations = animations.ToArray(); if (lightNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonLight.autoAnimate = true; babylonLight.autoAnimateFrom = (int)lightNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonLight.autoAnimateTo = (int)lightNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonLight.autoAnimateLoop = lightNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.LightsList.Add(babylonLight); }
private BabylonTexture ExportTexture(IStdMat2 stdMat, int index, out BabylonFresnelParameters fresnelParameters, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false) { fresnelParameters = null; if (!stdMat.MapEnabled(index)) { return null; } var babylonTexture = new BabylonTexture(); var texMap = stdMat.GetSubTexmap(index); // Fallout if (texMap.ClassName == "Falloff") // This is the only way I found to detect it. This is crappy but it works { fresnelParameters = new BabylonFresnelParameters(); var paramBlock = texMap.GetParamBlock(0); var color1 = paramBlock.GetColor(0, 0, 0); var color2 = paramBlock.GetColor(4, 0, 0); fresnelParameters.isEnabled = true; fresnelParameters.leftColor = color2.ToArray(); fresnelParameters.rightColor = color1.ToArray(); if (paramBlock.GetInt(8, 0, 0) == 2) { fresnelParameters.power = paramBlock.GetFloat(12, 0, 0); } else { fresnelParameters.power = 1; } var texMap1 = paramBlock.GetTexmap(2, 0, 0); var texMap1On = paramBlock.GetInt(3, 0, 0); var texMap2 = paramBlock.GetTexmap(6, 0, 0); var texMap2On = paramBlock.GetInt(7, 0, 0); if (texMap1 != null && texMap1On != 0) { texMap = texMap1; fresnelParameters.rightColor = new float[] { 1, 1, 1 }; if (texMap2 != null && texMap2On != 0) { RaiseWarning(string.Format("You cannot specify two textures for falloff. Only one is supported"), 2); } } else if (texMap2 != null && texMap2On != 0) { fresnelParameters.leftColor = new float[] { 1, 1, 1 }; texMap = texMap2; } else { return null; } } // Bitmap var texture = texMap.GetParamBlock(0).Owner as IBitmapTex; if (texture == null) { return null; } if (forceAlpha) { babylonTexture.hasAlpha = true; babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3); } else { babylonTexture.hasAlpha = (texture.AlphaSource != 3); babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2); } babylonTexture.level = stdMat.GetTexmapAmt(index, 0); var uvGen = texture.UVGen; switch (uvGen.GetCoordMapping(0)) { case 1: //MAP_SPHERICAL babylonTexture.coordinatesMode = 1; break; case 2: //MAP_PLANAR babylonTexture.coordinatesMode = 2; break; default: babylonTexture.coordinatesMode = 0; break; } babylonTexture.coordinatesIndex = uvGen.MapChannel - 1; if (uvGen.MapChannel > 2) { RaiseWarning(string.Format("Unsupported map channel, Only channel 1 and 2 are supported."), 2); } babylonTexture.uOffset = uvGen.GetUOffs(0); babylonTexture.vOffset = uvGen.GetVOffs(0); babylonTexture.uScale = uvGen.GetUScl(0); babylonTexture.vScale = uvGen.GetVScl(0); if (Path.GetExtension(texture.MapName).ToLower() == ".dds") { babylonTexture.vScale *= -1; // Need to invert Y-axis for DDS texture } babylonTexture.uAng = uvGen.GetUAng(0); babylonTexture.vAng = uvGen.GetVAng(0); babylonTexture.wAng = uvGen.GetWAng(0); babylonTexture.wrapU = 0; // CLAMP if ((uvGen.TextureTiling & 1) != 0) // WRAP { babylonTexture.wrapU = 1; } else if ((uvGen.TextureTiling & 4) != 0) // MIRROR { babylonTexture.wrapU = 2; } babylonTexture.wrapV = 0; // CLAMP if ((uvGen.TextureTiling & 2) != 0) // WRAP { babylonTexture.wrapV = 1; } else if ((uvGen.TextureTiling & 8) != 0) // MIRROR { babylonTexture.wrapV = 2; } babylonTexture.name = Path.GetFileName(texture.MapName); // Animations var animations = new List<BabylonAnimation>(); ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) }); ExportFloatAnimation("vOffset", animations, key => new[] { uvGen.GetVOffs(key) }); ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) }); ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) }); ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) }); ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) }); ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) }); babylonTexture.animations = animations.ToArray(); var absolutePath = texture.Map.FullFilePath; // Copy texture to output try { if (File.Exists(absolutePath)) { babylonTexture.isCube = IsTextureCube(absolutePath); if (CopyTexturesToOutput) { File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true); } } else { RaiseWarning(string.Format("Texture {0} not found.", babylonTexture.name), 2); } } catch { // silently fails } if (babylonTexture.isCube && !allowCube) { RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 2); } return babylonTexture; }
private void ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene) { if (meshNode.MaxNode.IsInstance()) { return; } if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport")) { return; } if (!ExportHiddenObjects && meshNode.MaxNode.IsHidden(NodeHideFlags.None, false)) { return; } var gameMesh = meshNode.IGameObject.AsGameMesh(); bool initialized = gameMesh.InitializeData; //needed, the property is in fact a method initializing the exporter that has wrongly been auto // translated into a property because it has no parameters var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() }; if (meshNode.NodeParent != null) { babylonMesh.parentId = GetParentID(meshNode.NodeParent, babylonScene, scene); } // Sounds var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", ""); if (!string.IsNullOrEmpty(soundName)) { var filename = Path.GetFileName(soundName); var meshSound = new BabylonSound { name = filename, autoplay = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_autoplay", 1), loop = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_loop", 1), volume = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_volume", 1.0f), playbackRate = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_playbackrate", 1.0f), connectedMeshId = babylonMesh.id, isDirectional = false, spatialSound = false, distanceModel = meshNode.MaxNode.GetStringProperty("babylonjs_sound_distancemodel", "linear"), maxDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_maxdistance", 100f), rolloffFactor = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_rolloff", 1.0f), refDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_refdistance", 1.0f), }; var isDirectional = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_directional", 0); if (isDirectional) { meshSound.isDirectional = true; meshSound.coneInnerAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneinnerangle", 360f); meshSound.coneOuterAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneouterangle", 360f); meshSound.coneOuterGain = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneoutergain", 1.0f); } babylonScene.SoundsList.Add(meshSound); try { File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true); } catch { } } // Misc. babylonMesh.isVisible = meshNode.MaxNode.Renderable == 1; babylonMesh.pickable = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable"); babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1; babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox"); babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox"); babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1; babylonMesh.alphaIndex = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000); // Actions babylonMesh.actions = ExportNodeAction(meshNode); // Collisions babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); var isSkinned = gameMesh.IsObjectSkinned; var skin = gameMesh.IGameSkin; var unskinnedMesh = gameMesh; IGMatrix skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); List<int> boneIds = null; if (isSkinned) { bonesCount = skin.TotalSkinBoneCount; skins.Add(skin); skinnedNodes.Add(meshNode); babylonMesh.skeletonId = skins.IndexOf(skin); skin.GetInitSkinTM(skinInitPoseMatrix); boneIds = SortBones(skin); skinSortedBones[skin] = boneIds; } // Position / rotation / scaling var localTM = meshNode.GetObjectTM(0); if (meshNode.NodeParent != null) { var parentWorld = meshNode.NodeParent.GetObjectTM(0); localTM.MultiplyBy(parentWorld.Inverse); } var meshTrans = localTM.Translation; var meshRotation = localTM.Rotation; var meshScale = localTM.Scaling; var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions"); babylonMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z }; if (exportQuaternions) { babylonMesh.rotationQuaternion = new[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W }; } else { RotationToEulerAngles(babylonMesh, meshRotation); } babylonMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z }; // Mesh RaiseMessage(meshNode.Name, 1); if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null) { if (unskinnedMesh.NumberOfFaces < 1) { RaiseError(string.Format("Mesh {0} has no face", babylonMesh.name), 2); } if (unskinnedMesh.NumberOfVerts < 3) { RaiseError(string.Format("Mesh {0} has not enough vertices", babylonMesh.name), 2); } if (unskinnedMesh.NumberOfVerts >= 65536) { RaiseWarning(string.Format("Mesh {0} has tmore than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", babylonMesh.name), 2); } // Physics var impostorText = meshNode.MaxNode.GetStringProperty("babylonjs_impostor", "None"); if (impostorText != "None") { switch (impostorText) { case "Sphere": babylonMesh.physicsImpostor = 1; break; case "Box": babylonMesh.physicsImpostor = 2; break; case "Plane": babylonMesh.physicsImpostor = 3; break; default: babylonMesh.physicsImpostor = 0; break; } babylonMesh.physicsMass = meshNode.MaxNode.GetFloatProperty("babylonjs_mass"); babylonMesh.physicsFriction = meshNode.MaxNode.GetFloatProperty("babylonjs_friction", 0.2f); babylonMesh.physicsRestitution = meshNode.MaxNode.GetFloatProperty("babylonjs_restitution", 0.2f); } // Material var mtl = meshNode.NodeMaterial; var multiMatsCount = 1; if (mtl != null) { babylonMesh.materialId = mtl.MaxMaterial.GetGuid().ToString(); if (!referencedMaterials.Contains(mtl)) { referencedMaterials.Add(mtl); } multiMatsCount = Math.Max(mtl.SubMaterialCount, 1); } babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever); var vertices = new List<GlobalVertex>(); var indices = new List<int>(); var mappingChannels = unskinnedMesh.ActiveMapChannelNum; bool hasUV = false; bool hasUV2 = false; for (int i = 0; i < mappingChannels.Count; ++i) { var indexer = new IntPtr(i); var channelNum = mappingChannels[indexer]; if (channelNum == 1) { hasUV = true; } else if (channelNum == 2) { hasUV2 = true; } } var hasColor = unskinnedMesh.NumberOfColorVerts > 0; var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0; var optimizeVertices = meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices"); // Compute normals List<GlobalVertex>[] verticesAlreadyExported = null; if (optimizeVertices) { verticesAlreadyExported = new List<GlobalVertex>[unskinnedMesh.NumberOfVerts]; } var subMeshes = new List<BabylonSubMesh>(); var indexStart = 0; for (int i = 0; i < multiMatsCount; ++i) { int materialId = meshNode.NodeMaterial == null ? 0 : meshNode.NodeMaterial.GetMaterialID(i); var indexCount = 0; var minVertexIndex = int.MaxValue; var maxVertexIndex = int.MinValue; var subMesh = new BabylonSubMesh { indexStart = indexStart, materialIndex = i }; if (multiMatsCount == 1) { for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j) { var face = unskinnedMesh.GetFace(j); ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds); } } else { ITab<IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId); for (int j = 0; j < materialFaces.Count; ++j) { var faceIndexer = new IntPtr(j); var face = materialFaces[faceIndexer]; Marshal.FreeHGlobal(faceIndexer); ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds); } } if (indexCount != 0) { subMesh.indexCount = indexCount; subMesh.verticesStart = minVertexIndex; subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1; indexStart += indexCount; subMeshes.Add(subMesh); } } if (vertices.Count >= 65536) { RaiseWarning(string.Format("Mesh {0} has {1} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", babylonMesh.name, vertices.Count), 2); if (!optimizeVertices) { RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2); } } RaiseMessage(string.Format("{0} vertices, {1} faces", vertices.Count, indices.Count / 3), 2); // Buffers babylonMesh.positions = vertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray(); babylonMesh.normals = vertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray(); if (hasUV) { babylonMesh.uvs = vertices.SelectMany(v => new[] { v.UV.X, 1 - v.UV.Y }).ToArray(); } if (hasUV2) { babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray(); } if (skin != null) { babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray(); babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray(); } if (hasColor) { babylonMesh.colors = vertices.SelectMany(v => v.Color.ToArray()).ToArray(); babylonMesh.hasVertexAlpha = hasAlpha; } babylonMesh.subMeshes = subMeshes.ToArray(); // Buffers - Indices babylonMesh.indices = indices.ToArray(); } // Instances var tabs = Loader.Global.NodeTab.Create(); Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs); var instances = new List<BabylonAbstractMesh>(); for (var index = 0; index < tabs.Count; index++) { var indexer = new IntPtr(index); var tab = tabs[indexer]; Marshal.FreeHGlobal(indexer); if (meshNode.MaxNode.GetGuid() == tab.GetGuid()) { continue; } var instanceGameNode = scene.GetIGameNode(tab); if (instanceGameNode == null) { continue; } tab.MarkAsInstance(); var instance = new BabylonAbstractMesh { name = tab.Name }; { var instanceLocalTM = instanceGameNode.GetObjectTM(0); var instanceTrans = instanceLocalTM.Translation; var instanceRotation = instanceLocalTM.Rotation; var instanceScale = instanceLocalTM.Scaling; instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z }; if (exportQuaternions) { instance.rotationQuaternion = new[] { instanceRotation.X, instanceRotation.Y, instanceRotation.Z, -instanceRotation.W }; } else { RotationToEulerAngles(instance, instanceRotation); } instance.scaling = new[] { instanceScale.X, instanceScale.Y, instanceScale.Z }; } var instanceAnimations = new List<BabylonAnimation>(); GenerateCoordinatesAnimations(meshNode, instanceAnimations); instance.animations = instanceAnimations.ToArray(); instances.Add(instance); } babylonMesh.instances = instances.ToArray(); // Animations var animations = new List<BabylonAnimation>(); GenerateCoordinatesAnimations(meshNode, animations); if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations)) { ExportFloatAnimation("visibility", animations, key => new[] { meshNode.MaxNode.GetVisibility(key, Tools.Forever) }); } babylonMesh.animations = animations.ToArray(); if (meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimate", 1)) { babylonMesh.autoAnimate = true; babylonMesh.autoAnimateFrom = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonMesh.autoAnimateTo = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to", 100); babylonMesh.autoAnimateLoop = meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop", 1); } babylonScene.MeshesList.Add(babylonMesh); }
private void ExportCamera(IIGameScene scene, IIGameNode cameraNode, BabylonScene babylonScene) { if (cameraNode.MaxNode.GetBoolProperty("babylonjs_noexport")) { return; } var gameCamera = cameraNode.IGameObject.AsGameCamera(); var maxCamera = gameCamera.MaxObject as ICameraObject; var initialized = gameCamera.InitializeData; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, 1); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString(); if (cameraNode.NodeParent != null) { babylonCamera.parentId = GetParentID(cameraNode.NodeParent, babylonScene, scene); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever)); if (maxCamera.ManualClip == 1) { babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever); babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever); } else { babylonCamera.minZ = 0.1f; babylonCamera.maxZ = 10000.0f; } if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // Type babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera"); // Control babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f); babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f); // Collisions babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity"); babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid"); // Position var wm = cameraNode.GetLocalTM(0); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(0); wm.MultiplyBy(parentWorld.Inverse); } var position = wm.Translation; babylonCamera.position = new [] { position.X, position.Y, position.Z }; // Target var target = gameCamera.CameraTarget; if (target != null) { babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString(); } else { var dir = wm.GetRow(3); babylonCamera.target = new [] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z }; } // Animations var animations = new List<BabylonAnimation>(); ExportVector3Animation("position", animations, key => { var tm = cameraNode.GetLocalTM(key); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(key); tm.MultiplyBy(parentWorld.Inverse); } var translation = tm.Translation; return new [] { translation.X, translation.Y, translation.Z }; }); if (gameCamera.CameraTarget == null) { ExportVector3Animation("target", animations, key => { var tm = cameraNode.GetLocalTM(key); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(key); tm.MultiplyBy(parentWorld.Inverse); } var translation = tm.Translation; var dir = tm.GetRow(3); return new float[] { translation.X - dir.X, translation.Y - dir.Y, translation.Z - dir.Z }; }); } ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); }
public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, bool generateBinary, Form callerForm) { var gameConversionManger = Loader.Global.ConversionManager; gameConversionManger.CoordSystem = Autodesk.Max.IGameConversionManager.CoordSystem.D3d; var gameScene = Loader.Global.IGameInterface; gameScene.InitialiseIGame(onlySelected); gameScene.SetStaticFrame(0); MaxSceneFileName = gameScene.SceneFileName; IsCancelled = false; RaiseMessage("Exportation started", Color.Blue); ReportProgressChanged(0); var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile)); var rawScene = Loader.Core.RootNode; if (!Directory.Exists(babylonScene.OutputPath)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); // Save scene RaiseMessage("Saving 3ds max file"); if (AutoSave3dsMaxFile) { var forceSave = Loader.Core.FileSave; if (callerForm != null) { callerForm.BringToFront(); } } // Global babylonScene.autoClear = true; babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); babylonScene.gravity = rawScene.GetVector3Property("babylonjs_gravity"); ExportQuaternionsInsteadOfEulers = rawScene.GetBoolProperty("babylonjs_exportquaternions", 1); // Sounds var soundName = rawScene.GetStringProperty("babylonjs_sound_filename", ""); if (!string.IsNullOrEmpty(soundName)) { var filename = Path.GetFileName(soundName); var globalSound = new BabylonSound { autoplay = rawScene.GetBoolProperty("babylonjs_sound_autoplay", 1), loop = rawScene.GetBoolProperty("babylonjs_sound_loop", 1), name = filename }; babylonScene.SoundsList.Add(globalSound); try { File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true); } catch { } } // Cameras BabylonCamera mainCamera = null; ICameraObject mainCameraNode = null; RaiseMessage("Exporting cameras"); var camerasTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera); for (int ix = 0; ix < camerasTab.Count; ++ix) { var indexer = new IntPtr(ix); var cameraNode = camerasTab[indexer]; Marshal.FreeHGlobal(indexer); ExportCamera(gameScene, cameraNode, babylonScene); if (mainCamera == null && babylonScene.CamerasList.Count > 0) { mainCameraNode = (cameraNode.MaxNode.ObjectRef as ICameraObject); mainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = mainCamera.id; RaiseMessage("Active camera set to " + mainCamera.name, Color.Green, 1, true); } } if (mainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Fog for (var index = 0; index < Loader.Core.NumAtmospheric; index++) { var atmospheric = Loader.Core.GetAtmospheric(index); if (atmospheric.Active(0) && atmospheric.ClassName == "Fog") { var fog = atmospheric as IStdFog; RaiseMessage("Exporting fog"); if (fog != null) { babylonScene.fogColor = fog.GetColor(0).ToArray(); babylonScene.fogMode = 3; } #if !MAX2015 && !MAX2016 else { var paramBlock = atmospheric.GetReference(0) as IIParamBlock; babylonScene.fogColor = Tools.GetParamBlockValueColor(paramBlock, "Fog Color"); babylonScene.fogMode = 3; } #endif if (mainCamera != null) { babylonScene.fogStart = mainCameraNode.GetEnvRange(0, 0, Tools.Forever); babylonScene.fogEnd = mainCameraNode.GetEnvRange(0, 1, Tools.Forever); } } } // Meshes ReportProgressChanged(10); RaiseMessage("Exporting meshes"); var meshes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Mesh); var progressionStep = 80.0f / meshes.Count; var progression = 10.0f; for (int ix = 0; ix < meshes.Count; ++ix) { var indexer = new IntPtr(ix); var meshNode = meshes[indexer]; Marshal.FreeHGlobal(indexer); ExportMesh(gameScene, meshNode, babylonScene); ReportProgressChanged((int)progression); progression += progressionStep; CheckCancelled(); } // Materials RaiseMessage("Exporting materials"); var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials foreach (var mat in matsToExport) { ExportMaterial(mat, babylonScene); CheckCancelled(); } RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1); // Lights RaiseMessage("Exporting lights"); var lightNodes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light); for (var i = 0; i < lightNodes.Count; ++i) { ExportLight(gameScene, lightNodes[new IntPtr(i)], babylonScene); CheckCancelled(); } if (babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", 1); RaiseWarning("A default hemispheric light was added for your convenience", 1); ExportDefaultLight(babylonScene); } else { RaiseMessage(string.Format("Total: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } // Skeletons if (skins.Count > 0) { RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // Actions babylonScene.actions = ExportNodeAction(gameScene.GetIGameNode(rawScene)); // Output RaiseMessage("Saving to output file"); babylonScene.Prepare(false); var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings()); var sb = new StringBuilder(); var sw = new StringWriter(sb, CultureInfo.InvariantCulture); await Task.Run(() => { using (var jsonWriter = new JsonTextWriterOptimized(sw)) { jsonWriter.Formatting = Formatting.None; jsonSerializer.Serialize(jsonWriter, babylonScene); } File.WriteAllText(outputFile, sb.ToString()); if (generateManifest) { File.WriteAllText(outputFile + ".manifest", "{\r\n\"version\" : 1,\r\n\"enableSceneOffline\" : true,\r\n\"enableTexturesOffline\" : true\r\n}"); } }); // Binary if (generateBinary) { RaiseMessage("Generating binary files"); BabylonFileConverter.BinaryConverter.Convert(outputFile, Path.GetDirectoryName(outputFile) + "\\Binary", message => RaiseMessage(message, 1), error => RaiseError(error, 1)); } ReportProgressChanged(100); watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
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); }
public void Export(string outputFile) { IsCancelled = false; RaiseMessage("Exportation started"); ReportProgressChanged(0); var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile)); var maxScene = Kernel.Scene; alreadyExportedTextures.Clear(); if (!Directory.Exists(babylonScene.OutputPath)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } // Save scene RaiseMessage("Saving 3ds max file"); var forceSave = Loader.Core.FileSave; // Global babylonScene.autoClear = true; babylonScene.clearColor = Loader.Core.GetBackGround(0, Interval.Forever._IInterval).ToArray(); babylonScene.ambientColor = Loader.Core.GetAmbient(0, Interval.Forever._IInterval).ToArray(); babylonScene.gravity = maxScene.RootNode._Node.GetVector3Property("babylonjs_gravity"); // Cameras BabylonCamera mainCamera = null; RaiseMessage("Exporting cameras"); foreach (var cameraNode in maxScene.NodesListBySuperClass(SuperClassID.Camera)) { ExportCamera(cameraNode, babylonScene); if (mainCamera == null && babylonScene.CamerasList.Count > 0) { mainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = mainCamera.id; RaiseMessage("Active camera set to " + mainCamera.name, true, true); } } if (mainCamera == null) { RaiseWarning("No camera defined", true); } // Fog for (var index = 0; index < Loader.Core.NumAtmospheric; index++) { var atmospheric = Loader.Core.GetAtmospheric(index); if (atmospheric.Active(0) && atmospheric.ClassName == "Fog") { RaiseMessage("Exporting fog"); var reference = atmospheric.GetReference(0); var parameters = Animatable.CreateWrapper<ParameterBlock1>(reference); babylonScene.fogColor = (parameters["fog color"].Value as IColor).ToArray(); babylonScene.fogDensity = (float)parameters["density"].Value; babylonScene.fogMode = ((int)parameters["fog type"].Value) == 0 ? 3 : 1; if (mainCamera != null) { babylonScene.fogStart = mainCamera.minZ * (float)parameters["near %"].Value; babylonScene.fogEnd = mainCamera.maxZ * (float)parameters["far %"].Value; } } } // Meshes ReportProgressChanged(10); RaiseMessage("Exporting meshes"); var meshes = maxScene.NodesListBySuperClasses(new[] {SuperClassID.GeometricObject, SuperClassID.Helper}); var progressionStep = 80.0f / meshes.Count(); var progression = 10.0f; foreach (var meshNode in meshes) { Tools.PreparePipeline(meshNode._Node, true); ExportMesh(meshNode, babylonScene); Tools.PreparePipeline(meshNode._Node, false); progression += progressionStep; ReportProgressChanged((int)progression); CheckCancelled(); } // Materials RaiseMessage("Exporting materials"); var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials foreach (var mat in matsToExport) { ExportMaterial(mat, babylonScene); CheckCancelled(); } // Lights RaiseMessage("Exporting lights"); foreach (var lightNode in maxScene.NodesListBySuperClass(SuperClassID.Light)) { ExportLight(lightNode, babylonScene); CheckCancelled(); } if (babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", true); } // Skeletons RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); skin.Dispose(); } // Output babylonScene.Prepare(false); var jsonSerializer = JsonSerializer.Create(); var sb = new StringBuilder(); var sw = new StringWriter(sb, CultureInfo.InvariantCulture); using (var jsonWriter = new JsonTextWriterOptimized(sw)) { jsonWriter.Formatting = Formatting.None; jsonSerializer.Serialize(jsonWriter, babylonScene); } File.WriteAllText(outputFile, sb.ToString()); ReportProgressChanged(100); RaiseMessage("Exportation done"); }
public virtual void OnExportGameObject(ref Unity3D2Babylon.ExportationOptions exportOptions, ref GameObject unityGameObject, ref UnityMetaData metaData, ref BabylonScene sceneBuilder, string outputPath) { }
private void ExportSkin(IISkin skin, BabylonScene babylonScene) { var babylonSkeleton = new BabylonSkeleton {id = skins.IndexOf(skin)}; babylonSkeleton.name = "skeleton #" + babylonSkeleton.id; RaiseMessage(babylonSkeleton.name, 1); var bones = new List<BabylonBone>(); for (var index = 0; index < skin.NumBones; index++) { var bone = new BabylonBone {name = skin.GetBoneName(index), index = index}; var maxBone = skin.GetBone(index); var parentNode = maxBone.ParentNode; if (parentNode != null) { for (var recurseIndex = 0; recurseIndex < index; recurseIndex++) { if (skin.GetBone(recurseIndex).GetGuid() == parentNode.GetGuid()) { bone.parentBoneIndex = recurseIndex; break; } } } var hasParent = bone.parentBoneIndex != -1; bone.matrix = GetBoneMatrix(skin, maxBone, 0, hasParent); // Animation var babylonAnimation = new BabylonAnimation { name = bone.name + "Animation", property = "_matrix", dataType = BabylonAnimation.DataType.Matrix, loopBehavior = BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.Global.FrameRate }; var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List<BabylonAnimationKey>(); for (var key = start; key <= end; key += Ticks) { var current = GetBoneMatrix(skin, maxBone, key, hasParent); if (key == start || key == end || !(previous.IsEqualTo(current))) { keys.Add(new BabylonAnimationKey { frame = key / Ticks, values = current }); } previous = current; } babylonAnimation.keys = keys.ToArray(); bone.animation = babylonAnimation; bones.Add(bone); } babylonSkeleton.bones = bones.ToArray(); babylonScene.SkeletonsList.Add(babylonSkeleton); }