Heightmap From Texture - Script Converter
Hello everyone!
Soo, i was trying to convert this script, that was in JavaScript to C#
So far, i "accomplished" that, but even if the script wasn't reporting any compile erros, it won't work!
And by the way, this script is supposed to take a Texture2D and apply into the terrain HeightMap.
Thanks :)
link: Original Script
My "Converted" Script:
static void ApplyHeightmap(int index)
{
var heightmap = heightMap[index];
var terrain = Terrain.activeTerrain.terrainData;
var w = heightmap.width;
var h = heightmap.height;
var w2 = terrain.heightmapWidth;
var heightmapData = terrain.GetHeights(0, 0, w2, w2);
var mapColors = heightmap.GetPixels();
var map = new Color[w2 * w2];
if (w2 != w || h != w)
{
// Resize using nearest-neighbor scaling if texture has no filtering
if (heightmap.filterMode == FilterMode.Point)
{
var dx = w / w2;
var dy = h / w2;
for (int y = 0; y < w2; y++)
{
var thisY = dy * y * w;
var yw = y * w2;
for (int x = 0; x < w2; x++)
{
map[yw + x] = mapColors[thisY + dx * x];
}
}
}
// Otherwise resize using bilinear filtering
else
{
var ratioX = 1.0f / w2 / (w - 1);
var ratioY = 1.0f / w2 / (h - 1);
for (int y = 0; y < w2; y++)
{
var yy = Mathf.Floor(y * ratioY);
var y1 = yy * w;
var y2 = (yy + 1) * w;
var yw = y * w2;
for (int x = 0; x < w2; x++)
{
var xx = Mathf.Floor(x * ratioX);
int temp_integer = (int)y1;
temp_integer += (int)xx;
var bl = mapColors[temp_integer];
temp_integer = (int)y1;
temp_integer += ((int)xx) + 1;
var br = mapColors[temp_integer];
temp_integer = (int)y2;
temp_integer += ((int)xx);
var tl = mapColors[temp_integer];
temp_integer = (int)y2;
temp_integer += ((int)xx) + 1;
var tr = mapColors[temp_integer];
var xLerp = x * ratioX - xx;
map[yw + x] = Color.Lerp(Color.Lerp(bl, br, xLerp), Color.Lerp(tl, tr, xLerp), y * ratioY - yy);
}
}
}
}
else
{
// Use original if no resize is needed
map = mapColors;
}
// Assign texture data to heightmap
for (int y = 0; y < w2; y++)
{
for (int x = 0; x < w2; x++)
{
heightmapData[y, x] = map[y * w2 + x].grayscale;
}
}
terrain.SetHeights(0, 0, heightmapData);
}
Answer by Oriles · Oct 19, 2017 at 12:06 AM
After some fiddling I finally found the cause... It was some journey, let me tell you... After debugging I found that it was applying same grayscale (line 77) through out the whole terrain. So obviously there was some problem with rounding.
The Java is very forgiving in this it seems. I've replaced whole code to strict type (var => int, float, etc....), that gave me errors about not compatible types, which needed to be resolved. After that I've replaced all your integer shenanigans with FloorToInt methods, which led to fixing the FilterMode.Point path, but not bilinear filtering. But then... then I could't believe my eyes. Do you know why there is this whole problem?
This:
var ratioX = 1.0f / w2 / (w - 1);
var ratioY = 1.0f / w2 / (h - 1);
I did't go deep into this, but in Java the
w2 and w - 1 have priority. In C# not.
if you do this:
float ratioX = 1.0f / ((float) w2 / (w - 1));
float ratioY = 1.0f / ((float) w2 / (h - 1));
It does NOT work :D it is still not enough. You have to do this:
float ratioX = (1.0f / ((float) w2 / (w - 1)));
float ratioY = (1.0f / ((float) w2 / (h - 1)));
Well without further ado, here is the final script in C#:
using System.IO;
using UnityEditor;
using UnityEngine;
public static class HeightmapFromTexture
{
[MenuItem("Terrain/Heightmap From Texture")]
static void ApplyHeightmap()
{
//string heightmapPath = EditorUtility.OpenFilePanel("Texture", GetFolderPath(SpecialFolder.Desktop), ".png");
Texture2D heightmap = Selection.activeObject as Texture2D;
if (heightmap == null)
{
EditorUtility.DisplayDialog("No texture selected", "Please select a texture.", "Cancel");
return;
}
var terrain = Terrain.activeTerrain.terrainData;
int w = heightmap.width;
int h = heightmap.height;
int w2 = terrain.heightmapWidth;
float[,] heightmapData = terrain.GetHeights(0, 0, w2, w2);
Color[] mapColors = heightmap.GetPixels();
Color[] map = new Color[w2 * w2];
if (w2 != w || h != w)
{
// Resize using nearest-neighbor scaling if texture has no filtering
if (heightmap.filterMode == FilterMode.Point)
{
float dx = (float) w / (float) w2;
float dy = (float) h / (float) w2;
for (int y = 0; y < w2; y++)
{
if (y % 20 == 0)
{
EditorUtility.DisplayProgressBar("Resize", "Calculating texture", Mathf.InverseLerp(0.0f, w2, y));
}
int thisY = Mathf.FloorToInt(dy * y) * w;
int yw = y * w2;
for (int x = 0; x < w2; x++)
{
map[yw + x] = mapColors[Mathf.FloorToInt(thisY + dx * x)];
}
}
}
// Otherwise resize using bilinear filtering
else
{
float ratioX = (1.0f / ((float) w2 / (w - 1)));
float ratioY = (1.0f / ((float) w2 / (h - 1)));
for (int y = 0; y < w2; y++)
{
if (y % 20 == 0)
{
EditorUtility.DisplayProgressBar("Resize", "Calculating texture", Mathf.InverseLerp(0.0f, w2, y));
}
int yy = Mathf.FloorToInt(y * ratioY);
int y1 = yy * w;
int y2 = (yy + 1) * w;
int yw = y * w2;
for (int x = 0; x < w2; x++)
{
int xx = Mathf.FloorToInt(x * ratioX);
Color bl = mapColors[y1 + xx];
Color br = mapColors[y1 + xx + 1];
Color tl = mapColors[y2 + xx];
Color tr = mapColors[y2 + xx + 1];
float xLerp = x * ratioX - xx;
map[yw + x] = Color.Lerp(Color.Lerp(bl, br, xLerp), Color.Lerp(tl, tr, xLerp), y * ratioY - (float)yy);
}
}
}
EditorUtility.ClearProgressBar();
}
else
{
// Use original if no resize is needed
map = mapColors;
}
// Assign texture data to heightmap
for (int y = 0; y < w2; y++)
{
for (int x = 0; x < w2; x++)
{
heightmapData[y, x] = map[y * w2 + x].grayscale;
}
}
terrain.SetHeights(0, 0, heightmapData);
}
}
Happy coding @lesmasamuray
Your answer
Follow this Question
Related Questions
Convert Java to C# 2 Answers
Can someone help me please? 0 Answers
change my code from java to c# 1 Answer
JavaScript to C# 1 Answer
Convert Java to C# 1 Answer