private static void ApplyTexturesToNewTerrain(TerrainData terrainData, TextureData data) { if (data.ControlTextureResolution != terrainData.alphamapResolution) { data.AdjustSplatMapResolution(terrainData.alphamapResolution); } terrainData.SetAlphamaps(0, 0, data.SplatMaps); }
/// <summary> /// Creates terrain data from heights. /// </summary> /// <param name="heightPercents">Terrain height percentages ranging from 0 to 1.</param> /// <param name="maxHeight">The maximum height of the terrain, corresponding to a height percentage of 1.</param> /// <param name="heightSampleDistance">The horizontal/vertical distance between height samples.</param> /// <param name="splatPrototypes">The textures used by the terrain.</param> /// <param name="alphaMap">Texture blending information.</param> /// <returns>A TerrainData instance.</returns> public static TerrainData CreateTerrainData(float[,] heightPercents, float maxHeight, float heightSampleDistance, SplatPrototype[] splatPrototypes, float[,,] alphaMap) { Debug.Assert((heightPercents.GetLength(0) == heightPercents.GetLength(1)) && (maxHeight >= 0) && (heightSampleDistance >= 0)); // Create the TerrainData. var terrainData = new TerrainData(); terrainData.heightmapResolution = heightPercents.GetLength(0); var terrainWidth = (terrainData.heightmapResolution - 1) * heightSampleDistance; // If maxHeight is 0, leave all the heights in terrainData at 0 and make the vertical size of the terrain 1 to ensure valid AABBs. if(!Mathf.Approximately(maxHeight, 0)) { terrainData.size = new Vector3(terrainWidth, maxHeight, terrainWidth); terrainData.SetHeights(0, 0, heightPercents); } else { terrainData.size = new Vector3(terrainWidth, 1, terrainWidth); } // Texture the terrain. if((splatPrototypes != null) && (alphaMap != null)) { Debug.Assert(alphaMap.GetLength(0) == alphaMap.GetLength(1)); terrainData.alphamapResolution = alphaMap.GetLength(0); terrainData.splatPrototypes = splatPrototypes; terrainData.SetAlphamaps(0, 0, alphaMap); } return terrainData; }
void Start() { tData = myTerrain.terrainData; xResolution = tData.heightmapWidth; zResolution = tData.heightmapHeight; heights = tData.GetHeights(0, 0, xResolution, zResolution); }
void OnGUI() { tWidth = EditorGUILayout.IntField("Terrain Width", tWidth); tHeight = EditorGUILayout.IntField("Terrain Height", tHeight); tDepth = EditorGUILayout.IntField("Terrain Depth", tDepth); EditorGUILayout.Separator(); cellWidth = EditorGUILayout.IntSlider("Cell Width", cellWidth, 1, 512); cellDepth = EditorGUILayout.IntSlider("Cell Depth", cellDepth, 1, 512); cliffLevel = EditorGUILayout.FloatField("Cliff Height", cliffLevel); EditorGUILayout.Separator(); if (GUILayout.Button("Create")) { TerrainData terData = new TerrainData() { size = new Vector3(tWidth, tHeight, tDepth), name = "Map Terrain", heightmapResolution = 512, baseMapResolution = 1024 }; GameObject ter = Terrain.CreateTerrainGameObject(terData); ter.name = "Map"; Gridmap gmap = ter.AddComponent<Gridmap>(); gmap.cellWidth = cellWidth; gmap.cellDepth = cellDepth; gmap.cliffHeight = cliffLevel; isVisible = false; this.Close(); } else if (GUILayout.Button("Cancel")) { isVisible = false; this.Close(); } }
// Update is called once per frame void Update() { transform.Translate(Vector3.forward * Time.deltaTime * Speed); if (transform.position.z >= 2 + float.Epsilon && !go) { go = true; GameObject terrain; TerrainData _terraindata = new TerrainData(); TerrainData t = gameObject.GetComponent<Terrain>().terrainData; terrain = Terrain.CreateTerrainGameObject(t); GameObject ingameTerrainGameObject = (GameObject)Instantiate(terrain, StartPos, Quaternion.identity); //GenerateHeights(gameObject.GetComponent<Terrain>(), 2f); ingameTerrainGameObject.AddComponent<MoveTerrain>(); Destroy(terrain); Destroy(gameObject); } /*if (transform.position.z > 20 + float.Epsilon) Destroy(gameObject);*/ }
private void getTerrain (){ if(Terrain.activeTerrain != null){ r_Terrain = Terrain.activeTerrain; r_TerrainData = r_Terrain.terrainData; r_TerrainPos = r_Terrain.transform.position; } }
void Update() { terrain = GetComponent<Terrain>(); tData = terrain ? terrain.terrainData : null; tMaterial = terrain ? terrain.materialTemplate : null; if (!terrain || !tData || !tMaterial) return; if(disableBasemap && !Application.isPlaying && GetComponent<Terrain>().basemapDistance != 1000000) // only reset on update in edit mode GetComponent<Terrain>().basemapDistance = 1000000; if (cutoutMode) { if (tMaterial.HasProperty("_CutoutModeHideAlpha") && tMaterial.GetFloat("_CutoutModeHideAlpha") != cutoutModeHideAlpha) tMaterial.SetFloat("_CutoutModeHideAlpha", cutoutModeHideAlpha); } else if (tMaterial.HasProperty("_CutoutModeHideAlpha") && tMaterial.GetFloat("_CutoutModeHideAlpha") != -1) tMaterial.SetFloat("_CutoutModeHideAlpha", -1); if (!Application.isPlaying) ApplyTransparencyMap(); else if (!transparencyMap && autoUpdateTransparencyMap) { UpdateTransparencyMap(); ApplyTransparencyMap(); } else ApplyTransparencyMap(); }
public int FindTree(Vector3 location) { terra = Terrain.activeTerrain.terrainData; trees = terra.treeInstances; float maxDistance = float.MaxValue; //int closestIndice = 0; //Vector3 closestTreePos = new Vector3(); int treeType = -1; //float heightScale = 1; //float widthScale = 1; for (int i = 0; i < terra.treeInstances.Length; i++) { TreeInstance currentTree = trees[i]; Vector3 currentTreeWorldPos = Vector3.Scale(currentTree.position, terra.size) + Terrain.activeTerrain.transform.position; float distance = Vector3.Distance(currentTreeWorldPos, location); if (distance < maxDistance) { maxDistance = distance; //closestIndice = i; //closestTreePos = currentTreeWorldPos; treeType = currentTree.prototypeIndex; //heightScale = currentTree.heightScale; //widthScale = currentTree.widthScale; } } return treeType; }
void OnGUI() { go=EditorGUILayout.ObjectField("Terrain game object", go, typeof(GameObject), true) as GameObject; if (!go) return; Terrain terrainObject; terrainObject=go.GetComponent(typeof(Terrain)) as Terrain; if (!terrainObject) return; terrain=terrainObject.terrainData; terrainPos = terrainObject.transform.position; saveFormat = (SaveFormatRTPtweaked) EditorGUILayout.EnumPopup("Export Format", saveFormat); saveResolution = (SaveResolutionRTPtweaked) EditorGUILayout.EnumPopup("Resolution", saveResolution); EditorGUILayout.BeginHorizontal (); EditorGUILayout.LabelField("Slope range (" + Mathf.RoundToInt(loAngle) + "\u00B0 - " + Mathf.RoundToInt(hiAngle) + "\u00B0)"); if (saveFormat==SaveFormatRTPtweaked.Triangles) { EditorGUILayout.MinMaxSlider(ref loAngle, ref hiAngle, 0, 90); } EditorGUILayout.EndHorizontal (); AnchorOffset=EditorGUILayout.Toggle("Anchor Offset", AnchorOffset); if (GUILayout.Button("Export")) { Export(); } }
void Awake() { Debug.Log("Awake WorldMap"); MapTile tempMapTile; BitMapDecoder bmd = new BitMapDecoder(heightmap); terrainData = terrain.terrainData; int heighMapWidth = terrainData.heightmapWidth; int heighMapHeight = terrainData.heightmapHeight; float[,] tempFloat = terrainData.GetHeights(0, 0, heighMapWidth, heighMapHeight); tilesDictionary = new Dictionary<string, MapTile>(); for (int z = 0; z < mapSizeZ; z++ ) { for (int x = 0; x < mapSizeX; x++) { tempMapTile = new MapTile(x,z); int height = BitMapDecoder.getHeightPos(x, z); tempMapTile.setY(height); //tempFloat[x*2+1, z*2+1] = height / 5; tempFloat[x * 2, z*2 * 2] = (float)height / 10; //tempFloat[x*2, z * 2+1] = height / 5; //tempFloat[x * 2 + 1, z * 2] = height / 5; tilesDictionary.Add(("x" + x.ToString() + "z" + z.ToString()), tempMapTile); } } terrain.terrainData.SetHeights(0, 0, tempFloat); }
void Start () { tData = Terrain.activeTerrain.terrainData; SplatPrototype[] terrainTexture = new SplatPrototype[1]; terrainTexture[0] = new SplatPrototype(); terrainTexture[0].texture = (Texture2D)Resources.Load("MyTextures/Dirt"); tData.splatPrototypes = terrainTexture; }
public static void UpdateControlTextureResolution(TerrainData terrainData, int newResolution) { var existingData = GetTerrainTextures(terrainData); terrainData.alphamapResolution = newResolution; ApplyTexturesToNewTerrain(terrainData, existingData); }
private static TextureData GetTerrainTextures(TerrainData terrainData) { return new TextureData { SplatMaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight), ControlTextureResolution = terrainData.alphamapResolution }; }
/// <summary> /// </summary> /// <param name="terrainData"></param> /// <param name="position">Location in the XZ plane (not the XY plane!)</param> /// <param name="sphereRadius"></param> /// <returns></returns> private static Vector3 AdjustSpawnPositionForTerrainShape(TerrainData terrainData, Vector2 position, float sphereRadius) { var height = terrainData.GetInterpolatedHeight(position.x, position.y); var normal = terrainData.GetInterpolatedNormal(position.x, position.y); var offsetAlongNormal = normal * sphereRadius; var positionOnTerrain = new Vector3(position.x, height, position.y); return positionOnTerrain + offsetAlongNormal; }
public Area(TerrainData owner, Block[] blocks) { m_owner = owner; foreach (Block point in blocks) { AddPoint(point); } }
private TerrainData CreateTerrain() { TerrainData terrainData = new TerrainData (); terrainData.size = terrainPrefab.terrainData.size; terrainData.heightmapResolution = terrainPrefab.terrainData.heightmapHeight; terrainData.baseMapResolution = terrainPrefab.terrainData.baseMapResolution; terrainData.SetDetailResolution (terrainPrefab.terrainData.detailResolution, 1); return terrainData; }
public void Awake() { waterScript = (WaterToolScript)target as WaterToolScript; terComponent = (Terrain) waterScript.GetComponent(typeof(Terrain)); if(terComponent == null) Debug.LogError("This script must be attached to a terrain object - Null reference will be thrown"); terData = terComponent.terrainData; terrainHeights = terData.GetHeights(0, 0, terData.heightmapResolution, terData.heightmapResolution); }
void CopyTerrainDataFromTo(TerrainData tDataFrom, ref TerrainData tDataTo) { tDataTo.SetDetailResolution(tDataFrom.detailResolution, 8); tDataTo.heightmapResolution = tDataFrom.heightmapResolution; tDataTo.alphamapResolution = tDataFrom.alphamapResolution; tDataTo.baseMapResolution = tDataFrom.baseMapResolution; tDataTo.size = tDataFrom.size; tDataTo.splatPrototypes = tDataFrom.splatPrototypes; }
public static string[] GetTerrainSplatNames(TerrainData d) { List<string> l = new List<string>(); for (int i = 0; i < d.splatPrototypes.Length; ++i) { l.Add(d.splatPrototypes[i].texture.name); } return l.ToArray(); }
public TerrainTile(Terrain terrain, TerrainData tData, Vector3 index) { Terrain = terrain; TData = tData; TCollider = terrain.GetComponent<TerrainCollider>(); Index = index; InUse = false; Terrain.terrainData = TData; TCollider.terrainData = TData; }
void checkTerrain(JSONNode mines) { terrain_data = terrain.terrainData; // var pos = mines[0]; // float x = pos[0].AsFloat, y = pos[1].AsFloat, z = pos[2].AsFloat; // Debug.Log ("mine0: x: " + x + ", " + "z: " + z + ", " + "y: " + y); // Debug.Log ("InterpolatedHeight: " + terrain_data.GetInterpolatedHeight((x+150.0f)/300.0f, (z+150.0f)/300.0f)); // // pos = mines[1]; // x = pos [0].AsFloat; y = pos [1].AsFloat; z = pos[2].AsFloat; // Debug.Log ("mine1: x: " + x + ", " + "z: " + z + ", " + "y: " + y); // Debug.Log ("InterpolatedHeight: " + terrain_data.GetInterpolatedHeight((x+150.0f)/300.0f, (z+150.0f)/300.0f)); // // pos = mines[2]; // x = pos [0].AsFloat; y = pos[1].AsFloat; z = pos[2].AsFloat; // Debug.Log ("mine2: x: " + x + ", " + "z: " + z + ", " + "y: " + y); // Debug.Log ("InterpolatedHeight: " + terrain_data.GetInterpolatedHeight((x+150.0f)/300.0f, (z+150.0f)/300.0f)); float[] x = new float[200]; float[] y = new float[200]; int mine_num = 200; for (int i = 0; i < mine_num; i++){ var pos = mines[i]; float px = pos[0].AsFloat, py = pos[1].AsFloat, pz = pos[2].AsFloat; x[i] = terrain_data.GetInterpolatedHeight((px+150.0f)/300.0f, (pz+150.0f)/300.0f); y[i] = py; Debug.Log(i); } float mxy = 0; float mx = 0; float mx2 = 0; float my = 0; for (int i = 0; i < mine_num; i++){ mx += x[i]; mx2 += x[i] * x[i]; my += y[i]; mxy += x[i]*y[i]; } mx /= mine_num; mx2 /= mine_num; my /= mine_num; mxy /= mine_num; float a_up = mxy - mx * my; float a_down = mx2 - mx * mx; float a = a_up / a_down; float b = my - a * mx; Debug.Log("a: "+a); Debug.Log("b: "+b); }
public static Mesh createMesh(TerrainData t, Vector3 terrainPosition) { Mesh m = new Mesh(); int w = t.heightmapWidth; int h = t.heightmapHeight; Vector3 meshScale = t.size; int tRes = 2; meshScale = new Vector3(meshScale.x / (w - 1) * tRes, meshScale.y, meshScale.z / (h - 1) * tRes); float[,] tData = t.GetHeights(0, 0, w, h); w = (w - 1) / tRes + 1; h = (h - 1) / tRes + 1; Vector3[] tVertices = new Vector3[w * h]; int[] tPolys; tPolys = new int[(w - 1) * (h - 1) * 6]; // Build vertices for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(-y, tData[x * tRes, y * tRes], x)) + terrainPosition; } } int index = 0; // Build triangle indices: 3 indices into vertex array for each triangle for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { // For each grid cell output two triangles tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = (y * w) + x + 1; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; } } m.vertices = tVertices; m.triangles = tPolys; m.subMeshCount = 1; return m; }
void Start() { terrain = transform.GetComponent<Terrain>(); tData = terrain.terrainData; xRes = tData.heightmapWidth; yRes = tData.heightmapHeight; Debug.Log (xRes + "," + yRes); initializePoints(); }
private void _generateNoise(System.Random rng, TerrainData data) { int width = data.Width; int height = data.Height; for (int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { data.SetValue(x, y, rng.NextDouble() < m_randomFillChance ? 1 : 0); } } }
void Start () { if (terrain == null) { terrain = Terrain.activeTerrain; if (terrain != null) { terrainData = terrain.terrainData; terrainPos = terrain.transform.position; } } }
void Start() { //Only do anything when this is more optimized tData = Terrain.activeTerrain.terrainData; //Get the Terrain lineMaterial = new Material(Shader.Find("Particles/Additive")); changingG = 0; //DrawLinesAnim(); }
/////////////////////////////////// /** * Initialise les attributs. */ void Start () { tData = this.GetComponent<Terrain>().terrainData; hMapTmp = null; inCreation = false; canAddTexture = false; player = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>(); soundController = GameObject.FindGameObjectWithTag("Music").GetComponent<SoundController>(); InitTerrain(); }
private void Awake() { var terrain = GetComponent<Terrain>(); var map = ReadMap(Filename); //var map = ReadMap(string.Format("{0}_{1}", 0, 0)); //var map = GetRandomizedMap(33, 33, 0.2f); var data = new TerrainData { size = new Vector3(100f, 100f, 100f), heightmapResolution = 33 }; terrain.terrainData = data; terrain.terrainData.SetHeights(0, 0, map); }
public void GenerateTerrain(TerrainData terrainData, float tileSize) { if(disableProceduralTerrain) return; _heightMap = new float[terrainData.heightmapWidth, terrainData.heightmapHeight]; float width_2 = terrainData.heightmapWidth*0.5f; float height_2 = terrainData.heightmapHeight*0.5f; float aW = MathHelpers.RandomFromVec2(aWMinMax); float bW = MathHelpers.RandomFromVec2(bWMinMax); float cW = MathHelpers.RandomFromVec2(cWMinMax); float dW = MathHelpers.RandomFromVec2(dWMinMax); float bH = MathHelpers.RandomFromVec2(bHMinMax); float cH = MathHelpers.RandomFromVec2(cHMinMax); for (int i = 0; i < terrainData.heightmapWidth; i++) { for (int k = 0; k < terrainData.heightmapHeight; k++) { float xW = (float)(i - width_2); float xH = (float)(k - height_2); float heightAdjustW = aW*Mathf.Exp(- (Mathf.Pow((xW -bW),2)/(2*Mathf.Pow(cW,2)) + Mathf.Pow((xH-bH),2)/(2*Mathf.Pow(cH,2)))) + dW; _heightMap[i, k] = heightAdjustW + MathHelpers.RandomFromVec2( perlinNoiseAmpMinMax )*Mathf.PerlinNoise(((float)i / (float)terrainData.heightmapWidth) * tileSize, ((float)k / (float)terrainData.heightmapHeight) * tileSize); } } terrainData.SetHeights(0, 0, _heightMap); SplatPrototype groundProto = new SplatPrototype(); groundProto.texture = terrainTexture; groundProto.tileOffset = new Vector2(0f,0f); groundProto.tileSize = new Vector2(10f,10f); SplatPrototype snowProto = new SplatPrototype(); snowProto.texture = snowTexture; snowProto.tileOffset = new Vector2(0f,0f); snowProto.tileSize = new Vector2(10f,10f); SplatPrototype[] prototypes = new SplatPrototype[2]; prototypes[0] = groundProto; prototypes[1] = snowProto; terrainData.splatPrototypes = prototypes; _terrainTransform.localPosition = new Vector3( -0.5f*terrainData.size.x,0f,-0.5f*terrainData.size.z ); }
public override void Construct(TerrainData data) { Vector3 position = transform.position; for (int y = 0; y < data.Height; y++) { for (int x = 0; x < data.Width; x++) { if (data.GetData(x, y) > 0) { float worldX = x * m_blockSize + position.x; float worldZ = y * m_blockSize + position.z; float worldY = position.y; GameObject newBlock = (GameObject) Instantiate(m_blocks[data.GetData(x, y) - 1], new Vector3(worldX, worldY, worldZ), Quaternion.identity); } } } List<EmptyTerrainBlock> emptyTerrain = new List<EmptyTerrainBlock>(FindObjectsOfType<EmptyTerrainBlock>()); int bodyBlock = Random.Range(0, emptyTerrain.Count); Instantiate(m_bodyItems[Random.Range(0, m_bodyItems.Length)], emptyTerrain[bodyBlock].transform.position + Vector3.up * m_blockSize * 0.5f + Vector3.up * m_itemOffset, Quaternion.identity); emptyTerrain.RemoveAt(bodyBlock); int headBlock = Random.Range(0, emptyTerrain.Count); Instantiate(m_headItems[Random.Range(0, m_headItems.Length)], emptyTerrain[headBlock].transform.position + Vector3.up * m_blockSize * 0.5f + Vector3.up * m_itemOffset, Quaternion.identity); emptyTerrain.RemoveAt(headBlock); int leftArm = Random.Range(0, emptyTerrain.Count); Instantiate(m_armItems[Random.Range(0, m_armItems.Length)], emptyTerrain[leftArm].transform.position + Vector3.up * m_blockSize * 0.5f + Vector3.up * m_itemOffset, Quaternion.identity); emptyTerrain.RemoveAt(leftArm); int rightArm = Random.Range(0, emptyTerrain.Count); Instantiate(m_armItems[Random.Range(0, m_armItems.Length)], emptyTerrain[rightArm].transform.position + Vector3.up * m_blockSize * 0.5f + Vector3.up * m_itemOffset, Quaternion.identity); emptyTerrain.RemoveAt(rightArm); int leftLeg = Random.Range(0, emptyTerrain.Count); Instantiate(m_legItems[Random.Range(0, m_legItems.Length)], emptyTerrain[leftLeg].transform.position + Vector3.up * m_blockSize * 0.5f + Vector3.up * m_itemOffset, Quaternion.identity); emptyTerrain.RemoveAt(leftLeg); int rightLeg = Random.Range(0, emptyTerrain.Count); Instantiate(m_legItems[Random.Range(0, m_legItems.Length)], emptyTerrain[rightLeg].transform.position + Vector3.up * m_blockSize * 0.5f + Vector3.up * m_itemOffset, Quaternion.identity); emptyTerrain.RemoveAt(rightLeg); int startBlock = Random.Range(0, emptyTerrain.Count); Instantiate(m_startArea, emptyTerrain[bodyBlock].transform.position + Vector3.up * m_blockSize * 0.5f, Quaternion.identity); emptyTerrain.RemoveAt(startBlock); }
public override void Sync(Component c) { Terrain terrainObject = c as Terrain; this.name = "cc.Terrain"; TerrainData terrain = terrainObject.terrainData; var terrainLayers = terrain.terrainLayers; var alphaMaps = terrain.GetAlphamaps(0, 0, terrain.alphamapWidth, terrain.alphamapHeight); for (var i = 0; i < terrainLayers.Length; i++) { SyncTerrainLayer layer = new SyncTerrainLayer(); layer.name = terrainLayers[i].name; this.terrainLayers.Add(layer); } // weight datas int weightmapWidth = terrain.alphamapWidth; int weightmapHeight = terrain.alphamapHeight; float[] allWeightDatas = new float[weightmapWidth * weightmapHeight * terrainLayers.Length]; for (var i = 0; i < weightmapWidth; i++) { for (var j = 0; j < weightmapHeight; j++) { for (var k = 0; k < terrainLayers.Length; k++) { var value = alphaMaps[j, i, k]; if (Single.IsNaN(value)) { value = 0; } int index = (i + j * weightmapWidth) * terrainLayers.Length + k; allWeightDatas[index] = value; } } } // height datas int heightmapWidth = terrain.heightmapResolution; int heightmapHeight = terrain.heightmapResolution; var tData = terrain.GetHeights(0, 0, heightmapWidth, heightmapHeight); var height = terrain.size.y; float[] allHeightDatas = new float[heightmapWidth * heightmapHeight]; for (var i = 0; i < heightmapWidth; i++) { for (var j = 0; j < heightmapHeight; j++) { allHeightDatas[i + j * heightmapWidth] = tData[j, i] * height; } } this.weightDatas = allWeightDatas; this.heightmapWidth = heightmapWidth; this.heightmapHeight = heightmapHeight; this.heightDatas = allHeightDatas; this.weightmapWidth = weightmapWidth; this.weightmapHeight = weightmapHeight; this.terrainWidth = terrain.size.x; this.terrainHeight = terrain.size.y; }
public void ExportTerrainData() { totalPath = Application.dataPath + "/TerrainData/"; assetsPath = "Assets/TerrainData/"; data = Terrain.activeTerrain.terrainData; totalPath = totalPath + mapName; assetsPath = assetsPath + mapName; if (!Directory.Exists(totalPath)) { Directory.CreateDirectory(totalPath); } float[,] tempHeights = data.GetHeights(0, 0, data.heightmapWidth, data.heightmapHeight); heightmapWidth = data.heightmapHeight; heightmapHeight = data.heightmapWidth; heights = new float[heightmapWidth, heightmapHeight]; for (int i = 0; i < heightmapHeight; i++) { for (int j = 0; j < heightmapWidth; j++) { heights[i, j] = tempHeights[j, i]; } } normals = new Vector3[data.heightmapWidth, data.heightmapHeight]; maxHeight = data.size.y; SaveHeightNormalMap(); if (isChunk) { chunkCountX = (int)(data.size.x / chunkWidth) + (data.size.x % chunkWidth != 0 ? 1 : 0); chunkCountZ = (int)(data.size.z / chunkLength) + (data.size.z % chunkLength != 0 ? 1 : 0); chunkPixelCountX = (int)(heightmapWidth * chunkWidth / data.size.x) + 1; chunkPixelCountZ = (int)(heightmapHeight * chunkLength / data.size.z) + 1; string chunkPath = totalPath + "/Chunks"; if (!Directory.Exists(chunkPath)) { Directory.CreateDirectory(chunkPath); } if (isSaveGPUMesh) { SaveTerrainMesh(chunkWidth, chunkLength, assetsPath, true); if (isDivideMaterial) { SaveChunkHeightNormalMap(chunkPath); SaveChunkTerrainMaterial(assetsPath + "/Chunks"); SaveChunkPrefab(assetsPath); } //SaveChunkTotalPrefab(assetsPath); } if (isSaveCPUMesh) { SaveChunkHeightMesh(assetsPath + "/Chunks"); } } else { chunkCountX = 1; chunkCountZ = 1; chunkPixelCountX = heightmapWidth; chunkPixelCountZ = heightmapHeight; } if (isSaveCPUMesh) { SaveHeightMesh(); } if (isSaveGPUMesh) { SaveTerrainMesh(data.size.x, data.size.z, assetsPath, false); if (isDivideMaterial) { SaveTotalTerrainMaterial(); SaveTotalPrefab(); } } if (isGPUInstance) { SaveInstancePrefab(); } }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { if (m_TargetTerrain == null || selectedDetail == kInvalidDetail || selectedDetail >= m_TargetTerrain.terrainData.detailPrototypes.Length) { return(false); } Texture2D brush = editContext.brushTexture as Texture2D; if (brush == null) { Debug.LogError("Brush texture is not a Texture2D."); return(false); } if (m_BrushRep == null) { m_BrushRep = new BrushRep(); } PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv); for (int t = 0; t < ctx.terrains.Length; ++t) { Terrain ctxTerrain = ctx.terrains[t]; if (ctxTerrain != null) { int detailPrototype = PaintDetailsUtils.FindDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail); if (detailPrototype == kInvalidDetail) { detailPrototype = PaintDetailsUtils.CopyDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail); } TerrainData terrainData = ctxTerrain.terrainData; TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrainData, "Terrain - Detail Edit"); int size = (int)Mathf.Max(1.0f, editContext.brushSize * ((float)terrainData.detailResolution / terrainData.size.x)); m_BrushRep.CreateFromBrush(brush, size); Vector2 ctxUV = ctx.uvs[t]; int xCenter = Mathf.FloorToInt(ctxUV.x * terrainData.detailWidth); int yCenter = Mathf.FloorToInt(ctxUV.y * terrainData.detailHeight); int intRadius = Mathf.RoundToInt(size) / 2; int intFraction = Mathf.RoundToInt(size) % 2; int xmin = xCenter - intRadius; int ymin = yCenter - intRadius; int xmax = xCenter + intRadius + intFraction; int ymax = yCenter + intRadius + intFraction; if (xmin >= terrainData.detailWidth || ymin >= terrainData.detailHeight || xmax <= 0 || ymax <= 0) { continue; } xmin = Mathf.Clamp(xmin, 0, terrainData.detailWidth - 1); ymin = Mathf.Clamp(ymin, 0, terrainData.detailHeight - 1); xmax = Mathf.Clamp(xmax, 0, terrainData.detailWidth); ymax = Mathf.Clamp(ymax, 0, terrainData.detailHeight); int width = xmax - xmin; int height = ymax - ymin; float targetStrength = detailStrength; if (Event.current.shift || Event.current.control) { targetStrength = -targetStrength; } int[] layers = { detailPrototype }; if (targetStrength < 0.0F && !Event.current.control) { layers = terrainData.GetSupportedLayers(xmin, ymin, width, height); } for (int i = 0; i < layers.Length; i++) { int[,] alphamap = terrainData.GetDetailLayer(xmin, ymin, width, height, layers[i]); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int xBrushOffset = (xmin + x) - (xCenter - intRadius + intFraction); int yBrushOffset = (ymin + y) - (yCenter - intRadius + intFraction); float opa = detailOpacity * m_BrushRep.GetStrengthInt(xBrushOffset, yBrushOffset); float targetValue = Mathf.Lerp(alphamap[y, x], targetStrength, opa); alphamap[y, x] = Mathf.RoundToInt(targetValue - .5f + Random.value); } } terrainData.SetDetailLayer(xmin, ymin, layers[i], alphamap); } } } return(false); }
void ConsumeTerrainTriangles(TerrainData terrain, GameObject gameObject) { Vector3 terrainPos = gameObject.transform.position; //GwNavTag navTag = BuildNavTag(gameObject); int vertexCount_x = terrain.heightmapWidth; int vertexCount_z = terrain.heightmapHeight; float sampleWidthInMeter = terrain.size.x / (terrain.heightmapWidth - 1); float sampleHeightInMeter = terrain.size.z / (terrain.heightmapHeight - 1); for (int z = 0; z < vertexCount_z - 1; ++z) { for (int x = 0; x < vertexCount_x - 1; ++x) { Vector3 A = GetTerrainVertex(terrain, x, z, sampleWidthInMeter, sampleHeightInMeter) + terrainPos; Vector3 B = GetTerrainVertex(terrain, x + 1, z, sampleWidthInMeter, sampleHeightInMeter) + terrainPos; Vector3 C = GetTerrainVertex(terrain, x + 1, z + 1, sampleWidthInMeter, sampleHeightInMeter) + terrainPos; Vector3 D = GetTerrainVertex(terrain, x, z + 1, sampleWidthInMeter, sampleHeightInMeter) + terrainPos; // RecastNavigationDllImports.PushTriangleWithNavTag(A, B, C); // RecastNavigationDllImports.PushTriangleWithNavTag(A, C, D); RecastNavigationDllImports.PushTriangleWithNavTag(C, B, A); RecastNavigationDllImports.PushTriangleWithNavTag(D, C, A); totalTriangleCount += 2; } } float treeRadius = 0.3f; float treeHeight = 5.0f; //navTag.m_isExclusive = true; foreach (TreeInstance tree in terrain.treeInstances) { Vector3 center = Vector3.Scale(terrain.size, tree.position) + terrainPos; Vector3 baseA = new Vector3(center.x - treeRadius, center.y, center.z - treeRadius); Vector3 baseB = new Vector3(center.x + treeRadius, center.y, center.z - treeRadius); Vector3 baseC = new Vector3(center.x + treeRadius, center.y, center.z + treeRadius); Vector3 baseD = new Vector3(center.x - treeRadius, center.y, center.z + treeRadius); Vector3 topA = baseA + Vector3.up * treeHeight; Vector3 topB = baseB + Vector3.up * treeHeight; Vector3 topC = baseC + Vector3.up * treeHeight; Vector3 topD = baseD + Vector3.up * treeHeight; /* * // Push base has non walkable * RecastNavigationDllImports.PushTriangleWithNavTag(baseA, baseB, baseC, navTag); * RecastNavigationDllImports.PushTriangleWithNavTag(baseA, baseC, baseD, navTag); * totalTriangleCount +=2; */ // Push trunk as a vertical square based tube // Front RecastNavigationDllImports.PushTriangleWithNavTag(baseA, baseB, topB); RecastNavigationDllImports.PushTriangleWithNavTag(baseA, topB, topA); // Right RecastNavigationDllImports.PushTriangleWithNavTag(baseB, baseC, topC); RecastNavigationDllImports.PushTriangleWithNavTag(baseB, topC, topB); // Back RecastNavigationDllImports.PushTriangleWithNavTag(baseC, baseD, topD); RecastNavigationDllImports.PushTriangleWithNavTag(baseC, topD, topC); // Left RecastNavigationDllImports.PushTriangleWithNavTag(baseD, baseA, topA); RecastNavigationDllImports.PushTriangleWithNavTag(baseD, topA, topD); totalTriangleCount += 8; } }
/// <summary> /// 创建单块地图 /// </summary> /// <param name="tdData"></param> private void CreateTerrain(TDData tdData) { // 设置TerrainData的基础参数 TerrainData terrainData = new TerrainData(); terrainData.heightmapResolution = head.ResolutionSize + 1; terrainData.SetDetailResolution(head.ResolutionSize, 8); terrainData.alphamapResolution = head.ResolutionSize * 2; terrainData.baseMapResolution = head.ResolutionSize; terrainData.size = head.terrainSize; terrainData.detailPrototypes = details; terrainData.treePrototypes = trees; terrainData.terrainLayers = splats; terrainData.RefreshPrototypes(); // 高度,贴图,细节设置 if (tdData.heightMap != null) { terrainData.SetHeights(0, 0, tdData.heightMap); } if (tdData.detailMap != null) { for (int i = 0; i < tdData.detailMap.Length; i++) { terrainData.SetDetailLayer(0, 0, i, tdData.detailMap[i]); } } if (tdData.alphaMap != null) { terrainData.SetAlphamaps(0, 0, tdData.alphaMap); } // 在场景中创建Terrain实体并设置实体的参数 GameObject newTerrainGameObject = Terrain.CreateTerrainGameObject(terrainData); newTerrainGameObject.name = terrainData.name; newTerrainGameObject.isStatic = false; newTerrainGameObject.transform.position = tdData.terrainPos; newTerrainGameObject.layer = LayerMask.NameToLayer("Terrain"); // 设置Terrain类的参数 Terrain terrain = newTerrainGameObject.GetComponent <Terrain>(); terrain.heightmapPixelError = head.heightmapPixelError; terrain.basemapDistance = head.basemapDistance; terrain.drawHeightmap = head.drawHeightmap; terrain.name = tdData.name; if (tdData.treePoses != null) { // 为地形添加树木实体 for (int index = 0; index < tdData.treePoses.Length; index++) { for (int i = 0; i < tdData.treePoses[index].Length; i++) { TreeInstance instance = TerrainUtility.GetTreeInstance(index); instance.position = tdData.treePoses[index][i]; terrain.AddTreeInstance(instance); } } } newTerrainGameObject.transform.SetParent(terrainParent); }
/// <summary> /// Calculate the new height after flattening /// </summary> /// <param name="currentHeight">Current terrain height</param> /// <param name="terrainData">The used terrain Data</param> /// <returns>The new height</returns> private float NewFlattenHeight(float targetHeight, TerrainData terrainData) { return(Mathf.Clamp(targetHeight, m_MinHeight / terrainData.size.y, m_MaxHeight / terrainData.size.y)); }
IEnumerator loadTerrainTile(TerrainTile tile) { // Create and position GameObject var terrainData = new TerrainData(); terrainData.heightmapResolution = terrainResolution; terrainData.alphamapResolution = tileSize; // Download the tile heightmap tile.url = baseUrl + tile.z + "/" + tile.x + "/" + tile.y + ".png"; WWW www = new WWW(tile.url); while (!www.isDone) { } tile.heightmap = new Texture2D(terrainResolution, terrainResolution); //2049 www.LoadImageIntoTexture(tile.heightmap); // Multidimensional array of this tiles heights in x/y float[,] terrainHeights = terrainData.GetHeights(0, 0, terrainResolution + 1, terrainResolution + 1); // Load colors into byte array Color[] pixelByteArray = tile.heightmap.GetPixels(); if (flatTerrain) { for (int y = 0; y <= tileSize; y++) { for (int x = 0; x <= tileSize; x++) { terrainHeights[y, x] = 0f; } } } else { for (int y = 0; y <= terrainResolution; y++) { for (int x = 0; x <= terrainResolution; x++) { if (x == terrainResolution && y == terrainResolution) { terrainHeights[y, x] = pixelByteArray[(y - 1) * tileSize + (x - 1)].grayscale; } else if (x == terrainResolution) { terrainHeights[y, x] = pixelByteArray[(y) * tileSize + (x - 1)].grayscale; } else if (y == terrainResolution) { terrainHeights[y, x] = pixelByteArray[((y - 1) * tileSize) + x].grayscale; } else { terrainHeights[y, x] = pixelByteArray[y * tileSize + x].grayscale; } } } } // Use the newly populated height data to apply the heightmap terrainData.SetHeights(0, 0, terrainHeights); // Set terrain size terrainData.size = new Vector3(terrainSize, terrainHeight, terrainSize); tile.terrain = Terrain.CreateTerrainGameObject(terrainData); tile.terrain.transform.position = new Vector3(tile.worldX * terrainSize, 0, tile.worldZ * terrainSize); tile.terrain.name = "tile_" + tile.x.ToString() + "_" + tile.y.ToString(); yield return(null); }
public static GameObject Spawn(GreebleDefinition greebleDefinition, Ray ray, float distance, Quaternion rotation, float maxSlope = 0.5f) { if (distance <= 0f) { return(null); } Vector3 vector = ray.origin; RaycastHit raycastHit; if (!Physics.Raycast(ray, out raycastHit, distance, greebleDefinition.SurfaceMask | greebleDefinition.KillMask)) { return(null); } if ((greebleDefinition.KillMask.value & 1 << raycastHit.collider.gameObject.layer) > 0) { return(null); } if (Vector3.Dot(ray.direction, raycastHit.normal) > -maxSlope) { return(null); } bool flag = greebleDefinition.TerrainTextureMask != null && greebleDefinition.TerrainTextureMask.Length > 0; if (flag) { Terrain component = raycastHit.collider.GetComponent <Terrain>(); if (component) { Vector3 position = component.GetPosition(); TerrainData terrainData = component.terrainData; int alphamapResolution = terrainData.alphamapResolution; int num = (int)((raycastHit.point.x - position.x) / terrainData.size.x * (float)alphamapResolution); int num2 = (int)((raycastHit.point.z - position.z) / terrainData.size.z * (float)alphamapResolution); bool flag2 = false; if (num >= 0 && num2 >= 0 && num < alphamapResolution && num2 < alphamapResolution) { float[,,] alphamaps = component.terrainData.GetAlphamaps(num, num2, 1, 1); float num3 = 0f; int num4 = -1; for (int i = terrainData.alphamapLayers - 1; i >= 0; i--) { if (alphamaps[0, 0, i] > num3) { num3 = alphamaps[0, 0, i]; num4 = i; } } if (num4 >= 0) { for (int j = 0; j < greebleDefinition.TerrainTextureMask.Length; j++) { if (greebleDefinition.TerrainTextureMask[j] == num4) { flag2 = true; break; } } } } if (!flag2) { return(null); } } } vector = raycastHit.point; if (greebleDefinition.MatchSurfaceNormal) { Vector3 lhs = Vector3.Cross(Vector3.forward, raycastHit.normal); Vector3 forward = Vector3.Cross(lhs, raycastHit.normal); Quaternion quaternion = Quaternion.LookRotation(forward, raycastHit.normal); if (greebleDefinition.RandomizeRotation) { rotation = quaternion * rotation; } else { rotation = quaternion; } } vector += rotation * greebleDefinition.Prefab.transform.position; rotation *= greebleDefinition.Prefab.transform.rotation; GameObject result; if (Application.isPlaying) { result = GreeblePlugin.Instantiate(greebleDefinition.Prefab, vector, rotation); } else { result = (GameObject)UnityEngine.Object.Instantiate(greebleDefinition.Prefab, vector, rotation); } return(result); }
void Create() { // check lighting auto bake if (m_Settings.EnableLightingAutoBake) { UnityEditor.Lightmapping.giWorkflowMode = UnityEditor.Lightmapping.GIWorkflowMode.Iterative; } else { UnityEditor.Lightmapping.giWorkflowMode = UnityEditor.Lightmapping.GIWorkflowMode.OnDemand; } if (m_Settings.EnableClearExistingData) { ClearExistingTerrainGroup(m_Settings.GroupID); } // create tiles int tileCount = m_Settings.TilesX * m_Settings.TilesZ; Vector2Int tileOffset = Vector2Int.zero; Vector2Int tileOffsetSource = Vector2Int.zero; Vector2Int tileResolution = new Vector2Int(m_Settings.TerrainWidth / m_Settings.TilesX, m_Settings.TerrainLength / m_Settings.TilesZ); Vector3 tileSize = new Vector3(tileResolution.x, m_Settings.TerrainHeight, tileResolution.y); Vector3 tilePosition = m_Settings.StartPosition; Terrain[] terrains = new Terrain[tileCount]; string assetFolderPath = GetAssetPathFromFullPath(m_Settings.TerrainAssetDirectory); int tileIndex = 0; try { // create terrain grouping object string groupName = "TerrainGroup_" + m_Settings.GroupID; GameObject terrainGroup = new GameObject(groupName); TerrainGroup groupComp = terrainGroup.AddComponent<TerrainGroup>(); terrainGroup.transform.position = m_Settings.StartPosition; Heightmap globalHeightmap = null; Vector2Int numHeightsPerTile = Vector2Int.zero; Undo.RegisterCreatedObjectUndo(terrainGroup, "Create terrain"); if (m_Settings.UseGlobalHeightmap) { byte[] rawData = File.ReadAllBytes(m_Settings.GlobalHeightmapPath); globalHeightmap = new Heightmap(rawData, m_Settings.FlipMode); tileOffsetSource = new Vector2Int(globalHeightmap.Width / m_Settings.TilesX, globalHeightmap.Height / m_Settings.TilesZ); } else { tileOffsetSource = tileResolution; } for (int x = 0; x < m_Settings.TilesX; x++, tileOffset.x += tileOffsetSource.x, tilePosition.x += tileResolution.x) { tileOffset.y = 0; tilePosition.z = m_Settings.StartPosition.z; for (int y = 0; y < m_Settings.TilesZ; y++, tileOffset.y += tileOffsetSource.y, tilePosition.z += tileResolution.y) { EditorUtility.DisplayProgressBar("Creating terrains", string.Format("Updating terrain tile ({0}, {1})", x, y), ((float)tileIndex / tileCount)); TerrainData terrainData = new TerrainData(); terrainData.alphamapResolution = m_Settings.ControlTextureResolution; terrainData.baseMapResolution = m_Settings.BaseTextureResolution; terrainData.SetDetailResolution(m_Settings.DetailResolution, m_Settings.DetailResolutionPerPatch); GameObject newGO = Terrain.CreateTerrainGameObject(terrainData); Terrain newTerrain = newGO.GetComponent<Terrain>(); newTerrain.groupingID = m_Settings.GroupID; newTerrain.allowAutoConnect = m_Settings.AutoConnect; newTerrain.drawInstanced = m_Settings.DrawInstanced; newTerrain.heightmapPixelError = m_Settings.PixelError; newTerrain.basemapDistance = m_Settings.BaseMapDistance; if (m_Settings.MaterialOverride != null) { newTerrain.materialTemplate = m_Settings.MaterialOverride; #if UNITY_2019_2_OR_NEWER #else newTerrain.materialType = Terrain.MaterialType.Custom; #endif } string terrainName = $"Terrain_{x}_{y}"; ; if (m_Settings.EnableGuid) { Guid newGuid = Guid.NewGuid(); terrainName = $"Terrain_{x}_{y}_{newGuid}"; } newGO.name = terrainName; newTerrain.transform.position = tilePosition; newTerrain.transform.SetParent(terrainGroup.transform); // import height if (m_Settings.HeightmapMode == Heightmap.Mode.Global && globalHeightmap != null) { Heightmap tileHeightmap = GetTileHeightmapFromGlobalHeightmap(globalHeightmap, tileOffset); tileHeightmap.ApplyTo(newTerrain); } if (m_Settings.HeightmapMode == Heightmap.Mode.Tiles || m_Settings.HeightmapMode == Heightmap.Mode.Batch) { if (File.Exists(m_Settings.TileHeightmapPaths[tileIndex])) { var remap = (m_Settings.HeightmapRemapMax - m_Settings.HeightmapRemapMin) / m_Settings.TerrainHeight; var baseLevel = m_Settings.HeightmapRemapMin / m_Settings.TerrainHeight; byte[] rawTileData = File.ReadAllBytes(m_Settings.TileHeightmapPaths[tileIndex]); Heightmap tileHeight = new Heightmap(rawTileData, m_Settings.FlipMode); Heightmap tileMap = new Heightmap(tileHeight, Vector2Int.zero, new Vector2Int(tileHeight.Width, tileHeight.Height), remap, baseLevel); tileMap.ApplyTo(newTerrain); } } terrains[tileIndex] = newTerrain; tileIndex++; // save terrain data asset terrainData.size = tileSize; // set terrain size after heightmap process string assetPath = $"{assetFolderPath}/{terrainName}.asset"; if (!Directory.Exists(assetFolderPath)) { Directory.CreateDirectory(assetFolderPath); } AssetDatabase.CreateAsset(terrainData, assetPath); // finally, resize height resolution if needed if (terrainData.heightmapResolution != (m_Settings.HeightmapResolution + 1)) { ToolboxHelper.ResizeHeightmap(terrainData, (m_Settings.HeightmapResolution + 1)); } Undo.RegisterCreatedObjectUndo(newGO, "Create terrain"); } } m_Terrains = terrains; m_CurrentGroup = terrainGroup; UpdateGroupSettings(groupComp); ToolboxHelper.CalculateAdjacencies(m_Terrains, m_Settings.TilesX, m_Settings.TilesZ); } finally { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); } }
void Export() { string fileName = EditorUtility.SaveFilePanel("Export .obj file", "", "Terrain", "obj"); int w = terrain.heightmapWidth; int h = terrain.heightmapHeight; Vector3 meshScale = terrain.size; int tRes = (int)Mathf.Pow(2, (int)saveResolution); meshScale = new Vector3(meshScale.x / (w - 1) * tRes, meshScale.y, meshScale.z / (h - 1) * tRes); Vector2 uvScale = new Vector2(1.0f / (w - 1), 1.0f / (h - 1)); float[,] tData = terrain.GetHeights(0, 0, w, h); w = (w - 1) / tRes + 1; h = (h - 1) / tRes + 1; Vector3[] tVertices = new Vector3[w * h]; Vector2[] tUV = new Vector2[w * h]; int[] tPolys; if (saveFormat == SaveFormat.Triangles) { tPolys = new int[(w - 1) * (h - 1) * 6]; } else { tPolys = new int[(w - 1) * (h - 1) * 4]; } // Build vertices and UVs for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(-y, tData[x * tRes, y * tRes], x)) + terrainPos; tUV[y * w + x] = Vector2.Scale(new Vector2(x * tRes, y * tRes), uvScale); } } int index = 0; if (saveFormat == SaveFormat.Triangles) { // Build triangle indices: 3 indices into vertex array for each triangle for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { // For each grid cell output two triangles tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = (y * w) + x + 1; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; } } } else { // Build quad indices: 4 indices into vertex array for each quad for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { // For each grid cell output one quad tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; } } } // Export to .obj StreamWriter sw = new StreamWriter(fileName); try { sw.WriteLine("# Unity terrain OBJ File"); // Write vertices System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); counter = tCount = 0; totalCount = (tVertices.Length * 2 + (saveFormat == SaveFormat.Triangles ? tPolys.Length / 3 : tPolys.Length / 4)) / progressUpdateInterval; for (int i = 0; i < tVertices.Length; i++) { UpdateProgress(); StringBuilder sb = new StringBuilder("v ", 20); // 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. sb.Append(tVertices[i].x.ToString()).Append(" "). Append(tVertices[i].y.ToString()).Append(" "). Append(tVertices[i].z.ToString()); sw.WriteLine(sb); } // Write UVs for (int i = 0; i < tUV.Length; i++) { UpdateProgress(); StringBuilder sb = new StringBuilder("vt ", 22); sb.Append(tUV[i].x.ToString()).Append(" "). Append(tUV[i].y.ToString()); sw.WriteLine(sb); } if (saveFormat == SaveFormat.Triangles) { // Write triangles for (int i = 0; i < tPolys.Length; i += 3) { UpdateProgress(); StringBuilder sb = new StringBuilder("f ", 43); sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" "). Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" "). Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1); sw.WriteLine(sb); } } else { // Write quads for (int i = 0; i < tPolys.Length; i += 4) { UpdateProgress(); StringBuilder sb = new StringBuilder("f ", 57); sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" "). Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" "). Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1).Append(" "). Append(tPolys[i + 3] + 1).Append("/").Append(tPolys[i + 3] + 1); sw.WriteLine(sb); } } } catch (Exception err) { Debug.Log("Error saving file: " + err.Message); } sw.Close(); terrain = null; EditorUtility.DisplayProgressBar("Saving file to disc.", "This might take a while...", 1f); EditorWindow.GetWindow <ExportTerrain>().Close(); EditorUtility.ClearProgressBar(); }
public override void OnInspectorGUI() { if (tg == null) { return; } if (tg.splatSettings == null || tg.splatSettings.Length == 0) { tg.Initialize(); } serializedObject.Update(); if (titleLabelStyle == null) { titleLabelStyle = new GUIStyle(EditorStyles.label); } titleLabelStyle.normal.textColor = titleColor; titleLabelStyle.fontStyle = FontStyle.Bold; if (boxStyle == null) { boxStyle = new GUIStyle(GUI.skin.box); } if (sectionHeaderStyle == null) { sectionHeaderStyle = new GUIStyle(EditorStyles.foldout); } sectionHeaderStyle.SetFoldoutColor(); EditorGUILayout.BeginHorizontal(); TerrainData prevTD = (TerrainData)terrainData.objectReferenceValue; EditorGUILayout.PropertyField(terrainData); TerrainData td = (TerrainData)terrainData.objectReferenceValue; if (td != prevTD) { tg.ExamineTerrainData(); } if (GUILayout.Button("Refresh", GUILayout.Width(60))) { tg.ExamineTerrainData(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.PropertyField(seaLevel); EditorGUILayout.PropertyField(waterVoxel); bool needCreate = false; bool needAssign = false; bool allIgnored = true; if (tg.terrainData != null) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Thumbnail Size", GUILayout.Width(EditorGUIUtility.labelWidth)); thumbnailSize = EditorGUILayout.IntSlider(thumbnailSize, 16, 256); EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); expandTerrainTextures = EditorGUILayout.Foldout(expandTerrainTextures, new GUIContent("Terrain Textures"), true, sectionHeaderStyle); if (expandTerrainTextures) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Size", GUILayout.Width(EditorGUIUtility.labelWidth)); terrainTextureSize = EditorGUILayout.IntField(terrainTextureSize); EditorGUILayout.EndHorizontal(); #if UNITY_2018_3_OR_NEWER for (int k = 0; k < tg.terrainData.terrainLayers.Length; k++) { #else for (int k = 0; k < tg.terrainData.splatPrototypes.Length; k++) { #endif EditorGUILayout.LabelField("Texture " + (k + 1), GUILayout.Width(80)); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent(tg.splatSettings [k].preview), boxStyle, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Voxel Top", GUILayout.Width(80)); tg.splatSettings [k].top = (VoxelDefinition)EditorGUILayout.ObjectField(tg.splatSettings [k].top, typeof(VoxelDefinition), false); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Smooth", GUILayout.Width(80)); tg.splatSettings [k].smoothPower = EditorGUILayout.Slider(tg.splatSettings [k].smoothPower, 0, 1f); EditorGUILayout.EndHorizontal(); #if UNITY_2018_3_OR_NEWER int textureCount = tg.terrainData.terrainLayers.Length; #else int textureCount = tg.terrainData.splatPrototypes.Length; #endif if (textureIndices == null || textureIndices.Length != textureCount) { textureIndices = new string[textureCount]; textureIndicesValues = new int[textureCount]; for (int t = 0; t < textureCount; t++) { textureIndices [t] = "Texture " + (t + 1); textureIndicesValues [t] = (t + 1); } } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Dirt With", GUILayout.Width(80)); tg.splatSettings [k].dirtWith = EditorGUILayout.IntPopup(tg.splatSettings [k].dirtWith, textureIndices, textureIndicesValues); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Blend Power", GUILayout.Width(80)); tg.splatSettings [k].blendPower = EditorGUILayout.Slider(tg.splatSettings [k].blendPower, 0, 1f); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Voxel Dirt", GUILayout.Width(80)); tg.splatSettings [k].dirt = (VoxelDefinition)EditorGUILayout.ObjectField(tg.splatSettings [k].dirt, typeof(VoxelDefinition), false); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Action", GUILayout.Width(80)); tg.splatSettings [k].action = (UnityTerrainGenerator.TerrainResourceAction)EditorGUILayout.EnumPopup(tg.splatSettings [k].action); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); if (tg.splatSettings [k].action != UnityTerrainGenerator.TerrainResourceAction.Ignore) { allIgnored = false; } if (tg.splatSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Create) { needCreate = true; } else if ((tg.splatSettings [k].top == null || tg.splatSettings [k].dirt == null) && tg.splatSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Assigned) { needAssign = true; } EditorGUILayout.Separator(); } } EditorGUILayout.Separator(); expandTrees = EditorGUILayout.Foldout(expandTrees, new GUIContent("Trees"), true, sectionHeaderStyle); if (expandTrees) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Size", GUILayout.Width(EditorGUIUtility.labelWidth)); treeTextureSize = EditorGUILayout.IntField(treeTextureSize); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Frond Density", GUILayout.Width(EditorGUIUtility.labelWidth)); frondDensity = EditorGUILayout.Slider(frondDensity, 0f, 1f); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Tree Scale", GUILayout.Width(EditorGUIUtility.labelWidth)); treeScale = EditorGUILayout.Slider(treeScale, 0.1f, 2f); EditorGUILayout.EndHorizontal(); for (int k = 0; k < tg.terrainData.treePrototypes.Length; k++) { EditorGUILayout.LabelField("Tree " + (k + 1), GUILayout.Width(80)); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent(tg.treeSettings [k].preview), boxStyle, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Model Def.", GUILayout.Width(80)); tg.treeSettings [k].md = (ModelDefinition)EditorGUILayout.ObjectField(tg.treeSettings [k].md, typeof(ModelDefinition), false); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Smooth", GUILayout.Width(80)); tg.treeSettings [k].smoothPower = EditorGUILayout.Slider(tg.treeSettings [k].smoothPower, 0, 1f); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Action", GUILayout.Width(80)); tg.treeSettings [k].action = (UnityTerrainGenerator.TerrainResourceAction)EditorGUILayout.EnumPopup(tg.treeSettings [k].action); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); if (tg.treeSettings [k].action != UnityTerrainGenerator.TerrainResourceAction.Ignore) { allIgnored = false; } if (tg.treeSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Create) { needCreate = true; } else if (tg.treeSettings[k].md == null && tg.treeSettings[k].action == UnityTerrainGenerator.TerrainResourceAction.Assigned) { needAssign = true; } EditorGUILayout.Separator(); } } EditorGUILayout.Separator(); expandVegetation = EditorGUILayout.Foldout(expandVegetation, new GUIContent("Vegetation"), true, sectionHeaderStyle); if (expandVegetation) { EditorGUILayout.PropertyField(vegetationDensity); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Size", GUILayout.Width(EditorGUIUtility.labelWidth)); vegetationTextureSize = EditorGUILayout.IntField(vegetationTextureSize); EditorGUILayout.EndHorizontal(); for (int k = 0; k < tg.terrainData.detailPrototypes.Length; k++) { EditorGUILayout.LabelField("Detail " + (k + 1), GUILayout.Width(EditorGUIUtility.labelWidth)); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent(tg.detailSettings [k].preview), boxStyle, GUILayout.Width(thumbnailSize), GUILayout.Height(thumbnailSize)); EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Voxel Def.", GUILayout.Width(80)); tg.detailSettings [k].vd = (VoxelDefinition)EditorGUILayout.ObjectField(tg.detailSettings [k].vd, typeof(VoxelDefinition), false); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Action", GUILayout.Width(80)); tg.detailSettings [k].action = (UnityTerrainGenerator.TerrainResourceAction)EditorGUILayout.EnumPopup(tg.detailSettings [k].action); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); if (tg.detailSettings [k].action != UnityTerrainGenerator.TerrainResourceAction.Ignore) { allIgnored = false; } if (tg.detailSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Create) { needCreate = true; } else if (tg.detailSettings [k].vd == null && tg.detailSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Assigned) { needAssign = true; } EditorGUILayout.Separator(); } } } EditorGUILayout.Separator(); if (!allIgnored) { if (needAssign) { EditorGUILayout.HelpBox("Please check all 'Assigned' resources are correctly set in the list above or press 'Refresh' to reload TerrainData info.", MessageType.Warning); } else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Clean Folders", GUILayout.Width(EditorGUIUtility.labelWidth)); cleanFolders = EditorGUILayout.Toggle(cleanFolders); EditorGUILayout.EndHorizontal(); if (needCreate) { EditorGUILayout.HelpBox("Press 'Generate' to create voxel definitions for the terrain resources.", MessageType.Info); if (GUILayout.Button("Generate")) { Generate(cleanFolders); } } else { if (GUILayout.Button("Generate Again")) { Generate(true); } } } } EditorGUILayout.Separator(); serializedObject.ApplyModifiedProperties(); } void Generate(bool forceGeneration = false) { GenerateTerrainVoxels(forceGeneration); GenerateTreeModels(forceGeneration); GenerateVegetationVoxels(forceGeneration); EditorUtility.SetDirty(tg); AssetDatabase.SaveAssets(); } string GetPath() { WorldDefinition wd = VoxelPlayEnvironment.instance.world; return(System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(wd)) + "/Resources/" + wd.name); } Texture2D CreateTextureFile(Texture2D tex, string path, string filename, float smoothPower) { if (smoothPower > 0) { TextureTools.Smooth(tex, smoothPower); } byte[] texBytes = tex.EncodeToPNG(); string fullPath = path + "/" + filename + ".png"; System.IO.File.WriteAllBytes(fullPath, texBytes); AssetDatabase.ImportAsset(fullPath); TextureImporter importerSettings = AssetImporter.GetAtPath(fullPath) as TextureImporter; if (importerSettings != null) { importerSettings.isReadable = true; importerSettings.filterMode = FilterMode.Point; importerSettings.mipmapEnabled = false; importerSettings.SaveAndReimport(); } tex = AssetDatabase.LoadAssetAtPath <Texture2D> (fullPath); return(tex); } VoxelDefinition GenerateVoxelFromTexture(Texture2D textureTop, Texture2D textureSide, Texture2D textureDirt, int textureSize, string path, string voxelDefinitionName, RenderType renderType, float smoothPower) { // Prepare top texture Texture2D texTop = null; if (textureTop != null) { texTop = Instantiate <Texture2D> (textureTop); texTop.name = textureTop.name; if (texTop.width != textureSize || texTop.height != textureSize) { TextureTools.Scale(texTop, textureSize, textureSize, FilterMode.Bilinear); } string texName = Sanitize(texTop.name); texTop = CreateTextureFile(texTop, path, texName, smoothPower); } // Side texture Texture2D texSide = null; if (textureSide != null) { if (textureSide == textureTop) { texSide = texTop; } else { texSide = Instantiate <Texture2D> (textureSide); texSide.name = textureSide.name; if (texSide.width != textureSize || texSide.height != textureSize) { TextureTools.Scale(texSide, textureSize, textureSize, FilterMode.Bilinear); } // Save texture string texSideName = Sanitize(texSide.name); texSide = CreateTextureFile(texSide, path, texSideName, smoothPower); } } // Dirt texture Texture2D texDirt = null; if (textureDirt != null) { if (textureDirt == textureTop) { texDirt = texTop; } else { texDirt = Instantiate <Texture2D> (textureDirt); texDirt.name = textureDirt.name; if (texDirt.width != textureSize || texDirt.height != textureSize) { TextureTools.Scale(texDirt, textureSize, textureSize, FilterMode.Bilinear); } // Save texture string texDirtName = Sanitize(texDirt.name); texDirt = CreateTextureFile(texDirt, path, texDirtName, smoothPower); } } // Setup and save voxel definition VoxelDefinition vd = ScriptableObject.CreateInstance <VoxelDefinition> (); vd.renderType = renderType; vd.textureTop = texTop; vd.textureSide = texSide; vd.textureBottom = texDirt; switch (renderType) { case RenderType.CutoutCross: vd.navigatable = false; vd.windAnimation = true; break; case RenderType.Cutout: vd.navigatable = false; vd.windAnimation = true; break; default: vd.navigatable = true; vd.windAnimation = false; break; } vd.name = Sanitize(voxelDefinitionName); string fullPath = path + "/" + vd.name + ".asset"; AssetDatabase.CreateAsset(vd, fullPath); return(vd); } void GenerateTerrainVoxels(bool forceGeneration) { string path = GetPath() + "/TerrainVoxels"; CheckDirectory(path); #if UNITY_2018_3_OR_NEWER for (int k = 0; k < tg.terrainData.terrainLayers.Length; k++) { #else for (int k = 0; k < tg.terrainData.splatPrototypes.Length; k++) { #endif if (forceGeneration || tg.splatSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Create) { if (tg.splatSettings [k].preview == null) { continue; } int dirtWith = tg.splatSettings [k].dirtWith - 1; string texBaseName = tg.splatSettings [k].preview.name; Texture2D texTop = Instantiate(tg.splatSettings [k].preview) as Texture2D; texTop.name = texBaseName + " Top"; Texture2D texOther = Instantiate(tg.splatSettings [dirtWith].preview) as Texture2D; Texture2D texDirt = CreateDirtTexture(texTop, texOther, tg.splatSettings [dirtWith].blendPower, 0); texDirt.name = texBaseName + " Dirt"; Texture2D texSide = CreateSideTexture(texTop, texDirt); texSide.name = texBaseName + " Side"; tg.splatSettings [k].top = GenerateVoxelFromTexture(texTop, texSide, texDirt, terrainTextureSize, path, "VoxelTerrainTop " + texBaseName, RenderType.Opaque, tg.splatSettings[k].smoothPower); tg.splatSettings [k].dirt = GenerateVoxelFromTexture(texDirt, texDirt, texDirt, terrainTextureSize, path, "VoxelTerrainDirt " + texBaseName, RenderType.Opaque, tg.splatSettings[k].smoothPower); tg.splatSettings [k].action = UnityTerrainGenerator.TerrainResourceAction.Assigned; } } } Texture2D CreateDirtTexture(Texture2D texTop, Texture2D texOther, float smoothPower, float blendAmount) { if (texTop.width != terrainTextureSize || texTop.height != terrainTextureSize) { TextureTools.Scale(texTop, terrainTextureSize, terrainTextureSize); } if (texOther.width != terrainTextureSize || texOther.height != terrainTextureSize) { TextureTools.Scale(texOther, terrainTextureSize, terrainTextureSize); } Color32[] colorsTop = texTop.GetPixels32(); Color32[] colorsOther = texOther.GetPixels32(); for (int k = 0; k < colorsTop.Length; k++) { colorsTop [k].r = (byte)Mathf.Lerp(colorsTop [k].r, colorsOther [k].r, blendAmount); colorsTop [k].g = (byte)Mathf.Lerp(colorsTop [k].g, colorsOther [k].g, blendAmount); colorsTop [k].b = (byte)Mathf.Lerp(colorsTop [k].b, colorsOther [k].b, blendAmount); colorsTop [k].a = (byte)Mathf.Lerp(colorsTop [k].a, colorsOther [k].a, blendAmount); } Texture2D tex = new Texture2D(texTop.width, texTop.height, TextureFormat.ARGB32, false); tex.SetPixels32(colorsTop); tex.Apply(true); return(tex); } Texture2D CreateSideTexture(Texture2D texTop, Texture2D texDirt) { // Make side texture Color32[] colors = texTop.GetPixels32(); Color32[] colorsDirt = texDirt.GetPixels32(); int h = texTop.height; int w = texTop.width; int y0 = (int)(h * 0.6f); int i = y0 * w; for (int y = y0; y < h; y++) { float threshold = Mathf.Clamp01(2f * ((float)(y - y0)) / (h - y0)); for (int x = 0; x < w; x++, i++) { if (UnityEngine.Random.value < threshold) { colorsDirt [i].r = (byte)Mathf.Lerp(colorsDirt [i].r, colors [i].r, threshold); colorsDirt [i].g = (byte)Mathf.Lerp(colorsDirt [i].g, colors [i].g, threshold); colorsDirt [i].b = (byte)Mathf.Lerp(colorsDirt [i].b, colors [i].b, threshold); colorsDirt [i].a = (byte)Mathf.Lerp(colorsDirt [i].a, colors [i].a, threshold); } } } Texture2D sideTexture = new Texture2D(w, h, TextureFormat.ARGB32, false); sideTexture.SetPixels32(colorsDirt); sideTexture.Apply(true); return(sideTexture); } void GenerateVegetationVoxels(bool forceGeneration) { string path = GetPath() + "/Vegetation"; CheckDirectory(path); for (int k = 0; k < tg.terrainData.detailPrototypes.Length; k++) { if (forceGeneration || tg.detailSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Create) { if (tg.detailSettings [k].preview == null) { continue; } TextureTools.EnsureTextureReadable(tg.detailSettings [k].preview); tg.detailSettings [k].vd = GenerateVoxelFromTexture(null, tg.detailSettings [k].preview, null, vegetationTextureSize, path, "VoxelVegetation " + tg.detailSettings [k].preview.name, RenderType.CutoutCross, 0); tg.detailSettings [k].action = UnityTerrainGenerator.TerrainResourceAction.Assigned; } } } void GenerateTreeModels(bool forceGeneration) { string path = GetPath() + "/Trees"; CheckDirectory(path); List <ModelBit> bits = new List <ModelBit> (); for (int k = 0; k < tg.terrainData.treePrototypes.Length; k++) { if (forceGeneration || tg.treeSettings [k].action == UnityTerrainGenerator.TerrainResourceAction.Create) { // Get tree size GameObject o = tg.terrainData.treePrototypes [k].prefab; // Look for LOD0 MeshRenderer[] rr = o.GetComponentsInChildren <MeshRenderer> (); if (rr.Length == 0) { continue; } MeshRenderer r = rr [0]; for (int b = 0; b < rr.Length; b++) { if (rr [b].name.Contains("LOD0")) { r = rr [b]; break; } } // Get bounds of renderer Bounds bounds = r.bounds; int sizeX = (int)(bounds.size.x * treeScale); int sizeY = (int)(bounds.size.y * treeScale); int sizeZ = (int)(bounds.size.z * treeScale); if (sizeX == 0 || sizeY == 0 || sizeZ == 0) { continue; } // Build model definition ModelDefinition md = ScriptableObject.CreateInstance <ModelDefinition> (); md.sizeX = sizeX; md.sizeY = sizeY; md.sizeZ = sizeZ; bits.Clear(); MeshFilter mf = r.GetComponent <MeshFilter> (); Mesh mesh = mf.sharedMesh; Vector3[] vertices = mesh.vertices; Vector2[] uvs = mesh.uv; for (int m = 0; m < mesh.subMeshCount; m++) { int[] triangles = mesh.GetTriangles(m); for (int i = 0; i < triangles.Length; i += 3) { int i1 = triangles [i]; int i2 = triangles [i + 1]; int i3 = triangles [i + 2]; Vector3 v1 = vertices [i1]; Vector3 v2 = vertices [i2]; Vector3 v3 = vertices [i3]; Vector2 uv1 = uvs [i1]; Vector2 uv2 = uvs [i2]; Vector2 uv3 = uvs [i3]; AddModelBit(bits, md, (v1 + v2 + v3) * treeScale / 3f, (uv1 + uv2 + uv3) / 3f, r.sharedMaterials [m], path, tg.treeSettings [k].smoothPower); } } md.bits = bits.ToArray(); string treeName = Sanitize(tg.terrainData.treePrototypes [k].prefab.name); md.name = "Tree " + treeName; string fullPath = path + "/" + md.name + ".asset"; AssetDatabase.CreateAsset(md, fullPath); tg.treeSettings [k].md = md; tg.treeSettings [k].action = UnityTerrainGenerator.TerrainResourceAction.Assigned; } } } void AddModelBit(List <ModelBit> bits, ModelDefinition md, Vector3 pos, Vector2 uv, Material mat, string path, float smoothPower) { Texture2D tex = (Texture2D)mat.mainTexture; if (tex == null) { return; } int y = Mathf.Clamp(Mathf.FloorToInt(pos.y), 0, md.sizeY - 1); int z = Mathf.Clamp(Mathf.FloorToInt(pos.z) + md.sizeZ / 2, 0, md.sizeZ - 1); int x = Mathf.Clamp(Mathf.FloorToInt(pos.x) + md.sizeX / 2, 0, md.sizeX - 1); int voxelIndex = y * md.sizeZ * md.sizeX + z * md.sizeX + x; int bitCount = bits.Count; if (bitCount > 0) { for (int k = bitCount - 1; k >= 0; k--) { if (bits [k].voxelIndex == voxelIndex) { return; } } } TextureTools.EnsureTextureReadable(tex); ModelBit bit = new ModelBit(); bit.voxelIndex = voxelIndex; VoxelDefinition vd; if (textureVoxels == null) { textureVoxels = new Dictionary <Texture2D, VoxelDefinition> (); } if (!textureVoxels.TryGetValue(tex, out vd)) { RenderType rt = RenderType.Cutout; string matName = mat.name.ToUpper(); string texName = tex.name.ToUpper(); if (matName.Contains("BRANCH") || matName.Contains("BARK") || texName.Contains("BARK")) { rt = RenderType.Opaque; vd = GenerateVoxelFromTexture(tex, tex, tex, treeTextureSize, path, "VoxelTree " + tex.name, rt, smoothPower); } else { Texture2D frondTex = GenerateFrondTexture(tex, uv, treeTextureSize, path); vd = GenerateVoxelFromTexture(frondTex, frondTex, frondTex, treeTextureSize, path, "VoxelTree " + frondTex.name, rt, smoothPower); } textureVoxels [tex] = vd; } bit.voxelDefinition = vd; bits.Add(bit); } Texture2D GenerateFrondTexture(Texture2D tex, Vector2 uv, int textureSize, string path) { Color32[] sourceColors = tex.GetPixels32(); // Extract representative colors around uv position int w = textureSize; int h = textureSize; int x = Mathf.Clamp((int)(w * uv.x), 0, w - 1); int y = Mathf.Clamp((int)(h * uv.y), 0, h - 1); List <Color32> repColors = new List <Color32> (); int gap = textureSize / 2; for (int y0 = y - gap; y0 < y + gap; y0++) { int ty = Mathf.Clamp(y0, 0, h - 1); for (int x0 = x - gap; x0 < x + gap; x0++) { int tx = Mathf.Clamp(x0, 0, w - 1); repColors.Add(sourceColors [ty * w + tx]); } } Color32[] colors = repColors.ToArray(); Color32[] newColors = new Color32[w * h]; int i = 0; for (int k = 0; k < newColors.Length; k++) { if (UnityEngine.Random.value > frondDensity) { continue; } for (int c = 0; c < colors.Length; c++) { if (colors [i].a > 128) { break; } i++; if (i >= colors.Length) { i = 0; } } newColors [k] = colors [i]; newColors [k].a = 255; i++; if (i >= colors.Length) { i = 0; } } Texture2D subTex = new Texture2D(w, h, TextureFormat.ARGB32, false); subTex.filterMode = FilterMode.Point; subTex.name = tex.name + " Frond"; subTex.SetPixels32(newColors); subTex.Apply(true); return(subTex); } void CheckDirectory(string path) { if (cleanFolders) { if (Directory.Exists(path)) { System.IO.DirectoryInfo di = new DirectoryInfo(path); foreach (FileInfo file in di.GetFiles()) { file.Delete(); } foreach (DirectoryInfo dir in di.GetDirectories()) { dir.Delete(true); } } AssetDatabase.Refresh(); } System.IO.Directory.CreateDirectory(path); } string Sanitize(string s) { if (string.IsNullOrEmpty(s)) { return(""); } int k = s.IndexOf("(Clone)"); if (k >= 0) { s = s.Substring(0, k); } char[] invalidChars = System.IO.Path.GetInvalidFileNameChars(); for (int i = 0; i < invalidChars.Length; i++) { if (s.IndexOf(invalidChars [i]) >= 0) { s = s.Replace(invalidChars [i], '_'); } } return(s); } } }
static XmlElement streamWorld(XmlDocument xmlDoc, XmlElement root) { XmlElement WorldNode = xmlDoc.CreateElement("gameObject"); WorldNode.SetAttribute("name", "world"); root.AppendChild(WorldNode); WorldNode.SetAttribute("wname", System.IO.Path.GetFileNameWithoutExtension(EditorApplication.currentScene)); root = WorldNode; GameObject obj = GameObject.Find("Terrain"); if (obj == null) { return(null); } XmlElement TerrainNode = xmlDoc.CreateElement("gameObject"); TerrainNode.SetAttribute("name", "Terrain"); root.AppendChild(TerrainNode); root = TerrainNode; TerrainData terrainData = obj.GetComponent <TerrainCollider>().terrainData; Debug.Log("StreamWorld:" + terrainData.name); HashSet <string> refPrefabs = new HashSet <string>(); XmlElement tmpNode = xmlDoc.CreateElement("size"); XmlElement prefabsNode = xmlDoc.CreateElement("prefabs"); root.AppendChild(prefabsNode); tmpNode.InnerText = (terrainData.size.x + " " + terrainData.size.y + " " + terrainData.size.z); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("name"); tmpNode.InnerText = terrainData.name; root.AppendChild(tmpNode); int splitsize = 0; foreach (Transform child in obj.transform) { string name = child.gameObject.name; if (name == "2") { splitsize = 2; } else if (name == "4") { splitsize = 4; } else if (name == "8") { splitsize = 8; } else if (name == "16") { splitsize = 16; } else if (name == "64") { splitsize = 64; } } ; if (splitsize == 0) { Debug.LogError("splitsize: is 0"); splitsize = 8; } tmpNode = xmlDoc.CreateElement("splitSize"); tmpNode.InnerText = (splitsize + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("alphamapWH"); tmpNode.SetAttribute("w", terrainData.alphamapWidth + ""); tmpNode.SetAttribute("h", terrainData.alphamapHeight + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("baseMapResolution"); tmpNode.InnerText = (terrainData.baseMapResolution + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("detailResolution"); tmpNode.InnerText = (terrainData.detailResolution + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("detailWH"); tmpNode.SetAttribute("w", terrainData.detailWidth + ""); tmpNode.SetAttribute("h", terrainData.detailHeight + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("heightmapWH"); tmpNode.SetAttribute("w", terrainData.heightmapWidth + ""); tmpNode.SetAttribute("h", terrainData.heightmapHeight + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("heightmapResolution"); tmpNode.InnerText = (terrainData.heightmapResolution + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("heightmapScale"); tmpNode.InnerText = (terrainData.heightmapScale.x + " " + terrainData.heightmapScale.y + " " + terrainData.heightmapScale.z); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("hideFlags"); tmpNode.InnerText = (terrainData.hideFlags + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("wavingGrassAmount"); tmpNode.InnerText = (terrainData.wavingGrassAmount + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("wavingGrassSpeed"); tmpNode.InnerText = (terrainData.wavingGrassSpeed + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("wavingGrassStrength"); tmpNode.InnerText = (terrainData.wavingGrassStrength + ""); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("wavingGrassTint"); tmpNode.InnerText = (terrainData.wavingGrassTint.r + " " + terrainData.wavingGrassTint.g + " " + terrainData.wavingGrassTint.b + " " + terrainData.wavingGrassTint.a); root.AppendChild(tmpNode); tmpNode = xmlDoc.CreateElement("treePrototypes"); for (int i = 0; i < terrainData.treePrototypes.Length; i++) { TreePrototype tp = terrainData.treePrototypes[i]; XmlElement itemNode = xmlDoc.CreateElement("item"); itemNode.SetAttribute("prefab", tp.prefab.name); refPrefabs.Add(tp.prefab.name); XmlElement prefabsItemNode = xmlDoc.CreateElement("item"); prefabsItemNode.InnerText = tp.prefab.name; //prefabsNode.AppendChild(prefabsItemNode); itemNode.SetAttribute("bendFactor", tp.bendFactor + ""); tmpNode.AppendChild(itemNode); string path = "Assets/StreamingAssets/" + tp.prefab.name.Replace(" ", "_") + ".unity3d"; BuildPipeline.BuildAssetBundle(tp.prefab, null, path); } root.AppendChild(tmpNode); /* * tmpNode = xmlDoc.CreateElement("treeInstances"); * for(int i=0; i<terrainData.treeInstances.Length; i++) * { * TreeInstance ti = terrainData.treeInstances[i]; * XmlElement itemNode = xmlDoc.CreateElement("item"); * ti. * itemNode.SetAttribute("prefab", tp.prefab.name); * itemNode.SetAttribute("bendFactor", tp.bendFactor + ""); * * tmpNode.AppendChild(itemNode); * } * root.AppendChild(tmpNode); */ tmpNode = xmlDoc.CreateElement("detailPrototypes"); for (int i = 0; i < terrainData.detailPrototypes.Length; i++) { DetailPrototype dp = terrainData.detailPrototypes[i]; XmlElement itemNode = xmlDoc.CreateElement("item"); itemNode.SetAttribute("prefab", dp.prototypeTexture.name); refPrefabs.Add(dp.prototypeTexture.name); itemNode.SetAttribute("bendFactor", dp.bendFactor + ""); itemNode.SetAttribute("usePrototypeMesh", dp.usePrototypeMesh + ""); XmlElement prefabsItemNode = xmlDoc.CreateElement("item"); prefabsItemNode.InnerText = dp.prototypeTexture.name; //prefabsNode.AppendChild(prefabsItemNode); tmpNode.AppendChild(itemNode); string path = "Assets/StreamingAssets/" + dp.prototypeTexture.name.Replace(" ", "_") + ".unity3d"; BuildPipeline.BuildAssetBundle(dp.prototypeTexture, null, path); } root.AppendChild(tmpNode); XmlElement splatprotosNode = xmlDoc.CreateElement("splatprotos"); for (int i = 0; i < terrainData.splatPrototypes.Length; i++) { SplatPrototype sp = terrainData.splatPrototypes[i]; XmlElement itemNode = xmlDoc.CreateElement("item"); string texture = sp.texture != null ? sp.texture.name : ""; if (texture != "") { XmlElement prefabsItemNode = xmlDoc.CreateElement("item"); prefabsItemNode.InnerText = texture; //prefabsNode.AppendChild(prefabsItemNode); refPrefabs.Add(texture); string path = "Assets/StreamingAssets/" + texture.Replace(" ", "_") + ".unity3d"; BuildPipeline.BuildAssetBundle(sp.texture, null, path); } itemNode.SetAttribute("texture", texture); texture = sp.normalMap != null ? sp.normalMap.name : ""; if (texture != "") { XmlElement prefabsItemNode = xmlDoc.CreateElement("item"); prefabsItemNode.InnerText = texture; //prefabsNode.AppendChild(prefabsItemNode); refPrefabs.Add(texture); string path = "Assets/StreamingAssets/" + texture.Replace(" ", "_") + ".unity3d"; BuildPipeline.BuildAssetBundle(sp.normalMap, null, path); } itemNode.SetAttribute("normalMap", sp.normalMap != null ? sp.normalMap.name : ""); itemNode.SetAttribute("tileOffsetX", sp.tileOffset.x + ""); itemNode.SetAttribute("tileOffsetY", sp.tileOffset.y + ""); itemNode.SetAttribute("tileSizeX", sp.tileSize.x + ""); itemNode.SetAttribute("tileSizeY", sp.tileSize.y + ""); splatprotosNode.AppendChild(itemNode); } root.AppendChild(splatprotosNode); return(WorldNode); }
void GetSurfaceSound() { if (onTerrain) { TerrainData terrainData = terrain.terrainData; #region Texture Mix // calculate which splat map cell the worldPos falls within (ignoring y) int mapX = (int)(((transform.position.x - terrain.GetPosition().x) / terrainData.size.x) * terrainData.alphamapWidth); int mapZ = (int)(((transform.position.z - terrain.GetPosition().z) / terrainData.size.z) * terrainData.alphamapHeight); // get the splat data for this cell as a 1x1xN 3d array (where N = number of textures) float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 1, 1); // extract the 3D array data to a 1D array: float[] textureMix = new float[splatmapData.GetUpperBound(2) + 1]; for (int n = 0; n < textureMix.Length; n++) { textureMix[n] = splatmapData[0, 0, n]; } #endregion #region Texture Index float maxMix = 0; int maxIndex = 0; // loop through each mix value and find the maximum for (int n = 0; n < textureMix.Length; n++) { if (textureMix[n] > maxMix) { maxIndex = n; maxMix = textureMix[n]; } } int textureIndex = maxIndex; #endregion #region Set Footstep Sound string textureName = terrainData.splatPrototypes[textureIndex].texture.name; foreach (var texture in textureAttributes) { if (texture.texture.name == textureName) { footstepSound = textureAttributes[texture.index].footstepSounds; canRun = textureAttributes[texture.index].canRun; GetComponent <PlayerController>().canRun = textureAttributes[texture.index].canRun; GetComponent <PlayerController>().walkSpeed = textureAttributes[texture.index].walkSpeed; GetComponent <PlayerController>().runSpeed = textureAttributes[texture.index].runSpeed; } } #endregion } else if (onMesh) { //Physics Material if (detectionType == _type.TerrainTextureAndPhysicsMaterial) { foreach (var physicsMaterial in physicsMaterials) { if (currentPhysicsMaterial == physicsMaterial.material) { footstepSound = physicsMaterial.footstepSounds; canRun = physicsMaterial.canRun; GetComponent <PlayerController>().canRun = physicsMaterial.canRun; /* if(!physicsMaterial.canRun) * if (GetComponent<PlayerController>().isRunning) * GetComponent<PlayerController>().isRunning = false; */ GetComponent <PlayerController>().walkSpeed = physicsMaterial.walkSpeed; GetComponent <PlayerController>().runSpeed = physicsMaterial.runSpeed; } } } //Tag else if (detectionType == _type.TerrainTextureAndTag) { foreach (var tag in tags) { if (currentMeshTag == tag.tagName) { footstepSound = tag.footstepSounds; canRun = tag.canRun; GetComponent <PlayerController>().canRun = tag.canRun; /* if (!tag.canRun) * if (GetComponent<PlayerController>().isRunning) * GetComponent<PlayerController>().isRunning = false; */ GetComponent <PlayerController>().walkSpeed = tag.walkSpeed; GetComponent <PlayerController>().runSpeed = tag.runSpeed; } } } } }
/// <summary> /// Apply the Circle Brush /// </summary> /// <param name="modType">The modification type to apply</param> /// <param name="heightData">Terrain height data</param> /// <param name="terrainData">Terrain Data used</param> private void CircleBrush(TerrainModificationType modType, float[,] heightData, TerrainData terrainData) { int offsetX = m_BrushWidth / 2; int offsetY = m_BrushHeight / 2; for (int i = 0; i < m_BrushHeight; i++) { for (int j = 0; j < m_BrushWidth; j++) { float currentRadiusSqr = new Vector2(offsetX - j, offsetY - i).sqrMagnitude; if (currentRadiusSqr < offsetX * offsetY) { switch (modType) { case TerrainModificationType.Raise: heightData[i, j] = NewRaiseHeight(heightData[i, j], terrainData); break; case TerrainModificationType.Lower: heightData[i, j] = NewLowerHeight(heightData[i, j], terrainData); break; case TerrainModificationType.Flatten: heightData[i, j] = NewFlattenHeight(heightData[offsetX, offsetY], terrainData); break; case TerrainModificationType.Smooth: SmoothTerrainOperation(1, heightData, j, i); break; } } } } }
public static Dictionary <Vector2Int, Terrain> SplitTerrainIntoChunks( Terrain split, float chunkSize, int heightsRes, int alphasRes, int detailsRes ) { if (split == null) { Debug.LogWarning("splitTerrain == null"); return(null); } TerrainData splitData = split.terrainData; float parentSize = splitData.size.x; if (parentSize <= chunkSize) { Debug.Log("splitTerrain fits in one grid already..."); return(null); } int splits = CalculateChunksInTerrain(split, chunkSize); Dictionary <Vector2Int, Terrain> grid2Terrain = new Dictionary <Vector2Int, Terrain>(); float[,] heights = splitData.GetHeights(0, 0, splitData.heightmapResolution, splitData.heightmapResolution); float[,] chunkHeights = new float[heightsRes, heightsRes]; TerrainLayer[] terrainLayers = splitData.terrainLayers; float[,,] alphas = splitData.GetAlphamaps(0, 0, splitData.alphamapResolution, splitData.alphamapResolution); float[,,] chunkAlphas = new float[alphasRes, alphasRes, splitData.alphamapLayers]; detailsRes = Mathf.Max(0, detailsRes); DetailPrototype[] detailPrototypes = splitData.detailPrototypes; int[][,] details = new int[detailPrototypes.Length][, ]; int[,] chunkDetails = new int[detailsRes, detailsRes]; if (detailsRes > 0) { for (int i = 0; i < detailPrototypes.Length; i++) { details[i] = splitData.GetDetailLayer(0, 0, splitData.detailResolution, splitData.detailResolution, i); } } TreePrototype[] treePrototypes = splitData.treePrototypes; TreeInstance[] treeInstances = splitData.treeInstances; Vector3 chunkSize3 = new Vector3(chunkSize, splitData.size.y, chunkSize); for (int y = 0; y < splits; y++) { for (int x = 0; x < splits; x++) { Vector2Int grid = new Vector2Int(x, y); TerrainData data = new TerrainData(); GameObject terrainG = Terrain.CreateTerrainGameObject(data); terrainG.name = split.name + "_" + grid; Terrain terrain = terrainG.GetComponent <Terrain>(); terrain.terrainData = data; grid2Terrain[grid] = terrain; // Copy parent terrain propeties #region parent properties terrain.basemapDistance = split.basemapDistance; terrain.castShadows = split.castShadows; terrain.detailObjectDensity = split.detailObjectDensity; terrain.detailObjectDistance = split.detailObjectDistance; terrain.heightmapPixelError = split.heightmapPixelError; terrain.treeBillboardDistance = split.treeBillboardDistance; terrain.treeCrossFadeLength = split.treeCrossFadeLength; terrain.treeDistance = split.treeDistance; terrain.treeMaximumFullLODCount = split.treeMaximumFullLODCount; #endregion Vector3 gridWorld = new Vector3(grid.x * chunkSize, 0, grid.y * chunkSize); terrain.transform.position = split.transform.position + gridWorld; SplitHeights(data, splitData, gridWorld, chunkSize, parentSize, chunkHeights, heights, heightsRes); SplitAlphas(data, splitData, gridWorld, chunkSize, parentSize, chunkAlphas, alphas, alphasRes, terrainLayers); if (detailsRes > 0) { SplitDetails(data, splitData, gridWorld, chunkSize, parentSize, chunkDetails, details, detailsRes, detailPrototypes); } SplitTrees(terrain, splitData, gridWorld, chunkSize, treeInstances, treePrototypes); data.size = chunkSize3; } } return(grid2Terrain); }
/// <summary> /// Apply the Rectangle Brush /// </summary> /// <param name="modType">The modification type to apply</param> /// <param name="heightData">Terrain height data</param> /// <param name="terrainData">Terrain Data used</param> private void RectangleBrush(TerrainModificationType modType, float[,] heightData, TerrainData terrainData) { int offsetX = m_BrushWidth / 2; int offsetY = m_BrushHeight / 2; for (int i = 0; i < m_BrushHeight; i++) { for (int j = 0; j < m_BrushWidth; j++) { switch (modType) { case TerrainModificationType.Raise: heightData[i, j] = NewRaiseHeight(heightData[i, j], terrainData); break; case TerrainModificationType.Lower: heightData[i, j] = NewLowerHeight(heightData[i, j], terrainData); break; case TerrainModificationType.Flatten: heightData[i, j] = NewFlattenHeight(heightData[offsetX, offsetY], terrainData); break; case TerrainModificationType.Smooth: SmoothTerrainOperation(1, heightData, i, j); break; } } } }
public IEnumerator CreateImpl() { try { using (m_queue = new JobQueue(8)) { Stopwatch sw = new Stopwatch(); AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); sw.Reset(); sw.Start(); EditorUtility.DisplayProgressBar("Bake HLOD", "Initialize Bake", 0.0f); TerrainData data = m_hlod.TerrainData; m_size = data.size; m_heightmap = new Heightmap(data.heightmapResolution, data.heightmapResolution, data.size, data.GetHeights(0, 0, data.heightmapResolution, data.heightmapResolution)); string materialPath = AssetDatabase.GUIDToAssetPath(m_hlod.MaterialGUID); m_terrainMaterial = AssetDatabase.LoadAssetAtPath <Material>(materialPath); if (m_terrainMaterial == null) { m_terrainMaterial = new Material(Shader.Find("Lightweight Render Pipeline/Lit-Terrain-HLOD-High")); } m_terrainMaterialInstanceId = m_terrainMaterial.GetInstanceID(); m_terrainMaterialName = m_terrainMaterial.name; materialPath = AssetDatabase.GUIDToAssetPath(m_hlod.MaterialLowGUID); m_terrainMaterialLow = AssetDatabase.LoadAssetAtPath <Material>(materialPath); if (m_terrainMaterialLow == null) { m_terrainMaterialLow = new Material(Shader.Find("Lightweight Render Pipeline/Lit-Terrain-HLOD-Low")); } m_terrainMaterialLowInstanceId = m_terrainMaterialLow.GetInstanceID(); m_terrainMaterialLowName = m_terrainMaterialLow.name; using (m_alphamaps = new DisposableList <WorkingTexture>()) using (m_layers = new DisposableList <Layer>()) { for (int i = 0; i < data.alphamapTextures.Length; ++i) { m_alphamaps.Add(new WorkingTexture(Allocator.Persistent, data.alphamapTextures[i])); } for (int i = 0; i < data.terrainLayers.Length; ++i) { m_layers.Add(new Layer(data.terrainLayers[i], m_hlod.ChunkSize)); } QuadTreeSpaceSplitter splitter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = splitter.CreateSpaceTree(m_hlod.GetBounds(), m_hlod.ChunkSize * 2.0f, m_hlod.transform.position, null, progress => { }); EditorUtility.DisplayProgressBar("Bake HLOD", "Create mesh", 0.0f); using (DisposableList <HLODBuildInfo> buildInfos = CreateBuildInfo(data, rootNode)) { yield return(m_queue.WaitFinish()); //Write material & textures for (int i = 0; i < buildInfos.Count; ++i) { int curIndex = i; m_queue.EnqueueJob(() => { ISimplifier simplifier = (ISimplifier)Activator.CreateInstance(m_hlod.SimplifierType, new object[] { m_hlod.SimplifierOptions }); simplifier.SimplifyImmidiate(buildInfos[curIndex]); }); } EditorUtility.DisplayProgressBar("Bake HLOD", "Simplify meshes", 0.0f); yield return(m_queue.WaitFinish()); Debug.Log("[TerrainHLOD] Simplify: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); EditorUtility.DisplayProgressBar("Bake HLOD", "Make border", 0.0f); for (int i = 0; i < buildInfos.Count; ++i) { HLODBuildInfo info = buildInfos[i]; m_queue.EnqueueJob(() => { for (int oi = 0; oi < info.WorkingObjects.Count; ++oi) { WorkingObject o = info.WorkingObjects[oi]; int borderVertexCount = m_hlod.BorderVertexCount * Mathf.RoundToInt(Mathf.Pow(2.0f, (float)info.Distances[oi])); using (WorkingMesh m = MakeBorder(o.Mesh, info.Heightmap, borderVertexCount)) { ReampUV(m, info.Heightmap); o.SetMesh(MakeFillHoleMesh(m)); } } }); } yield return(m_queue.WaitFinish()); Debug.Log("[TerrainHLOD] Make Border: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); for (int i = 0; i < buildInfos.Count; ++i) { SpaceNode node = buildInfos[i].Target; HLODBuildInfo info = buildInfos[i]; if (node.HasChild() == false) { SpaceNode parent = node.ParentNode; node.ParentNode = null; GameObject go = new GameObject(buildInfos[i].Name); for (int wi = 0; wi < info.WorkingObjects.Count; ++wi) { WorkingObject wo = info.WorkingObjects[wi]; GameObject targetGO = null; if (wi == 0) { targetGO = go; } else { targetGO = new GameObject(wi.ToString()); targetGO.transform.SetParent(go.transform, false); } List <Material> materials = new List <Material>(); for (int mi = 0; mi < wo.Materials.Count; ++mi) { WorkingMaterial wm = wo.Materials[mi]; if (wm.NeedWrite() == false) { materials.Add(wm.ToMaterial()); continue; } Material mat = new Material(wm.ToMaterial()); string[] textureNames = wm.GetTextureNames(); for (int ti = 0; ti < textureNames.Length; ++ti) { WorkingTexture wt = wm.GetTexture(textureNames[ti]); Texture2D tex = wt.ToTexture(); tex.wrapMode = wt.WrapMode; mat.name = targetGO.name + "_Mat"; mat.SetTexture(textureNames[ti], tex); } mat.EnableKeyword("_NORMALMAP"); materials.Add(mat); } targetGO.AddComponent <MeshFilter>().sharedMesh = wo.Mesh.ToMesh(); var mr = targetGO.AddComponent <MeshRenderer>(); mr.sharedMaterials = materials.ToArray(); mr.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; } go.transform.SetParent(m_hlod.transform, false); m_hlod.AddGeneratedResource(go); parent.Objects.Add(go); buildInfos.RemoveAt(i); i -= 1; } } //controller IStreamingBuilder builder = (IStreamingBuilder)Activator.CreateInstance(m_hlod.StreamingType, new object[] { m_hlod, m_hlod.StreamingOptions }); builder.Build(rootNode, buildInfos, m_hlod.gameObject, m_hlod.CullDistance, m_hlod.LODDistance, true, false, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Storing results.", 0.75f + progress * 0.25f); }); Debug.Log("[TerrainHLOD] Build: " + sw.Elapsed.ToString("g")); } } EditorUtility.SetDirty(m_hlod.gameObject); } } finally { EditorUtility.ClearProgressBar(); GC.Collect(); } }
private void OldAssignTextures() { // Get a reference to the terrain data TerrainData terrainData = _terrain.terrainData; // Splatmap data is stored internally as a 3d array of floats, so declare a new empty array ready for your custom splatmap data: float[,,] splatmapData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers]; for (int y = 0; y < terrainData.alphamapHeight; y++) { for (int x = 0; x < terrainData.alphamapWidth; x++) { // Normalise x/y coordinates to range 0-1 float y_01 = (float)y / (float)terrainData.alphamapHeight; float x_01 = (float)x / (float)terrainData.alphamapWidth; // Sample the height at this location (note GetHeight expects int coordinates corresponding to locations in the heightmap array) //float height = terrainData.GetHeight(Mathf.RoundToInt(y_01 * terrainData.heightmapHeight), Mathf.RoundToInt(x_01 * terrainData.heightmapWidth)); // Calculate the normal of the terrain (note this is in normalised coordinates relative to the overall terrain dimensions) //Vector3 normal = terrainData.GetInterpolatedNormal(y_01, x_01); // Calculate the steepness of the terrain // float steepness = terrainData.GetSteepness(y_01, x_01); // Setup an array to record the mix of texture weights at this point float[] splatWeights = new float[terrainData.alphamapLayers]; // CHANGE THE RULES BELOW TO SET THE WEIGHTS OF EACH TEXTURE ON WHATEVER RULES YOU WANT CaseInfos caseInfo = _mapInfosManager.GetInfosAtPos(new Vector2(x, y)); CaseInfos infoXPlus = _mapInfosManager.GetInfosAtPos(new Vector2(x + 10, y)); CaseInfos infoXMoins = _mapInfosManager.GetInfosAtPos(new Vector2(x - 10, y)); CaseInfos infoYPlus = _mapInfosManager.GetInfosAtPos(new Vector2(x, y + 10)); CaseInfos infoYMoins = _mapInfosManager.GetInfosAtPos(new Vector2(x, y - 10)); int idCase = GetTextureId(caseInfo); int idXPlus = GetTextureId(infoXPlus); int idXMoins = GetTextureId(infoXMoins); int idYPlus = GetTextureId(infoYPlus); int idYMoins = GetTextureId(infoYMoins); if (caseInfo == null) { //Debug.LogWarning("Case infos not found at pos (" + x + "," + y + ")"); splatWeights[0] = 0.5f; splatWeights[1] = 0.5f; } else { int yunit = y - (y / 10) * 10; int xunit = x - (x / 10) * 10; float currentRatio; if (xunit < 4 && xunit != 0 && idXMoins != -1 && idXMoins != idCase) { currentRatio = (-2 * xunit + 7) / 10.0f; splatWeights[idXMoins] = currentRatio + splatWeights[idXMoins] - splatWeights[idXMoins] * currentRatio; } else if (xunit > 7 && idXPlus != -1 && idXPlus != idCase) { currentRatio = (2 * xunit - 15) / 10.0f; splatWeights[idXPlus] = currentRatio + splatWeights[idXPlus] - splatWeights[idXPlus] * currentRatio; } else if (xunit == 0 && idXPlus != -1 && idXPlus != idCase) { currentRatio = 0.49f; splatWeights[idXPlus] = currentRatio + splatWeights[idXPlus] - splatWeights[idXPlus] * currentRatio; } if (yunit < 4 && yunit != 0 && idYMoins != -1 && idYMoins != idCase) { currentRatio = (-2 * yunit + 7) / 10.0f; splatWeights[idYMoins] = currentRatio + splatWeights[idYMoins] - splatWeights[idYMoins] * currentRatio; } else if (yunit > 7 && idYPlus != -1 && idYPlus != idCase) { currentRatio = (2 * yunit - 15) / 10.0f; splatWeights[idYPlus] = currentRatio + splatWeights[idYPlus] - splatWeights[idYPlus] * currentRatio; } else if (yunit == 0 && idYPlus != -1 && idYPlus != idCase) { currentRatio = 0.50f; splatWeights[idYPlus] = currentRatio + splatWeights[idYPlus] - splatWeights[idYPlus] * currentRatio; } splatWeights[idCase] = splatWeights[idCase] == 0 ? 1 - splatWeights.Sum() : splatWeights[idCase] * (1 - splatWeights.Sum()); } // Texture[2] stronger on flatter terrain // Note "steepness" is unbounded, so we "normalise" it by dividing by the extent of heightmap height and scale factor // Subtract result from 1.0 to give greater weighting to flat surfaces //splatWeights[2] = 1.0f - Mathf.Clamp01(steepness * steepness / (terrainData.heightmapHeight / 5.0f)); // Texture[3] increases with height but only on surfaces facing positive Z axis //splatWeights[3] = height * Mathf.Clamp01(normal.z); // Sum of all textures weights must add to 1, so calculate normalization factor from sum of weights float z = splatWeights.Sum(); // Loop through each terrain texture for (int i = 0; i < terrainData.alphamapLayers; i++) { // Normalize so that sum of all texture weights = 1 splatWeights[i] /= z; // Assign this point to the splatmap array splatmapData[x, y, i] = splatWeights[i]; } } } // Finally assign the new splatmap to the terrainData: terrainData.SetAlphamaps(0, 0, splatmapData); }
/// <summary> /// Calculate the new height after lowering /// </summary> /// <param name="currentHeight">Current terrain height</param> /// <param name="terrainData">The used terrain Data</param> /// <returns>The new height</returns> private float NewLowerHeight(float currentHeight, TerrainData terrainData) { return(Mathf.Clamp(currentHeight - (m_ModificationSpeed * Time.deltaTime) / terrainData.size.y, m_MinHeight / terrainData.size.y, m_MaxHeight / terrainData.size.y)); }
void OnGUI() { //Выводим текст GUILayout.Label("Procedurally texture terrain, by Christian S."); GUILayout.Label("Terrain:"); ter = (Terrain)EditorGUILayout.ObjectField(ter, typeof(Terrain), true); if (ter != null) { blendByAngle = GUILayout.Toggle(blendByAngle, "Blend by Angle"); // Array stuff goes here ScriptableObject target = this; SerializedObject so = new SerializedObject(target); SerializedProperty stringsProperty = so.FindProperty("splatHeights"); EditorGUILayout.PropertyField(stringsProperty, true); // True means show children so.ApplyModifiedProperties(); // Remember to apply modified properties if (GUILayout.Button("Apply")) { Debug.Log("Applied"); TerrainData terrainData = Terrain.activeTerrain.terrainData; float[,,] splatmapData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers]; for (int y = 0; y < terrainData.alphamapHeight; y++) { for (int x = 0; x < terrainData.alphamapWidth; x++) { float terrainHeight = terrainData.GetHeight(y, x); float[] splat = new float[splatHeights.Length]; for (int i = 0; i < splatHeights.Length; i++) { float thisNoise = Mathf.Clamp(Mathf.PerlinNoise(x * 0.05f, y * 0.05f), 0.5f, 1f); float thisHeightStart = findHeightByIndex(i).startingHeight *thisNoise - findHeightByIndex(i).overlap *thisNoise; float nextHeightStart = 0; if (i != splatHeights.Length - 1) { nextHeightStart = findHeightByIndex(i + 1).startingHeight *thisNoise + findHeightByIndex(i + 1).overlap *thisNoise; } if (i == splatHeights.Length - 1 && terrainHeight >= findHeightByIndex(i).startingHeight) { splat[findHeightByIndex(i).textureIndex] = 1; } else if (terrainHeight >= findHeightByIndex(i).startingHeight&& terrainHeight <= findHeightByIndex(i + 1).startingHeight) { splat[findHeightByIndex(i).textureIndex] = 1; } //normalize(splat); for (int j = 0; j < splatHeights.Length; j++) { splatmapData[x, y, j] = splat[findHeightByIndex(j).textureIndex]; } } if (blendByAngle) { // Get the normalized terrain coordinate that // corresponds to the the point. float normX = x * 1.0f / (terrainData.alphamapWidth - 1); float normY = y * 1.0f / (terrainData.alphamapHeight - 1); var angle = terrainData.GetSteepness(normX, normY); // Steepness is given as an angle, 0..90 degrees. Divide // by 90 to get an alpha blending value in the range 0..1. var frac = angle / 180.0; splatmapData[x, y, 0] = (float)frac; splatmapData[x, y, 1] = (float)(1 - frac); float[] dirHi = new float[5]; dirHi[0] = terrainData.GetHeight(y, x); dirHi[1] = terrainData.GetHeight(y + 1, x); dirHi[2] = terrainData.GetHeight(y, x + 1); dirHi[3] = terrainData.GetHeight(y - 1, x); dirHi[4] = terrainData.GetHeight(y, x - 1); // convert to a-n... } //Based on height of it and nearby pos, change texture. } terrainData.SetAlphamaps(0, 0, splatmapData); } } } }
public static void GenerateSplatMap(ChunkData chunkData) { // Get the attached terrain component Terrain terrain = chunkData.terrain; // Get a reference to the terrain data TerrainData terrainData = chunkData.terrainData; TextureData[] textureData = ProceduralTerrain.Current.TerrainMapData.TerrainTextures; float constantWeight = ProceduralTerrain.Current.TerrainMapData.Texture1ConstantWeight; float steepnessScale = ProceduralTerrain.Current.TerrainMapData.TextureSteepnessScaleFactor; float textureBlendAmount = ProceduralTerrain.Current.TerrainMapData.TextureBlendAmount; // Splatmap data is stored internally as a 3d array of floats, so declare a new empty array ready for your custom splatmap data: float[,,] splatmapData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers]; for (int y = 0; y < terrainData.alphamapHeight; y++) { for (int x = 0; x < terrainData.alphamapWidth; x++) { // Normalise x/y coordinates to range 0-1 float y_01 = (float)y / (float)terrainData.alphamapHeight; float x_01 = (float)x / (float)terrainData.alphamapWidth; // Sample the height at this location (note GetHeight expects int coordinates corresponding to locations in the heightmap array) float height = terrainData.GetHeight(Mathf.RoundToInt(y_01 * terrainData.heightmapHeight), Mathf.RoundToInt(x_01 * terrainData.heightmapWidth)); // Calculate the normal of the terrain (note this is in normalised coordinates relative to the overall terrain dimensions) Vector3 normal = terrainData.GetInterpolatedNormal(y_01, x_01); // Calculate the steepness of the terrain float steepness = terrainData.GetSteepness(y_01, x_01); // Setup an array to record the mix of texture weights at this point float[] splatWeights = new float[terrainData.alphamapLayers]; // CHANGE THE RULES BELOW TO SET THE WEIGHTS OF EACH TEXTURE ON WHATEVER RULES YOU WANT height = height / ProceduralTerrain.Current.TerrainMapData.TerrainHeight; //For steeper terrains, last value in array is always for steepness splatWeights[textureData.Length - 1] = Mathf.Clamp01(steepness * steepness / (terrainData.heightmapHeight / steepnessScale)); //If is not too steep apply other textures if (splatWeights[textureData.Length - 1] < 0.8f) { //Go backwards through textures for (int i = 0; i < textureData.Length; i++) { if (height > textureData[i].TextureStartHeight) { //If not last element in array and height value is less than the next textures start height if (i < textureData.Length - 1 && textureData[i + 1].TextureStartHeight > height) { splatWeights[i] = 1; } } } } //if(height - 0.1f > 0.1f) //for (int i = 0; i < splatWeights.Length - 1; i++) { // splatWeights[i] -= textureBlendAmount; // splatWeights[i + 1] += textureBlendAmount; //} // Texture[0] has constant influence //splatWeights[0] = constantWeight; // Texture[1] is stronger at lower altitudes //splatWeights[1] = 1; //Mathf.Clamp01(1 - height / ProceduralTerrain.Current.TerrainMapData.TerrainHeight); // Texture[2] stronger on flatter terrain // Note "steepness" is unbounded, so we "normalise" it by dividing by the extent of heightmap height and scale factor // Subtract result from 1.0 to give greater weighting to flat surfaces //splatWeights[2] = 1.0f - Mathf.Clamp01(steepness * steepness / (terrainData.heightmapHeight / steepnessScale)); // Texture[3] steeper terrains //splatWeights[3] = Mathf.Clamp01(steepness * steepness / (terrainData.heightmapHeight / steepnessScale));//Mathf.Clamp01(height / ProceduralTerrain.Current.TerrainMapData.TerrainHeight); //* Mathf.Clamp01(normal.z); // Sum of all textures weights must add to 1, so calculate normalization factor from sum of weights float z = splatWeights.Sum(); // Loop through each terrain texture for (int i = 0; i < terrainData.alphamapLayers; i++) { // Normalize so that sum of all texture weights = 1 splatWeights[i] /= z; // Assign this point to the splatmap array splatmapData[x, y, i] = splatWeights[i]; } } } // Finally assign the new splatmap to the terrainData: terrainData.SetAlphamaps(0, 0, splatmapData); }
private DigResult AttemptToDig(long checkX, long checkY, long checkZ) { mnCurrentDigSizeY = digArea.CurrentHeight; var segment = mFrustrum != null ? AttemptGetSegment(checkX, checkY, checkZ) : WorldScript.instance.GetSegment(checkX, checkY, checkZ); if (segment == null || !segment.mbInitialGenerationComplete || segment.mbDestroyed) { mrDigDelay = 1f; return(DigResult.Fail); } ushort cube = segment.GetCube(checkX, checkY, checkZ); if (cube == eCubeTypes.CentralPowerHub) { return(DigResult.Dig); } if (cube == mReplaceType) { return(DigResult.Skip); } if (CubeHelper.IsReinforced(cube) && eExcavateState != ExcavateState.ClearAll) { return(DigResult.Dig); } if (CubeHelper.HasEntity((int)cube) && eExcavateState != ExcavateState.ClearAll) { if (cube != eCubeTypes.AlienPlant && cube != eCubeTypes.ArachnidRock) { return(DigResult.Dig); } } if (TerrainData.GetHardness(cube, 0) > 500f) { return(DigResult.Dig); } if (eExcavateState == ExcavateState.ClearGarbage) { if (CubeHelper.IsOre(cube)) { return(DigResult.Dig); } } // Tranqs Creative Survival mod really breaks this call as nearly everything in the game is craftable. if (CraftingManager.IsCraftable(cube) && cube != eCubeTypes.Giger && eExcavateState != ExcavateState.ClearAll) { // ore should never ever be craftable if (!CubeHelper.IsOre(cube)) { return(DigResult.Dig); } } int num = (int)(checkX - segment.baseX); int num2 = (int)(checkY - segment.baseY); int num3 = (int)(checkZ - segment.baseZ); if (num == 0 && base.AttemptGetSegment(checkX - 1L, checkY, checkZ) == null) { return(DigResult.Fail); } if (num == 15 && base.AttemptGetSegment(checkX + 1L, checkY, checkZ) == null) { return(DigResult.Fail); } if (num2 == 0 && base.AttemptGetSegment(checkX, checkY - 1L, checkZ) == null) { return(DigResult.Fail); } if (num2 == 15 && base.AttemptGetSegment(checkX, checkY + 1L, checkZ) == null) { return(DigResult.Fail); } if (num3 == 0 && base.AttemptGetSegment(checkX, checkY, checkZ - 1L) == null) { return(DigResult.Fail); } if (num3 == 15 && base.AttemptGetSegment(checkX, checkY, checkZ + 1L) == null) { return(DigResult.Fail); } ushort mValue = segment.GetCubeData(checkX, checkY, checkZ).mValue; WorldScript.instance.BuildFromEntity(segment, checkX, checkY, checkZ, this.mReplaceType, TerrainData.GetDefaultValue(this.mReplaceType)); this.mrCurrentPower -= this.mrPowerRate; this.mbLocatedBlock = true; this.mnBlocksDestroyed++; if (segment.mbInLocalFrustrum) { if (eDropState == DropState.DropSome) { bool flag = true; if (CubeHelper.IsGarbage(cube) && this.mRand.Next(100) > 5) { flag = false; } if (flag) { Vector3 velocity = new Vector3((float)this.mRand.NextDouble() - 0.5f, 0f, (float)this.mRand.NextDouble() - 0.5f); velocity.x *= 5f; velocity.z *= 5f; ItemManager.DropNewCubeStack(cube, mValue, 1, checkX, checkY, checkZ, velocity); } } if (eDropState == DropState.DropAll) { Vector3 velocity = new Vector3((float)this.mRand.NextDouble() - 0.5f, 0f, (float)this.mRand.NextDouble() - 0.5f); velocity.x *= 5f; velocity.z *= 5f; ItemManager.DropNewCubeStack(cube, mValue, 1, checkX, checkY, checkZ, velocity); } if (eDropState == DropState.DropOre && CubeHelper.IsOre(cube)) { Vector3 velocity = new Vector3((float)this.mRand.NextDouble() - 0.5f, 0f, (float)this.mRand.NextDouble() - 0.5f); velocity.x *= 5f; velocity.z *= 5f; ItemManager.DropNewCubeStack(cube, mValue, 1, checkX, checkY, checkZ, velocity); } this.mrTimeSinceShoot = 0f; } return(DigResult.Dig); }
Vector3 GetTerrainVertex(TerrainData terrain, int x, int y, float sampleWidthInMeter, float sampleHeightInMeter) { Vector3 v = new Vector3(x * sampleWidthInMeter, terrain.GetHeight(x, y), y * sampleHeightInMeter); return(v); }
void DoFourWaySplit() { //Split terrain for (int i = 0; i < terrainsCount; i++) { EditorUtility.DisplayProgressBar("Split terrain", "Process " + i, (float)i / terrainsCount); TerrainData td = new TerrainData(); GameObject tgo = Terrain.CreateTerrainGameObject(td); tgo.name = parentTerrain.name + "_" + i; terrainData.Add(td); terrainGo.Add(tgo); Terrain genTer = tgo.GetComponent(typeof(Terrain)) as Terrain; genTer.terrainData = td; AssetDatabase.CreateAsset(td, _assetsPath + "/" + genTer.name + ".asset"); // added chunked tiles to lists for further iterations terrainMatrix.Add(genTer); terrainAssets.Add(genTer.name + ".asset"); // Assign splatmaps genTer.terrainData.splatPrototypes = parentTerrain.terrainData.splatPrototypes; // Assign detail prototypes genTer.terrainData.detailPrototypes = parentTerrain.terrainData.detailPrototypes; // Assign tree information genTer.terrainData.treePrototypes = parentTerrain.terrainData.treePrototypes; // Copy parent terrain propeties #region parent properties genTer.basemapDistance = parentTerrain.basemapDistance; genTer.castShadows = parentTerrain.castShadows; genTer.detailObjectDensity = parentTerrain.detailObjectDensity; genTer.detailObjectDistance = parentTerrain.detailObjectDistance; genTer.heightmapMaximumLOD = parentTerrain.heightmapMaximumLOD; genTer.heightmapPixelError = parentTerrain.heightmapPixelError; genTer.treeBillboardDistance = parentTerrain.treeBillboardDistance; genTer.treeCrossFadeLength = parentTerrain.treeCrossFadeLength; genTer.treeDistance = parentTerrain.treeDistance; genTer.treeMaximumFullLODCount = parentTerrain.treeMaximumFullLODCount; #endregion //Start processing it // Translate peace to position #region translate peace to right position Vector3 parentPosition = parentTerrain.GetPosition(); int terraPeaces = (int)Mathf.Sqrt(terrainsCount); float spaceShiftX = parentTerrain.terrainData.size.z / terraPeaces; float spaceShiftY = parentTerrain.terrainData.size.x / terraPeaces; float xWShift = (i % terraPeaces) * spaceShiftX; float zWShift = (i / terraPeaces) * spaceShiftY; tgo.transform.position = new Vector3(tgo.transform.position.x + zWShift, tgo.transform.position.y, tgo.transform.position.z + xWShift); // Shift last position tgo.transform.position = new Vector3(tgo.transform.position.x + parentPosition.x, tgo.transform.position.y + parentPosition.y, tgo.transform.position.z + parentPosition.z ); #endregion // Split height #region split height if (_debugToLog) { Debug.Log("Split height on" + tgo.name); } //Copy heightmap td.heightmapResolution = parentTerrain.terrainData.heightmapResolution / terraPeaces; //Keep y same td.size = new Vector3(parentTerrain.terrainData.size.x / terraPeaces, parentTerrain.terrainData.size.y, parentTerrain.terrainData.size.z / terraPeaces ); float[,] parentHeight = parentTerrain.terrainData.GetHeights(0, 0, parentTerrain.terrainData.heightmapResolution, parentTerrain.terrainData.heightmapResolution); float[,] peaceHeight = new float[parentTerrain.terrainData.heightmapResolution / terraPeaces + 1, parentTerrain.terrainData.heightmapResolution / terraPeaces + 1 ]; // Shift calc int heightShift = parentTerrain.terrainData.heightmapResolution / terraPeaces; int startX = 0; int startY = 0; int endX = 0; int endY = 0; if (i == 0) { startX = startY = 0; endX = endY = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; } if (i == 1) { startX = startY = 0; endX = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; endY = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; } if (i == 2) { startX = startY = 0; endX = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; endY = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; } if (i == 3) { startX = startY = 0; endX = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; endY = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1; } // iterate for (int x = startX; x < endX; x++) { EditorUtility.DisplayProgressBar("Split terrain", "Split height", (float)x / (endX - startX)); for (int y = startY; y < endY; y++) { int xShift = 0; int yShift = 0; // if (i == 0) { xShift = 0; yShift = 0; } // if (i == 1) { xShift = heightShift; yShift = 0; } // if (i == 2) { xShift = 0; yShift = heightShift; } if (i == 3) { xShift = heightShift; yShift = heightShift; } float ph = parentHeight[x + xShift, y + yShift]; peaceHeight[x, y] = ph; } } EditorUtility.ClearProgressBar(); // Set heightmap to child genTer.terrainData.SetHeights(0, 0, peaceHeight); #endregion // Split splat map #region split splat map td.alphamapResolution = parentTerrain.terrainData.alphamapResolution / terraPeaces; float[,,] parentSplat = parentTerrain.terrainData.GetAlphamaps(0, 0, parentTerrain.terrainData.alphamapResolution, parentTerrain.terrainData.alphamapResolution); float[,,] peaceSplat = new float[parentTerrain.terrainData.alphamapResolution / terraPeaces, parentTerrain.terrainData.alphamapResolution / terraPeaces, parentTerrain.terrainData.alphamapLayers ]; // Shift calc int splatShift = parentTerrain.terrainData.alphamapResolution / terraPeaces; if (i == 0) { startX = startY = 0; endX = endY = parentTerrain.terrainData.alphamapResolution / terraPeaces; } if (i == 1) { startX = startY = 0; endX = parentTerrain.terrainData.alphamapResolution / terraPeaces; endY = parentTerrain.terrainData.alphamapResolution / terraPeaces; } if (i == 2) { startX = startY = 0; endX = parentTerrain.terrainData.alphamapResolution / terraPeaces; endY = parentTerrain.terrainData.alphamapResolution / terraPeaces; } if (i == 3) { startX = startY = 0; endX = parentTerrain.terrainData.alphamapResolution / terraPeaces; endY = parentTerrain.terrainData.alphamapResolution / terraPeaces; } // iterate for (int s = 0; s < parentTerrain.terrainData.alphamapLayers; s++) { for (int x = startX; x < endX; x++) { EditorUtility.DisplayProgressBar("Split terrain", "Split splat", (float)x / (endX - startX)); for (int y = startY; y < endY; y++) { int xShift = 0; int yShift = 0; // if (i == 0) { xShift = 0; yShift = 0; } // if (i == 1) { xShift = splatShift; yShift = 0; } // if (i == 2) { xShift = 0; yShift = splatShift; } if (i == 3) { xShift = splatShift; yShift = splatShift; } float ph = parentSplat[x + xShift, y + yShift, s]; peaceSplat[x, y, s] = ph; } } } EditorUtility.ClearProgressBar(); // Set heightmap to child genTer.terrainData.SetAlphamaps(0, 0, peaceSplat); #endregion // Split detail map #region split detail map td.SetDetailResolution(parentTerrain.terrainData.detailResolution / terraPeaces, 8); for (int detLay = 0; detLay < parentTerrain.terrainData.detailPrototypes.Length; detLay++) { int[,] parentDetail = parentTerrain.terrainData.GetDetailLayer(0, 0, parentTerrain.terrainData.detailResolution, parentTerrain.terrainData.detailResolution, detLay); int[,] peaceDetail = new int[parentTerrain.terrainData.detailResolution / terraPeaces, parentTerrain.terrainData.detailResolution / terraPeaces ]; // Shift calc int detailShift = parentTerrain.terrainData.detailResolution / terraPeaces; if (i == 0) { startX = startY = 0; endX = endY = parentTerrain.terrainData.detailResolution / terraPeaces; } if (i == 1) { startX = startY = 0; endX = parentTerrain.terrainData.detailResolution / terraPeaces; endY = parentTerrain.terrainData.detailResolution / terraPeaces; } if (i == 2) { startX = startY = 0; endX = parentTerrain.terrainData.detailResolution / terraPeaces; endY = parentTerrain.terrainData.detailResolution / terraPeaces; } if (i == 3) { startX = startY = 0; endX = parentTerrain.terrainData.detailResolution / terraPeaces; endY = parentTerrain.terrainData.detailResolution / terraPeaces; } // iterate for (int x = startX; x < endX; x++) { EditorUtility.DisplayProgressBar("Split terrain", "Split detail", (float)x / (endX - startX)); for (int y = startY; y < endY; y++) { int xShift = 0; int yShift = 0; // if (i == 0) { xShift = 0; yShift = 0; } // if (i == 1) { xShift = detailShift; yShift = 0; } // if (i == 2) { xShift = 0; yShift = detailShift; } if (i == 3) { xShift = detailShift; yShift = detailShift; } int ph = parentDetail[x + xShift, y + yShift]; peaceDetail[x, y] = ph; } } EditorUtility.ClearProgressBar(); // Set heightmap to child genTer.terrainData.SetDetailLayer(0, 0, detLay, peaceDetail); } #endregion // Split tree data #region split tree data for (int t = 0; t < parentTerrain.terrainData.treeInstances.Length; t++) { EditorUtility.DisplayProgressBar("Split terrain", "Split trees ", (float)t / parentTerrain.terrainData.treeInstances.Length); // Get tree instance TreeInstance ti = parentTerrain.terrainData.treeInstances[t]; // First section if (i == 0 && ti.position.x > 0f && ti.position.x < 0.5f && ti.position.z > 0f && ti.position.z < 0.5f ) { // Recalculate new tree position ti.position = new Vector3(ti.position.x * 2f, ti.position.y, ti.position.z * 2f); // Add tree instance genTer.AddTreeInstance(ti); } // Second section if (i == 1 && ti.position.x > 0.0f && ti.position.x < 0.5f && ti.position.z >= 0.5f && ti.position.z <= 1.0f ) { // Recalculate new tree position ti.position = new Vector3((ti.position.x) * 2f, ti.position.y, (ti.position.z - 0.5f) * 2f); // Add tree instance genTer.AddTreeInstance(ti); } // Third section if (i == 2 && ti.position.x >= 0.5f && ti.position.x <= 1.0f && ti.position.z > 0.0f && ti.position.z < 0.5f ) { // Recalculate new tree position ti.position = new Vector3((ti.position.x - 0.5f) * 2f, ti.position.y, (ti.position.z) * 2f); // Add tree instance genTer.AddTreeInstance(ti); } // Fourth section if (i == 3 && ti.position.x >= 0.5f && ti.position.x <= 1.0f && ti.position.z >= 0.5f && ti.position.z <= 1.0f ) { // Recalculate new tree position ti.position = new Vector3((ti.position.x - 0.5f) * 2f, ti.position.y, (ti.position.z - 0.5f) * 2f); // Add tree instance genTer.AddTreeInstance(ti); } } #endregion AssetDatabase.SaveAssets(); } EditorUtility.ClearProgressBar(); }
void BuildTerrainData(TerrainData terrainData) { // Define the size of the arrays that Unity's terrain will // use internally to represent the terrain. Bigger numbers // mean more fine details. //if(CoRoutineShouldPause()) // yield return null; // "Heightmap Resolution": "Pixel resolution of the terrain’s heightmap (should be a power of two plus one, eg, 513 = 512 + 1)." // AFAIK, this defines the size of the 2-dimensional array that holds the information about the terrain (i.e. terrainData.GetHeights()) // Larger numbers lead to finer terrain details (if populated by a suitable source image heightmap). // As for actual physical size of the terrain (in Unity world space), this is defined as: // terrainData.Size = terrainData.heightmapScale * terrainData.heightmapResolution terrainData.heightmapResolution = 128 + 1; // "Base Texture Resolution": "Resolution of the composite texture used on the terrain when viewed from a distance greater than the Basemap Distance" // AFAIK, this doesn't affect the terrain mesh -- only how the terrain texture (i.e. Splats) are rendered terrainData.baseMapResolution = 512 + 1; // "Detail Resolution" and "Detail Resolution Per Patch" // (used for Details -- i.e. grass/flowers/etc...) terrainData.SetDetailResolution(1024, 32); // Set the Unity worldspace size of the terrain AFTER you set the resolution. // This effectively just sets terrainData.heightmapScale for you, depending on the value of terrainData.heightmapResolution terrainData.size = new Vector3(WorldUnitsPerChunk, TerrainHeight, WorldUnitsPerChunk); // Get the 2-dimensional array of floats that defines the actual height data for the terrain. // Each float has a value from 0..1, where a value of 1 means the maximum height of the terrain as defined by terrainData.size.y // // AFAIK, terrainData.heightmapWidth and terrainData.heightmapHeight will always be equal to terrainData.heightmapResolution // float[,] heights = terrainData.GetHeights(0, 0, terrainData.heightmapWidth, terrainData.heightmapHeight); float halfDegreesPerChunk = DegreesPerChunk / 2f; // Caching these dimensions and... int w = terrainData.heightmapWidth; int h = terrainData.heightmapHeight; // Replacing loop divisions with mults cuts this function by about 10% // -- Shout out to Karl Goodloe float widthAdjust = 1f / (w - 1f); float heightAdjust = 1f / (h - 1f); // Loop through each point in the terrainData heightmap. for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { // Normalize x and y to a value from 0..1 // NOTE: We are INVERTING the x and y because internally Unity does this float xPos = (float)x * widthAdjust; float yPos = (float)y * heightAdjust; // This converts our chunk position to a latitude/longitude, // which we can then use to get UV coordinates from the heightmap // FIXME: I think this is doing a pincushion effect // Someone smarter than me will have to figure this out. Quaternion pointRotation = ChunkRotation * Quaternion.Euler( xPos * DegreesPerChunk - halfDegreesPerChunk, yPos * DegreesPerChunk - halfDegreesPerChunk, 0 ); Vector2 uv = CoordHelper.RotationToUV(pointRotation); // Get the pixel from the heightmap image texture at the appropriate position Color pix = HeightMapTexture.GetPixelBilinear(uv.x, uv.y); // Update the heights array heights[x, y] = pix.grayscale / heightMapTextureScaling; } } // Update the terrain data based on our changed heights array terrainData.SetHeights(0, 0, heights); }
public override bool OnPaint(Terrain terrain, IOnPaint editContext) { if (m_TargetTerrain == null || selectedDetail == kInvalidDetail || selectedDetail >= m_TargetTerrain.terrainData.detailPrototypes.Length) { return(false); } Texture2D brush = editContext.brushTexture as Texture2D; if (brush == null) { Debug.LogError("Brush texture is not a Texture2D."); return(false); } if (m_BrushRep == null) { m_BrushRep = new DetailBrushRepresentation(); } PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv); for (int t = 0; t < ctx.neighborTerrains.Length; ++t) { Terrain ctxTerrain = ctx.neighborTerrains[t]; if (ctxTerrain != null) { int detailPrototype = PaintDetailsToolUtility.FindDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail); if (detailPrototype == kInvalidDetail) { detailPrototype = PaintDetailsToolUtility.CopyDetailPrototype(ctxTerrain, m_TargetTerrain, selectedDetail); } TerrainData terrainData = ctxTerrain.terrainData; TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrainData, "Terrain - Detail Edit"); int size = (int)Mathf.Max(1.0f, editContext.brushSize * ((float)terrainData.detailResolution / terrainData.size.x)); m_BrushRep.Update(brush, size); float targetStrength = m_DetailsStrength; if (Event.current.shift || Event.current.control) { targetStrength = -targetStrength; } DetailBrushBounds brushBounds = new DetailBrushBounds(terrainData, ctx, size, t); int[] layers = { detailPrototype }; if (targetStrength < 0.0F && !Event.current.control) { layers = terrainData.GetSupportedLayers(brushBounds.min, brushBounds.bounds.size); } for (int i = 0; i < layers.Length; i++) { int[,] alphamap = terrainData.GetDetailLayer(brushBounds.min, brushBounds.bounds.size, layers[i]); for (int y = 0; y < brushBounds.bounds.height; y++) { for (int x = 0; x < brushBounds.bounds.width; x++) { Vector2Int brushOffset = brushBounds.GetBrushOffset(x, y); float opa = detailOpacity * m_BrushRep.GetStrength(brushOffset.x, brushOffset.y); float targetValue = Mathf.Lerp(alphamap[y, x], targetStrength * terrainData.maxDetailScatterPerRes, opa); alphamap[y, x] = Mathf.Min(Mathf.RoundToInt(targetValue - .5f + Random.value), terrainData.maxDetailScatterPerRes); } } terrainData.SetDetailLayer(brushBounds.min, layers[i], alphamap); } } } return(false); }
private static void GenerateTrees() { Terrain t = Terrain.activeTerrain; TerrainData td = t.terrainData; TreePrototype[] treeprototypes = new TreePrototype[] { new TreePrototype() { prefab = BigTree }, new TreePrototype() { prefab = Tree } }; td.treePrototypes = treeprototypes; //float[, ,] splatmaps = td.GetAlphamaps(0, 0, td.alphamapWidth, td.alphamapHeight); td.treeInstances = new TreeInstance[0]; List <Vector3> treePos = new List <Vector3>(); print(td.alphamapWidth + "," + td.alphamapHeight); float[,] noisemap = new float[td.alphamapWidth, td.alphamapHeight]; Generator noise_tree = new Max( new PinkNoise((int)UnityEngine.Random.Range(0, int.MaxValue)) { Frequency = 0.01f, OctaveCount = 6, Persistence = 0.66f, Lacunarity = 0.1f }, new PinkNoise((int)UnityEngine.Random.Range(0, int.MaxValue)) { Frequency = 0.015f, OctaveCount = 2, Persistence = 0.66f, Lacunarity = 0.2f }); for (int ny = 0; ny < noisemap.GetLength(1); ny++) { for (int nx = 0; nx < noisemap.GetLength(0); nx++) { noisemap[nx, ny] = noise_tree.GetValue(nx, ny, 0); } } if (maxSteepness == 0) { maxSteepness = 70.0f; } if (waterLevel == 0) { waterLevel = 0.0f; } float x = 0.0f; while (x < td.alphamapWidth) { float y = 0.0f; while (y < td.alphamapHeight) { float height = td.GetHeight((int)x, (int)y); float heightScaled = height / td.size.y; float xScaled = (x + Random.Range(-1f, 1f)) / td.alphamapWidth; float yScaled = (y + Random.Range(-1f, 1f)) / td.alphamapHeight; float steepness = td.GetSteepness(xScaled, yScaled); if (Random.Range(0f, 1f) > 1f - noisemap[(int)x, (int)y] * 2f && steepness <maxSteepness && height> waterLevel) { treePos.Add(new Vector3(xScaled, heightScaled, yScaled)); } y++; } x++; } TreeInstance[] treeInstances = new TreeInstance[treePos.Count]; for (int ii = 0; ii < treeInstances.Length; ii++) { treeInstances[ii].position = treePos[ii]; treeInstances[ii].prototypeIndex = Random.Range(0, treeprototypes.Length); treeInstances[ii].color = Color.white;//new Color(Random.Range(200, 255), Random.Range(200, 255), Random.Range(200, 255)); treeInstances[ii].lightmapColor = Color.white; treeInstances[ii].heightScale = 1.0f + Random.Range(-0.25f, 0.5f); treeInstances[ii].widthScale = 1.0f + Random.Range(-0.5f, 0.25f); } td.treeInstances = treeInstances; }
public void LoadTerrain() { string fileName = "elevation.bhm"; using (FileStream stream = new FileStream(fileName, FileMode.Open)) { BinaryReader reader = new BinaryReader(stream); int width = reader.ReadInt32(); int height = reader.ReadInt32(); int[] intData = new int[width * height]; int minValue = Int32.MaxValue, maxValue = 0; for (int i = 0; i < width * height; i++) { intData[i] = reader.ReadInt32(); if (intData[i] < 0) { intData[i] = 0; } if (intData[i] > 0 && minValue > intData[i]) { minValue = intData[i]; } if (maxValue < intData[i]) { maxValue = intData[i]; } } for (int i = 0; i < width * height; i++) { if (intData[i] >= minValue) { intData[i] = intData[i] - minValue; } } maxValue = maxValue - minValue; float maxValueF = maxValue; int resolution = 2049; if (width < resolution) { resolution = width; } if (height < resolution) { resolution = height; } float[,] data = new float[resolution, resolution]; for (int y = 0; y < resolution; y++) { for (int x = 0; x < resolution; x++) { data[x, y] = intData[y * width + x] / maxValueF; } } TerrainData terrainData = new TerrainData(); terrainData.heightmapResolution = resolution; terrainData.SetHeights(0, 0, data); terrainData.size = new Vector3(1000, 100, 1000); GameObject terrain = Terrain.CreateTerrainGameObject(terrainData); Instantiate(terrain, Vector3.zero, Quaternion.identity); //Instantiate(terrain, new Vector3 (1000, 0, 0), Quaternion.identity); //Instantiate(terrain, new Vector3(1000, 0, 1000), Quaternion.identity); //Instantiate(terrain, new Vector3(0, 0, 1000), Quaternion.identity); } }
public void Start() { terrainData = Terrain.activeTerrain.terrainData; float[,,] splatmapData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers]; newHeightData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight]; ApplyPerlin(); RoughTerrain(); ApplyMountains(); ApplyHoles(); ApplyRiver(); for (int i = 0; i < smoothAmount; i++) { SmoothTerrain(); } terrainData.SetHeights(0, 0, newHeightData); for (int y = 0; y < terrainData.alphamapHeight; y++) { for (int x = 0; x < terrainData.alphamapWidth; x++) { float terrainHeight = terrainData.GetHeight(y, x); float[] splat = new float[splatHeights.Length]; for (int i = 0; i < splatHeights.Length; i++) { float thisNoise = map(Mathf.PerlinNoise(x * 0.05f, y * 0.05f), 0f, 1f, 0.5f, 1f); float thisHeightStart = splatHeights[i].startHeight * thisNoise - splatHeights[i].overlap * thisNoise; float nextHeightStart = 0; if (i != splatHeights.Length - 1) { nextHeightStart = splatHeights[i + 1].startHeight * thisNoise + splatHeights[i + 1].overlap * thisNoise; } if (i == splatHeights.Length - 1 && terrainHeight >= thisHeightStart) { splat[i] = 1; } else if (terrainHeight >= thisHeightStart && terrainHeight <= nextHeightStart) { splat[i] = 1; } } normalize(splat); for (int j = 0; j < splatHeights.Length; j++) { splatmapData[x, y, j] = splat[j]; } } } terrainData.SetAlphamaps(0, 0, splatmapData); }
public void Export() { GameObject TerrainGO = new GameObject(); string terrainName = TerrainGO.name; string FinalExpName = terrainName; int tCount; int counter; int totalCount; float progressUpdateInterval = 10000; /*建立路径 * if (!System.IO.Directory.Exists(T4MPrefabFolder + "Terrains/")) * { * System.IO.Directory.CreateDirectory(T4MPrefabFolder + "Terrains/"); * } * if (!System.IO.Directory.Exists(T4MPrefabFolder + "Terrains/Material/")) * { * System.IO.Directory.CreateDirectory(T4MPrefabFolder + "Terrains/Material/"); * } * if (!System.IO.Directory.Exists(T4MPrefabFolder + "Terrains/Texture/")) * { * System.IO.Directory.CreateDirectory(T4MPrefabFolder + "Terrains/Texture/"); * } * if (!System.IO.Directory.Exists(T4MPrefabFolder + "Terrains/Meshes/")) * { * System.IO.Directory.CreateDirectory(T4MPrefabFolder + "Terrains/Meshes/"); * }*/ AssetDatabase.Refresh(); TerrainData terrain = TerrainGO.GetComponent <Terrain>().terrainData; int w = terrain.heightmapWidth; int h = terrain.heightmapHeight; float tRes = w / 256; Vector3 meshScale = terrain.size; meshScale = new Vector3(meshScale.x / (h - 1) * tRes, meshScale.y, meshScale.z / (w - 1) * tRes); Vector2 uvScale = new Vector2((float)(1.0 / (w - 1)), (float)(1.0 / (h - 1))); float[,] tData = terrain.GetHeights(0, 0, w, h); w = (int)((w - 1) / tRes + 1); h = (int)((h - 1) / tRes + 1); Vector3[] tVertices = new Vector3[w * h]; Vector2[] tUV = new Vector2[w * h]; int[] tPolys = new int[(w - 1) * (h - 1) * 6]; int y = 0; int x = 0; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { //tVertices[y*w + x] = Vector3.Scale(meshScale, new Vector3(x, tData[(int)(x*tRes),(int)(y*tRes)], y)); tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(-y, tData[(int)(x * tRes), (int)(y * tRes)], x)); //Thank Cid Newman tUV[y * w + x] = Vector2.Scale(new Vector2(y * tRes, x * tRes), uvScale); } } y = 0; x = 0; int index = 0; for (y = 0; y < h - 1; y++) { for (x = 0; x < w - 1; x++) { tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = (y * w) + x + 1; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; } } bool ExportNameSuccess = false; int num = 1; string Next; do { Next = terrainName + num; if (!System.IO.File.Exists("Assets/RTSGameTools/TerrainData" + terrainName + ".prefab")) { FinalExpName = terrainName; ExportNameSuccess = true; } else if (!System.IO.File.Exists("Assets/RTSGameTools/TerrainData" + Next + ".prefab")) { FinalExpName = Next; ExportNameSuccess = true; } num++; } while (!ExportNameSuccess); //StreamWriter sw = new StreamWriter(T4MPrefabFolder+"Terrains/Meshes/"+FinalExpName+".obj"); StreamWriter sw = new StreamWriter(FinalExpName + ".obj"); try { sw.WriteLine("# T4M File"); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); counter = tCount = 0; totalCount = (int)((tVertices.Length * 2 + (tPolys.Length / 3)) / progressUpdateInterval); for (int i = 0; i < tVertices.Length; i++) { // UpdateProgress(); StringBuilder sb = new StringBuilder("v ", 20); sb.Append(tVertices[i].x.ToString()).Append(" "). Append(tVertices[i].y.ToString()).Append(" "). Append(tVertices[i].z.ToString()); sw.WriteLine(sb); } for (int i = 0; i < tUV.Length; i++) { // UpdateProgress(); StringBuilder sb = new StringBuilder("vt ", 22); sb.Append(tUV[i].x.ToString()).Append(" "). Append(tUV[i].y.ToString()); sw.WriteLine(sb); } for (int i = 0; i < tPolys.Length; i += 3) { // UpdateProgress(); StringBuilder sb = new StringBuilder("f ", 43); sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" "). Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" "). Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1); sw.WriteLine(sb); } } catch (Exception err) { Debug.Log("Error saving file: " + err.Message); } sw.Close(); AssetDatabase.SaveAssets(); //UpdateProgress(); /* ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// * * //Deplacement de l'obj dans les repertoire mesh * FileUtil.CopyFileOrDirectory(FinalExpName + ".obj", T4MPrefabFolder + "Terrains/Meshes/" + FinalExpName + ".obj"); * FileUtil.DeleteFileOrDirectory(FinalExpName + ".obj"); * * * * //Force Update * AssetDatabase.ImportAsset(T4MPrefabFolder + "Terrains/Meshes/" + FinalExpName + ".obj", ImportAssetOptions.ForceUpdate); * * UpdateProgress(); * * //Instance du T4M * GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(T4MPrefabFolder + "Terrains/Meshes/" + FinalExpName + ".obj", typeof(GameObject)); * * AssetDatabase.Refresh(); * * * GameObject forRotate = (GameObject)Instantiate(prefab, TerrainGO.transform.position, Quaternion.identity) as GameObject; * Transform childCheck = forRotate.transform.Find("default"); * Child = childCheck.gameObject; * forRotate.transform.DetachChildren(); * DestroyImmediate(forRotate); * Child.name = FinalExpName; * Child.AddComponent<T4MObjSC>(); * //Child.transform.rotation= Quaternion.Euler(0, 90, 0); * * UpdateProgress(); * * //Application des Parametres sur le Script * Child.GetComponent<T4MObjSC>().T4MMaterial = Tmaterial; * Child.GetComponent<T4MObjSC>().ConvertType = "UT"; * * //Regalges Divers * vertexInfo = 0; * partofT4MObj = 0; * trisInfo = 0; * int countchild = Child.transform.childCount; * if (countchild > 0) * { * Renderer[] T4MOBJPART = Child.GetComponentsInChildren<Renderer>(); * for (int i = 0; i < T4MOBJPART.Length; i++) * { * if (!T4MOBJPART[i].gameObject.AddComponent<MeshCollider>()) * T4MOBJPART[i].gameObject.AddComponent<MeshCollider>(); * T4MOBJPART[i].gameObject.isStatic = true; * T4MOBJPART[i].material = Tmaterial; * T4MOBJPART[i].gameObject.layer = 30; * T4MOBJPART[i].gameObject.AddComponent<T4MPartSC>(); * Child.GetComponent<T4MObjSC>().T4MMesh = T4MOBJPART[0].GetComponent<MeshFilter>(); * partofT4MObj += 1; * vertexInfo += T4MOBJPART[i].gameObject.GetComponent<MeshFilter>().sharedMesh.vertexCount; * trisInfo += T4MOBJPART[i].gameObject.GetComponent<MeshFilter>().sharedMesh.triangles.Length / 3; * } * } * else * { * Child.AddComponent<MeshCollider>(); * Child.isStatic = true; * Child.GetComponent<Renderer>().material = Tmaterial; * Child.layer = 30; * vertexInfo += Child.GetComponent<MeshFilter>().sharedMesh.vertexCount; * trisInfo += Child.GetComponent<MeshFilter>().sharedMesh.triangles.Length / 3; * partofT4MObj += 1; * } * * UpdateProgress(); * * * GameObject BasePrefab2 = PrefabUtility.CreatePrefab(T4MPrefabFolder + "Terrains/" + FinalExpName + ".prefab", Child); * AssetDatabase.ImportAsset(T4MPrefabFolder + "Terrains/" + FinalExpName + ".prefab", ImportAssetOptions.ForceUpdate); * GameObject forRotate2 = (GameObject)PrefabUtility.InstantiatePrefab(BasePrefab2) as GameObject; * * DestroyImmediate(Child.gameObject); * * Child = forRotate2.gameObject; * * TerrainGO.GetComponent<Terrain>().enabled = false; * * EditorUtility.SetSelectedWireframeHidden(Child.GetComponent<Renderer>(), true); * * UnityTerrain = TerrainGO.gameObject; * * EditorUtility.ClearProgressBar(); * * AssetDatabase.DeleteAsset(T4MPrefabFolder + "Terrains/Meshes/Materials"); * terrainName = ""; * AssetDatabase.StartAssetEditing(); * //Modification des attribut du mesh avant de le pr茅fabriquer * ModelImporter OBJI = ModelImporter.GetAtPath(T4MPrefabFolder + "Terrains/Meshes/" + FinalExpName + ".obj") as ModelImporter; * OBJI.globalScale = 1; * OBJI.splitTangentsAcrossSeams = true; * OBJI.normalImportMode = ModelImporterTangentSpaceMode.Calculate; * OBJI.tangentImportMode = ModelImporterTangentSpaceMode.Calculate; * OBJI.generateAnimations = ModelImporterGenerateAnimations.None; * OBJI.meshCompression = ModelImporterMeshCompression.Off; * OBJI.normalSmoothingAngle = 180f; * //AssetDatabase.ImportAsset (T4MPrefabFolder+"Terrains/Meshes/"+FinalExpName+".obj", ImportAssetOptions.TryFastReimportFromMetaData); * AssetDatabase.ImportAsset(T4MPrefabFolder + "Terrains/Meshes/" + FinalExpName + ".obj", ImportAssetOptions.ForceSynchronousImport); * AssetDatabase.StopAssetEditing(); * PrefabUtility.ResetToPrefabState(Child); * * *////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }