- Home /
Bake terrain normal via script
I am Interested in exporting my Unity terrain height data into a normal map via script within Unity, I not a programmer, so this is pretty much black magic to me, but I am not 100% useless.
This is a free script I have laying around which does exactly what I want, however it is intended for mesh terrain.
protected override void CreateMap(float[] heights, int width, int height)
{
float ux = 1.0f / (width - 1.0f);
float uy = 1.0f / (height - 1.0f);
float scaleX = m_terrainHeight / m_terrainWidth;
float scaleY = m_terrainHeight / m_terrainLength;
Texture2D normalMap = new Texture2D(width, height, TextureFormat.ARGB32, false, true);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int xp1 = (x == width - 1) ? x : x + 1;
int xn1 = (x == 0) ? x : x - 1;
int yp1 = (y == height - 1) ? y : y + 1;
int yn1 = (y == 0) ? y : y - 1;
float l = heights[xn1 + y * width] * scaleX;
float r = heights[xp1 + y * width] * scaleX;
float b = heights[x + yn1 * width] * scaleY;
float t = heights[x + yp1 * width] * scaleY;
float dx = (r - l) / (2.0f * ux);
float dy = (t - b) / (2.0f * uy);
Vector3 normal;
normal.x = -dx;
normal.y = -dy; //you might need to flip y
normal.z = 1;
normal.Normalize();
Color pixel;
pixel.r = normal.x * 0.5f + 0.5f;
pixel.g = normal.y * 0.5f + 0.5f;
pixel.b = normal.z;
pixel.a = 1.0f;
normalMap.SetPixel(x, y, pixel);
}
}
normalMap.Apply();
m_material.mainTexture = normalMap;
}
}
I believe the key height data here is "heights" which is a float array from the heightmap on the mesh terrain, here is what the above script derives from.
void Start()
{
if (m_material == null) return;
string fileName = Application.dataPath + "/TerrainTopology/Heights.raw";
float[] heights = Load16Bit(fileName);
int width = 1024;
int height = 1024;
CreateMap(heights, width, height);
}
void OnDestroy()
{
if (m_material == null) return;
m_material.mainTexture = null;
}
protected abstract void CreateMap(float[] heights, int width, int height);
protected float[] Load16Bit(string fileName, bool bigendian = false)
{
byte[] bytes = System.IO.File.ReadAllBytes(fileName);
int size = bytes.Length / 2;
float[] data = new float[size];
for (int x = 0, i = 0; x < size; x++)
{
data[x] = (bigendian) ? (bytes[i++] * 256.0f + bytes[i++]) : (bytes[i++] + bytes[i++] * 256.0f);
data[x] /= ushort.MaxValue;
}
return data;
So, I am wondering if anyone knows how this could be converted to take the heightmap from a Unity Terrain instead of a mesh terrain. I assumed I would be able to do something like, heights = myTerrain.terrainData.GetHeights; However that is a nested [,] float, which I have no clue how to make work with the above set up.
Worth noting the only goal here is to do it within Unity via script using a similar method to the above, I am aware I could export the heightmap to a third party program and generate it there.
Any tips from you programming experts would be amazingly helpful!!
Thanks in advance
Your answer
![](https://koobas.hobune.stream/wayback/20220612212629im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
copy smaller size terrain's data, and seet the heights on bigger Terrain at click position 0 Answers
How to generate multiple Terrain objects with different TerrainData and Splat Texture via C# script? 1 Answer
Problem with blending two terrains together on an edge. 1 Answer