public static string GetBitDepth(Heightmap.Depth depth) { switch (depth) { case Heightmap.Depth.Bit16: return("16 bit"); case Heightmap.Depth.Bit8: return("8 bit"); default: return("8 bit"); } }
public static void ExportTerrainHeightsToRawFile(TerrainData terrainData, string path, Heightmap.Depth depth, bool flipVertical, ByteOrder byteOrder, Vector2 inputLevelsRange) { // trim off the extra 1 pixel, so we get a power of two sized texture #if UNITY_2019_3_OR_NEWER int heightmapWidth = terrainData.heightmapResolution - 1; int heightmapHeight = terrainData.heightmapResolution - 1; #else int heightmapWidth = terrainData.heightmapWidth - 1; int heightmapHeight = terrainData.heightmapHeight - 1; #endif float[,] heights = terrainData.GetHeights(0, 0, heightmapWidth, heightmapHeight); byte[] data = new byte[heightmapWidth * heightmapHeight * (int)depth]; if (depth == Heightmap.Depth.Bit16) { float normalize = (1 << 16); for (int y = 0; y < heightmapHeight; ++y) { for (int x = 0; x < heightmapWidth; ++x) { int index = x + y * heightmapWidth; int srcY = flipVertical ? heightmapHeight - 1 - y : y; float remappedHeight = (heights[srcY, x] - inputLevelsRange.x) / (inputLevelsRange.y - inputLevelsRange.x); int height = Mathf.RoundToInt(remappedHeight * normalize); ushort compressedHeight = (ushort)Mathf.Clamp(height, 0, ushort.MaxValue); byte[] byteData = System.BitConverter.GetBytes(compressedHeight); if ((byteOrder == ByteOrder.Mac) == System.BitConverter.IsLittleEndian) { data[index * 2 + 0] = byteData[1]; data[index * 2 + 1] = byteData[0]; } else { data[index * 2 + 0] = byteData[0]; data[index * 2 + 1] = byteData[1]; } } } } else { float normalize = (1 << 8); for (int y = 0; y < heightmapHeight; ++y) { for (int x = 0; x < heightmapWidth; ++x) { int index = x + y * heightmapWidth; int srcY = flipVertical ? heightmapHeight - 1 - y : y; int height = Mathf.RoundToInt(heights[srcY, x] * normalize); byte compressedHeight = (byte)Mathf.Clamp(height, 0, byte.MaxValue); data[index] = compressedHeight; } } } FileStream fs = new FileStream((path + ".raw"), FileMode.Create); fs.Write(data, 0, data.Length); fs.Close(); }
/// <summary> /// This overloaded method deals specifically with testing the level correction of the raw format /// </summary> /// <param name="toolboxWindow">Window where the Export Heightmap Utilities live</param> /// <param name="minMaxRemap">Min and Max values of the remap</param> /// <param name="format">Heightmap File Format</param> /// <param name="path">String path of the files directory location</param> /// <param name="depth">Heightmap Bit Depth</param> /// <returns></returns> bool TestLevelCorrection(TerrainToolboxWindow toolboxWindow, Vector2 minMaxRemap, string path, Heightmap.Depth depth) { //Execute the repro steps in code toolboxWindow.m_TerrainUtilitiesMode.m_Settings.ExportHeightRemapMin = minMaxRemap.x; toolboxWindow.m_TerrainUtilitiesMode.m_Settings.ExportHeightRemapMax = minMaxRemap.y; toolboxWindow.m_TerrainUtilitiesMode.m_Settings.HeightFormat = Heightmap.Format.RAW; toolboxWindow.m_TerrainUtilitiesMode.m_Settings.HeightmapDepth = depth; toolboxWindow.m_TerrainUtilitiesMode.m_SelectedDepth = (depth == Heightmap.Depth.Bit16) ? 0 : 1; toolboxWindow.m_TerrainUtilitiesMode.ExportHeightmaps(new Object[] { m_TerrainComponent }); //Get byte data of the terrain's heightmap TerrainData terrainData = m_TerrainComponent.terrainData; #if UNITY_2019_3_OR_NEWER int heightmapWidth = terrainData.heightmapResolution - 1; int heightmapHeight = terrainData.heightmapResolution - 1; #else int heightmapWidth = terrainData.heightmapWidth - 1; int heightmapHeight = terrainData.heightmapHeight - 1; #endif float[,] heights = terrainData.GetHeights(0, 0, heightmapWidth, heightmapHeight); byte[] data = new byte[heightmapWidth * heightmapHeight * (int)depth]; if (depth == Heightmap.Depth.Bit16) { float normalize = (1 << 16); for (int y = 0; y < heightmapHeight; ++y) { for (int x = 0; x < heightmapWidth; ++x) { //Remapping the heightmap data int index = x + y * heightmapWidth; float remappedHeight = heights[y, x] * (minMaxRemap.y - minMaxRemap.x) + minMaxRemap.x; int height = Mathf.RoundToInt(remappedHeight * normalize); ushort compressedHeight = (ushort)Mathf.Clamp(height, 0, ushort.MaxValue); byte[] byteData = System.BitConverter.GetBytes(compressedHeight); if ((toolboxWindow.m_TerrainUtilitiesMode.m_Settings.HeightmapByteOrder == ToolboxHelper.ByteOrder.Mac) == System.BitConverter.IsLittleEndian) { data[index * 2 + 0] = byteData[1]; data[index * 2 + 1] = byteData[0]; } else { data[index * 2 + 0] = byteData[0]; data[index * 2 + 1] = byteData[1]; } } } } else { float normalize = (1 << 8); for (int y = 0; y < heightmapHeight; ++y) { for (int x = 0; x < heightmapWidth; ++x) { //Remapping the heightmap data int index = x + y * heightmapWidth; float remappedHeight = heights[y, x] * (minMaxRemap.y - minMaxRemap.x) + minMaxRemap.x; int height = Mathf.RoundToInt(remappedHeight * normalize); byte compressedHeight = (byte)Mathf.Clamp(height, 0, byte.MaxValue); data[index] = compressedHeight; } } } //Compare both the original and regression test data byte[] rawByteData = File.ReadAllBytes(path); return(data.SequenceEqual(rawByteData)); }
public void TerrainToolboxUtilites_WhenExportHeightmap_LevelCorrectionWorks(float min, float max, Heightmap.Format format, Heightmap.Depth depth = Heightmap.Depth.Bit16) { TerrainToolboxWindow toolboxWindow = EditorWindow.GetWindow(typeof(TerrainToolboxWindow)) as TerrainToolboxWindow; Texture2D gradientTexture = CreateGradientTexture(); int heightmapResolution = 513; int numberOfTiles = 1; int baseLevel = 0; int remapLevel = 1; ToolboxHelper.CopyTextureToTerrainHeight(m_TerrainComponent.terrainData, gradientTexture, Vector2Int.zero, heightmapResolution, numberOfTiles, baseLevel, remapLevel); Selection.activeGameObject = m_TerrainGO; m_TerrainGO.name = "TestTerrain"; m_TerrainComponent.name = "TestComponent"; RenderTexture oldRT = RenderTexture.active; RenderTexture.active = m_TerrainComponent.terrainData.heightmapTexture; //Run Tests and Cleanup files string fileName = m_TerrainGO.name + "_heightmap"; string path = Path.Combine(toolboxWindow.m_TerrainUtilitiesMode.m_Settings.HeightmapFolderPath, fileName); switch (format) { case Heightmap.Format.PNG: path += ".png"; Assert.IsTrue(TestLevelCorrection(toolboxWindow, new Vector2(min, max), path, format)); FileUtil.DeleteFileOrDirectory(path); FileUtil.DeleteFileOrDirectory(path + ".meta"); break; case Heightmap.Format.TGA: path += ".tga"; Assert.IsTrue(TestLevelCorrection(toolboxWindow, new Vector2(min, max), path, format)); FileUtil.DeleteFileOrDirectory(path); FileUtil.DeleteFileOrDirectory(path + ".meta"); break; case Heightmap.Format.RAW: path += ".raw"; Assert.IsTrue(TestLevelCorrection(toolboxWindow, new Vector2(min, max), path, depth)); FileUtil.DeleteFileOrDirectory(path); FileUtil.DeleteFileOrDirectory(path + ".meta"); break; } AssetDatabase.Refresh(); RenderTexture.active = oldRT; toolboxWindow.Close(); }