#### Archived

This topic is now archived and is closed to further replies.

# Computing normals for terrain

This topic is 5404 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

How can I compute vertex normals for a terrain chunk? Suppose the chunk is 32x32, what should I do? So far, I am setting the ny to 1 and all other to 0. Any other ways? Thanks

##### Share on other sites
my 3d math is beyond rusty but look up the cross product that should give you the info you need to calculate the normal for a surface/triangle, dot product can also come in handy when culling geometry. just look up any vector math tutorial and it will probably show you how to do this and a lot more...

- Damage Inc.

##### Share on other sites
Can you point me at a tutorial? I almost now where I need to "move", along the lines of Cross vector and Dot product.

##### Share on other sites
if you have your terrain data in one of the D3DX mesh object classes then you can just use D3DXComputeNormals.

otherwise you can use D3DXVec3Cross to get the cross product for each triangle. you would then want to calculate the vertex normals by averaging all of the face normals together for all triangles that made use of each vertex.

##### Share on other sites
Thank you, I fixed them now. But I have a problem. I have a material for my terrain, with diffuse (1,1,1,1) and ambient (0,0,0).
For my light, I use directional, with direction = 0,-1,0 (downwards), ambient (1,1,1) and diffuse(1,1,1).

Now, something weird happens. If I disable lighting, the terrain is lit, where it should be black, right? When I enable lighting, the terrain''s color is dependant of the material, not the light. Also, the diffuse (material or light color) isnt changing anything, only the ambient is. For my scene ambient color, I use full white.

Any ideas? I believe that the diffuse light sets the color for a mesh after it is lit, not the ambient.

##### Share on other sites
Try setting a lower ambient value

##### Share on other sites
I just did. Well, sorry to ask so many questions, but it was not directly my fault. I fixed it, but for the light, the Y is reversed! I was using 0,-1,0 as I told you for my directional light direction. I wasnt getting results whatsoever, and I wondered. So I switched to 0,1,0 and voila.. But why, its weird. Shouldnt it be the reverse way?

Anyway it works now, but if you could tell me why this happens, it would be excellent.

##### Share on other sites
Could it be that your normals are pointing the wrong way? If you switch places of the two source vectors in the D3DXVec3Cross function the direction of the normal will be reversed.

##### Share on other sites
Cool, do you think I have them reversed? I''ll try to see. Thank you very much!

##### Share on other sites
You can compute cross products for each vertex, but if your terrain is a grid, this is a faster method (and gives you the same answer):

	The 4 adjacent points in a uniform grid: A, B, C, D	   B	   |	C--0--A	   |	   D	The ratio of XY-scale to Z-scale: s = Sxy / Sz	The desired normal: N = cross(A,B) + cross(B,C) + cross(C,D) + cross(D,A), (then normalize)		A faster way to get the same answer:	Nx = 2 * s * (Cz - Az)	Ny = 2 * s * (Dz - Bz)	Nz = 4 * s^2	N = normalize( N )		And since N is normalized in the end, it can be divided by 2 * s:		Nx = Cz - Az	Ny = Dz - Bz	Nz = 2 * s	N = normalize( N )

[edited by - Jambolo on May 4, 2003 4:04:48 AM]

##### Share on other sites
Cool I will do that.

##### Share on other sites
this is quick and dirty ripped code from andy pikes tutorials

  bool CAdvTerrain::CalcNormals(){	DWORD numVertices;	DWORD numFaces;	// Get face and vertex count	numFaces		= m_TerrainFaces;	numVertices		= m_TerrainVerts;	WORD* pNumOfSharedPolygons = new WORD[numVertices];							//Array holds how many times this vertex is shared	D3DXVECTOR3* pSumVertexNormal = new D3DXVECTOR3[3 * numFaces];						//Array holds sum of all face normals for shared vertex	ADVT_CUSTOMVERTEX* pVertices;	short* pIndices;	D3DXVECTOR3 vNormal;	//Lock the vertex buffer	m_pTerrainVB->Lock(0, numVertices * sizeof(ADVT_CUSTOMVERTEX),(void **)&pVertices, 0);	m_pTerrainIB->Lock(0, 3 * numFaces * sizeof(short), (void **)&pIndices, 0);	int facenew = 0;	for (DWORD i=0; i < numFaces ; i++)	{		pNumOfSharedPolygons[pIndices[3*i+0]] = 0;		pSumVertexNormal[pIndices[3*i+0]] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);		pSumVertexNormal[pIndices[3*i+1]] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);		pSumVertexNormal[pIndices[3*i+2]] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);	}	for (DWORD i=0; i < numFaces ; i++)	{		D3DXVECTOR3 v0 = pVertices[pIndices[3*i+0]].p;		D3DXVECTOR3 v1 = pVertices[pIndices[3*i+1]].p;		D3DXVECTOR3 v2 = pVertices[pIndices[3*i+2]].p;		vNormal = GetTriangeNormal(&v0,  &v1, &v2);				pNumOfSharedPolygons[pIndices[3*i+0]]++;		pNumOfSharedPolygons[pIndices[3*i+1]]++;		pNumOfSharedPolygons[pIndices[3*i+2]]++;		pSumVertexNormal[pIndices[3*i+0]] += vNormal;		pSumVertexNormal[pIndices[3*i+1]] += vNormal;		pSumVertexNormal[pIndices[3*i+2]] += vNormal;		}// Direction vector OF DIRECTIONAL LIGHT TO TEST NORMALS dont need to enable d3d lighting	D3DXVECTOR3 lightpos = D3DXVECTOR3(0.0f, 1.0f, 0.0f);	float factor = 0.0f;	//For each vertex, calculate the average normal	for(i = 0; i < numVertices; i++)	{		vNormal.x = pSumVertexNormal[i].x / pNumOfSharedPolygons[i];		vNormal.y = pSumVertexNormal[i].y / pNumOfSharedPolygons[i];		vNormal.z = pSumVertexNormal[i].z / pNumOfSharedPolygons[i];		D3DXVec3Normalize(&vNormal, &vNormal);		pVertices[i].n = vNormal;		D3DXVec3Normalize(&lightpos, &lightpos);		factor = D3DXVec3Dot(&vNormal, &lightpos);		if (factor < 0)			factor = 0;		float red = 25.0f * factor;		float gre = 185.0f * factor; // terrain green color		float blu = 55.0f * factor;			pVertices[i].d = D3DCOLOR_XRGB((int)red, (int)gre, (int)blu);	}	// Smooting stuff in rows and cols	float k = 0.0f;	m_pTerrainVB->Unlock();	m_pTerrainIB->Unlock();	return true;}

##### Share on other sites
I fixed it, it was mainly the Scene ambient color!! I had it white, thus overriding the light color. I will post some screenshots soon for you to see.