I have come across this nice bit of code on gamedev.net forums. Which i think will come in handy for a loads of people as i cant seem to find alot of examples of generating normal maps from heightmaps.
At the moment Indevilage Engine (yes my engine is called Indevilage) uses normals generated on a per patch basis but eventually i want to use high res normal maps generated on the gpu. Heres the function and an example of what it does.
I know this is a bit of a side step from my normal posts but i haven really posted anything usefull i thin its time i started.
1: public static Texture2D NormalMapFromHeightMap(GraphicsDevice Device,Texture2D heightmap)
2: {
3: int size = heightmap.Width;
4: Color[] colorArray = new Color[size * size];
5: heightmap.GetData<Color>(colorArray);
6: Color[] normalArray = new Color[size * size];
7: Vector3 xyzdist = new Vector3(0.01f, 0.01f, 0.01f);//new Vector3(1.0f, 1.0f, 1.0f);
8: for (int i = 0; i < size - 1; i++)
9: {
10: for (int j = 0; j < size - 1; j++)
11: {
12: float sample1 = (colorArray[i + (j + 1) * size].R + colorArray[i + (j + 1) * size].G + colorArray[i + (j + 1) * size].B);
13: float sample2 = (colorArray[i + j * size].R + colorArray[i + j * size].G + colorArray[i + j * size].B);
14: float sample3 = (colorArray[(i + 1) + j * size].R + colorArray[(i + 1) + j * size].G + colorArray[(i + 1) + j * size].B);
15: Vector3 surfacesample0 = new Vector3(i * xyzdist.X, j * xyzdist.Y, sample1 * xyzdist.Z);
16: Vector3 surfacesample1 = new Vector3(i * xyzdist.X, (j + 1) * xyzdist.Y, sample2 * xyzdist.Z);
17: Vector3 surfacesample2 = new Vector3((i + 1) * xyzdist.X, j * xyzdist.Y, sample3 * xyzdist.Z);
18: Vector3 surfacevec0 = surfacesample1 - surfacesample0;
19: Vector3 surfacevec1 = surfacesample2 - surfacesample0;
20: surfacevec0.Normalize();
21: surfacevec1.Normalize();
22: Vector3 surfacenormal = new Vector3();
23: Vector3.Cross(ref surfacevec0, ref surfacevec1, out surfacenormal);
24: surfacenormal.Normalize();
25: surfacenormal.Z = -surfacenormal.Z;
26: surfacenormal.X = (surfacenormal.X + 1.0f) / 2.0f;
27: surfacenormal.Y = (surfacenormal.Y + 1.0f) / 2.0f;
28: surfacenormal.Z = (surfacenormal.Z + 1.0f) / 2.0f;
29: normalArray[i + j * size] = new Color(surfacenormal);
30: }
31: }
32: Texture2D texture = new Texture2D(Device, size, size);
33: texture.SetData(normalArray);
34: return texture;
35: }
Heightmap
I havent actually had time to test this in my engine, but it seems to generate the right values, i hope this is of help to anybody.
No comments:
Post a Comment