I’m building a script to create terrains based on L3DT’s exported mosaic tiles and i’m to the point where it reads the information and creates the assets but now I am stuck on actually importing the height map onto the terrain asset. I’ve been all over and I see the ways to generate one procedurally but thats not what I want to do I want to apply an already created height map.
Is there something I am missing? I know the option is up there on the Toolbar so it must exist i just cannot find the method in the docs.
Use Texture2D to import the image if it is 8bits per channel. THen use GetPixels to create a float array from the image and apply that to the heightfield using TerrainData.SetHeights()
If you are using 16bits per channel data you can write your own RAW importer. There is an example out there somwhere. Or encode 8bits in red and 8 bits in green.
Got it working finally but for some reason the heightmap is being applied reverse so instead of the tiles being placed in the positive locations they are going negative on the Z axes.
Doesnt do that when I use the import raw map via the gui … wonder why I am missing …
The heightfield texture X maps to world Z and texture Y maps to world Z. Not sure f this is relevant to your problem or not though.
Also, check TerrainData.size and make sure it’s Z component is positive:
Here is a class I wrote for decoding from .RAW (16bit)… This is assuming you have already got the byte-array from a .RAW file, and that you know whether it is big-endian (MAC) or “little-endian” (IBM). I may have those mixed up.
It uses a pre-generated height-table to speed things up. This class doesn’t cover actually creating the terrain using scripting. I have separated it like this so I can generate the height values in a background thread.
public class TerrainMaker
{
static public float[] heightTable;
static public void GenerateHeightTable()
{
heightTable = new float[65536];
for (int i = 0; i < 65536; i++)
{
heightTable[i] = i / 65535f;
}
}
static public float[,] GetHeights(byte[] bytes, bool isLittleEndian)
{
if (heightTable == null)
{
GenerateHeightTable();
}
int w = Mathf.RoundToInt(Mathf.Sqrt(bytes.Length / 2)); //assumes your image is square
float[,] heights = new float[w, w];
int i = 0;
if (isLittleEndian == BitConverter.IsLittleEndian)
{
for (int y = 0; y < w; y++)
{
for (int x = 0; x < w; x++)
{
heights[x, y] = heightTable[BitConverter.ToUInt16(bytes, i)];
i += 2;
}
}
}
else
{
byte[] bigEndBytes = new byte[2];
for (int y = 0; y < w; y++)
{
for (int x = 0; x < w; x++)
{
bigEndBytes[0] = bytes[i + 1];
bigEndBytes[1] = bytes[i];
heights[x, y] = heightTable[BitConverter.ToUInt16(bigEndBytes, 0)];
i += 2;
}
}
}
return heights;
}
}