Searc

Monday 23 January 2012

Creating Normal Maps on the cpu

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

NormalMap


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