private BabylonMesh ConvertUnityTerrainToBabylon(Terrain terrain, GameObject gameObject, float progress, ref UnityMetaData metaData, ref List <BabylonExport.Entities.BabylonParticleSystem> particleSystems, ref List <UnityFlareSystem> lensFlares, ref string componentTags) { ExporterWindow.ReportProgress(progress, "Exporting terrain: " + gameObject.name); var transform = gameObject.transform; float[] position = transform.localPosition.ToFloat(); float[] rotation = new float[3]; rotation[0] = transform.localRotation.eulerAngles.x * (float)Math.PI / 180; rotation[1] = transform.localRotation.eulerAngles.y * (float)Math.PI / 180; rotation[2] = transform.localRotation.eulerAngles.z * (float)Math.PI / 180; float[] scaling = transform.localScale.ToFloat(); BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) }; metaData.type = "Terrain"; if (!String.IsNullOrEmpty(componentTags)) { babylonMesh.tags = componentTags; } babylonMesh.tags += " [TERRAIN]"; if (!String.IsNullOrEmpty(babylonMesh.tags)) { babylonMesh.tags = babylonMesh.tags.Trim(); } babylonMesh.parentId = GetParentID(transform); babylonMesh.position = Vector3.zero.ToFloat(); babylonMesh.rotation = rotation; babylonMesh.scaling = scaling; babylonMesh.isVisible = true; babylonMesh.visibility = 1; babylonMesh.checkCollisions = false; metaData.properties["collisionMeshId"] = null; var generator = gameObject.GetComponent <BabylonTerrainGenerator>(); if (generator != null && terrain != null) { // TODO: Terrain tree information object treeInstances = null; object treePrototypes = null; // Terrain metadata infomation Vector3 terrainSize = terrain.terrainData.size; metaData.properties.Add("width", terrainSize.x); metaData.properties.Add("length", terrainSize.z); metaData.properties.Add("height", terrainSize.y); metaData.properties.Add("position", position); metaData.properties.Add("rotation", rotation); metaData.properties.Add("scaling", scaling); metaData.properties.Add("thickness", terrain.terrainData.thickness); metaData.properties.Add("detailWidth", terrain.terrainData.detailWidth); metaData.properties.Add("detailHeight", terrain.terrainData.detailHeight); metaData.properties.Add("heightmapWidth", terrain.terrainData.heightmapWidth); metaData.properties.Add("heightmapHeight", terrain.terrainData.heightmapHeight); metaData.properties.Add("wavingGrassAmount", terrain.terrainData.wavingGrassAmount); metaData.properties.Add("wavingGrassSpeed", terrain.terrainData.wavingGrassSpeed); metaData.properties.Add("wavingGrassStrength", terrain.terrainData.wavingGrassStrength); metaData.properties.Add("wavingGrassTint", terrain.terrainData.wavingGrassTint.ToFloat()); metaData.properties.Add("treeInstanceCount", terrain.terrainData.treeInstanceCount); metaData.properties.Add("treeInstances", treeInstances); metaData.properties.Add("treePrototypes", treePrototypes); metaData.properties.Add("physicsState", generator.physicsActive); metaData.properties.Add("physicsMass", generator.physicsMass); metaData.properties.Add("physicsFriction", generator.physicsFriction); metaData.properties.Add("physicsRestitution", generator.physicsRestitution); metaData.properties.Add("physicsImpostor", (int)generator.physicsImpostor); metaData.properties.Add("groundTessellation", generator.groundTessellation); // Generate detailed mesh ExporterWindow.ReportProgress(progress, "Generating terrain mesh: " + gameObject.name); BabylonTerrainData terrainMeshData = Unity3D2Babylon.Tools.CreateTerrainData(terrain.terrainData, (int)generator.terrainResolution, transform.localPosition, true); Tools.GenerateBabylonMeshTerrainData(terrainMeshData, babylonMesh, false, babylonScene, transform); if (generator.surfaceMaterial != null) { babylonMesh.materialId = DumpMaterial(generator.surfaceMaterial, terrain.lightmapIndex, terrain.lightmapScaleOffset, generator.coordinatesIndex).id; } // Generate collision heightmap var terrainCollider = gameObject.GetComponent <TerrainCollider>(); if (terrainCollider != null && terrainCollider.enabled) { ExporterWindow.ReportProgress(progress, "Generating terrain heightmap: " + gameObject.name); float minheight = float.MaxValue; float maxheight = float.MinValue; int hwidth = terrain.terrainData.heightmapWidth; int hheight = terrain.terrainData.heightmapHeight; float[,] rawHeights = terrain.terrainData.GetHeights(0, 0, hwidth, hheight); Texture2D heightMap = new Texture2D(hwidth, hheight, TextureFormat.ARGB32, false); for (int y = 0; y < hheight; y++) { for (int x = 0; x < hwidth; x++) { float inverted = rawHeights[y, x]; minheight = Mathf.Min(minheight, inverted); maxheight = Mathf.Max(maxheight, inverted); } } List <Color32> pixels = new List <Color32>(); for (int y = 0; y < hheight; y++) { for (int x = 0; x < hwidth; x++) { float inverted = rawHeights[y, x]; if (generator.heightmapStrength > 0) { float threadhold = minheight + generator.floorThreashold; if (inverted > threadhold) { inverted += (generator.heightmapStrength / 10.0f); } } byte[] packed = BitConverter.GetBytes(inverted); if (packed != null && packed.Length >= 4) { pixels.Add(new Color32(packed[0], packed[1], packed[2], packed[3])); } } } heightMap.SetPixels32(pixels.ToArray()); heightMap.Apply(); byte[] heightmapBytes = heightMap.EncodeToPNG(); metaData.properties.Add("heightmapBase64", ("data:image/png;base64," + Convert.ToBase64String(heightmapBytes))); } } else { UnityEngine.Debug.LogWarning("No valid terrain or generator found for: " + gameObject.name); } babylonMesh.metadata = metaData; babylonScene.MeshesList.Add(babylonMesh); SceneBuilder.Metadata.properties["hasTerrainMeshes"] = true; // Animations ExportAnimations(transform, babylonMesh); if (IsRotationQuaternionAnimated(babylonMesh)) { babylonMesh.rotationQuaternion = transform.localRotation.ToFloat(); } // Lens Flares ParseLensFlares(gameObject, babylonMesh.id, ref lensFlares); // Particles Systems ParseParticleSystems(gameObject, babylonMesh.id, ref particleSystems); return(babylonMesh); }
void Export() { int index = 0; string fileName = EditorUtility.SaveFilePanel("Export Terrain File", "", "Terrain", "obj"); BabylonMesh babylonMesh = new BabylonMesh(); BabylonTerrainData terrainData = Unity3D2Babylon.Tools.CreateTerrainData(terrain, (int)saveResolution, terrainObject.transform.localPosition, false); Unity3D2Babylon.Tools.GenerateBabylonMeshTerrainData(terrainData, babylonMesh, flipNormals); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); StreamWriter sw = new StreamWriter(fileName); try { // StringBuilder stuff is done this way because it's faster than using the "{0} {1} {2}"etc. format // Which is important when you're exporting huge terrains. sw.WriteLine("# U3D - BabylonJS - Terrain Mesh File"); // Write vertices counter = tCount = 0; totalCount = ((babylonMesh.positions.Length / 3) * 2 + (babylonMesh.indices.Length / 3)) / progressUpdateInterval; for (index = 0; index < babylonMesh.positions.Length / 3; index++) { UpdateProgress(); StringBuilder sb = new StringBuilder("v ", 32); sb.Append(babylonMesh.positions[index * 3].ToString()).Append(" "). Append(babylonMesh.positions[index * 3 + 1].ToString()).Append(" "). Append(babylonMesh.positions[index * 3 + 2].ToString()); sw.WriteLine(sb); } // Write normals for (index = 0; index < babylonMesh.normals.Length / 3; index++) { UpdateProgress(); StringBuilder sb = new StringBuilder("vn ", 32); sb.Append(babylonMesh.normals[index * 3].ToString()).Append(" "). Append(babylonMesh.normals[index * 3 + 1].ToString()).Append(" "). Append(babylonMesh.normals[index * 3 + 2].ToString()); sw.WriteLine(sb); } // Write uvs for (index = 0; index < babylonMesh.uvs.Length / 2; index++) { UpdateProgress(); StringBuilder sb = new StringBuilder("vt ", 32); sb.Append(babylonMesh.uvs[index * 2].ToString()).Append(" "). Append(babylonMesh.uvs[index * 2 + 1].ToString()); sw.WriteLine(sb); } // Write triangles for (int i = 0; i < babylonMesh.indices.Length; i += 3) { UpdateProgress(); StringBuilder sb = new StringBuilder("f ", 64); sb.Append(babylonMesh.indices[i] + 1).Append("/").Append(babylonMesh.indices[i] + 1).Append(" "). Append(babylonMesh.indices[i + 1] + 1).Append("/").Append(babylonMesh.indices[i + 1] + 1).Append(" "). Append(babylonMesh.indices[i + 2] + 1).Append("/").Append(babylonMesh.indices[i + 2] + 1); sw.WriteLine(sb); } } catch (Exception err) { Debug.Log("Error saving file: " + err.Message); } sw.Close(); terrain = null; EditorUtility.DisplayProgressBar("Babylon.js", "Saving terrain mesh data... This may take a while.", 1f); AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); this.Close(); }