private void OnGUI() { if (!terrainEdit) { terrainEdit = Resources.Load <ComputeShader>("TerrainEdit"); } terrainData = (MTerrainData)EditorGUILayout.ObjectField("Terrain Data", terrainData, typeof(MTerrainData), false); if (!terrainData) { return; } chunkPosition = EditorGUILayout.Vector2IntField("Chunk Position", new Vector2Int(chunkPosition.x, chunkPosition.y)); heightTexture = EditorGUILayout.ObjectField("Height Texture", heightTexture, typeof(Texture), false) as Texture; targetChunkCount = EditorGUILayout.IntField("Chunk Count", targetChunkCount); targetChunkCount = max(0, targetChunkCount); int largestChunkCount = (int)(pow(2.0, terrainData.GetLodOffset()) + 0.1); if (GUILayout.Button("Update Height Texture")) { VirtualTextureLoader loader = new VirtualTextureLoader( terrainData.heightmapPath, terrainEdit, largestChunkCount, MTerrain.MASK_RESOLUTION, true, null); RenderTexture cacheRt = new RenderTexture(new RenderTextureDescriptor { width = MTerrain.MASK_RESOLUTION, height = MTerrain.MASK_RESOLUTION, volumeDepth = 1, dimension = UnityEngine.Rendering.TextureDimension.Tex2DArray, msaaSamples = 1, graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat, enableRandomWrite = true }); cacheRt.Create(); int mipLevel = 0; int meshResolution = terrainData.GetMeshResolution(); int saveMipLevel = 0; ComputeBuffer cb = new ComputeBuffer(meshResolution * meshResolution, sizeof(float2)); float2[] resultArr = new float2[meshResolution * meshResolution]; RenderTexture mipRT = new RenderTexture(MTerrain.MASK_RESOLUTION, MTerrain.MASK_RESOLUTION, 0, UnityEngine.Experimental.Rendering.GraphicsFormat.R32G32_SFloat, mipLevel); mipRT.enableRandomWrite = true; mipRT.useMipMap = true; mipRT.autoGenerateMips = false; mipRT.Create(); System.IO.FileStream fsm = new System.IO.FileStream(terrainData.boundPath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite); for (int i = MTerrain.MASK_RESOLUTION; i > 0; i /= 2) { mipLevel++; if (i <= meshResolution) { saveMipLevel++; } } MTerrainBoundingTree btree = new MTerrainBoundingTree(saveMipLevel); for (int x = 0; x < targetChunkCount; ++x) { for (int y = 0; y < targetChunkCount; ++y) { int2 pos = int2(x, y) + int2(chunkPosition.x, chunkPosition.y); if (pos.x >= largestChunkCount || pos.y >= largestChunkCount) { continue; } terrainEdit.SetTexture(6, ShaderIDs._SourceTex, heightTexture); terrainEdit.SetTexture(6, ShaderIDs._DestTex, cacheRt); terrainEdit.SetInt(ShaderIDs._Count, MTerrain.MASK_RESOLUTION); terrainEdit.SetInt(ShaderIDs._OffsetIndex, 0); terrainEdit.SetVector("_ScaleOffset", float4(float2(1.0 / targetChunkCount), float2(x, y) / targetChunkCount)); const int disp = MTerrain.MASK_RESOLUTION / 16; terrainEdit.Dispatch(6, disp, disp, 1); loader.WriteToDisk(cacheRt, 0, pos); for (int i = 0, res = MTerrain.MASK_RESOLUTION; i < mipLevel; ++i, res /= 2) { int pass; if (i == 0) { pass = 7; terrainEdit.SetTexture(pass, "_SourceArray", cacheRt); terrainEdit.SetTexture(pass, "_Mip1", mipRT); } else { if (res <= meshResolution) { pass = 9; terrainEdit.SetBuffer(pass, "_DataBuffer", cb); } else { pass = 8; } terrainEdit.SetTexture(pass, "_Mip0", mipRT, i - 1); terrainEdit.SetTexture(pass, "_Mip1", mipRT, i); } terrainEdit.SetInt(ShaderIDs._Count, res); int mipdisp = Mathf.CeilToInt(res / 16f); terrainEdit.Dispatch(pass, mipdisp, mipdisp, 1); if (pass == 9) { cb.GetData(resultArr, 0, 0, res * res); int targetMipLevel = mipLevel - 1 - i; for (int xx = 0; xx < res * res; ++xx) { btree[xx, targetMipLevel] = resultArr[xx]; } } } btree.WriteToDisk(fsm, x + y * largestChunkCount); } } btree.Dispose(); cacheRt.Release(); cb.Dispose(); mipRT.Release(); loader.Dispose(); fsm.Dispose(); Debug.Log("Finish!"); } maskTexture = EditorGUILayout.ObjectField("Mask Texture", maskTexture, typeof(Texture), false) as Texture; void SaveToMask(RenderTexture cacheRt) { VirtualTextureLoader loader = new VirtualTextureLoader( terrainData.maskmapPath, terrainEdit, largestChunkCount, MTerrain.MASK_RESOLUTION, false, null); for (int x = 0; x < targetChunkCount; ++x) { for (int y = 0; y < targetChunkCount; ++y) { int2 pos = int2(x, y) + int2(chunkPosition.x, chunkPosition.y); if (pos.x >= largestChunkCount || pos.y >= largestChunkCount) { continue; } terrainEdit.SetTexture(6, ShaderIDs._SourceTex, maskTexture); terrainEdit.SetTexture(6, ShaderIDs._DestTex, cacheRt); terrainEdit.SetInt(ShaderIDs._Count, MTerrain.MASK_RESOLUTION); terrainEdit.SetInt(ShaderIDs._OffsetIndex, 0); terrainEdit.SetVector("_ScaleOffset", float4(float2(1.0 / targetChunkCount), float2(x, y) / targetChunkCount)); const int disp = MTerrain.MASK_RESOLUTION / 16; terrainEdit.Dispatch(6, disp, disp, 1); loader.WriteToDisk(cacheRt, 0, pos); } } loader.Dispose(); } if (GUILayout.Button("Update Mask Texture")) { RenderTexture cacheRt = new RenderTexture(new RenderTextureDescriptor { width = MTerrain.MASK_RESOLUTION, height = MTerrain.MASK_RESOLUTION, volumeDepth = 1, dimension = UnityEngine.Rendering.TextureDimension.Tex2DArray, msaaSamples = 1, graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat, enableRandomWrite = true }); cacheRt.Create(); SaveToMask(cacheRt); cacheRt.Release(); } }
private void OnGUI() { terrainData = (MTerrainData)EditorGUILayout.ObjectField("Terrain Data", terrainData, typeof(MTerrainData), false); chunkPosition = EditorGUILayout.Vector2IntField("Chunk Position", new Vector2Int(chunkPosition.x, chunkPosition.y)); chunkSize = EditorGUILayout.IntField("Chunk Size", chunkSize); chunkSize = max(1, chunkSize); maskTexture = EditorGUILayout.ObjectField("Mask Texture", maskTexture, typeof(Texture), false) as Texture; heightTexture = EditorGUILayout.ObjectField("Height Texture", heightTexture, typeof(Texture), false) as Texture; if (!terrainData) { return; } if (GUILayout.Button("Update Height Mask Texture")) { TerrainFactory factory = new TerrainFactory(terrainData.lodDistances.Length - terrainData.renderingLevelCount, terrainData.lodDistances.Length, terrainData.readWritePath); try { int resolution = (int)(0.1 + pow(2.0, terrainData.renderingLevelCount)); for (int x = 0; x < chunkSize; ++x) { for (int y = 0; y < chunkSize; ++y) { int2 currentPos = int2(x + chunkPosition.x, y + chunkPosition.y); if (currentPos.x > resolution || currentPos.y > resolution) { continue; } factory.BlitMask(currentPos, terrainData.lodDistances.Length - 1, maskTexture, 1f / chunkSize, float2(x, y) / chunkSize); factory.BlitHeight(currentPos, terrainData.lodDistances.Length - 1, heightTexture, 1f / chunkSize, float2(x, y) / chunkSize); } } } finally { factory.Dispose(); } } if (GUILayout.Button("Generate Mipmap")) { TerrainFactory factory = new TerrainFactory(terrainData.lodDistances.Length - terrainData.renderingLevelCount, terrainData.lodDistances.Length, terrainData.readWritePath); try { for (int i = terrainData.lodDistances.Length - 2; i >= terrainData.lodDistances.Length - terrainData.renderingLevelCount; --i) { int resolution = (int)(0.1 + pow(2.0, i)); for (int x = 0; x < resolution; ++x) { for (int y = 0; y < resolution; ++y) { factory.GenerateMaskMip(int2(x, y), i); factory.GenerateHeightMip(int2(x, y), i); } } } } finally { factory.Dispose(); } } }