Archived

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

aker_jus

Computing normals for terrain

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 this post


Link to post
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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites