For some reason this simple normal code does not produce the desired results.

Perhaps they are backwards or something. I'm using pre-computed light because not much is gained with dynamic lighting.Code:void CTerrain::ComputeNormals(void) { TerrainVertex *Vertices; m_pVB->Lock(0,0,(void **)&Vertices,0); for (int i=0;i<m_iNumCellsPerCol;i++) { for (int j=0;j<m_iNumCellsPerRow;j++) { int index0=i * m_iNumVertsPerRow + j; int index1=i * m_iNumVertsPerRow + j + 1; int index2=(i+1) * m_iNumVertsPerRow + j; int index3=(i+1) * m_iNumVertsPerRow + j; int index4=i * m_iNumVertsPerRow + j + 1; int index5=(i+1) * m_iNumVertsPerRow + j + 1; D3DXVECTOR3 v1=Vertices[index1].Position-Vertices[index0].Position; D3DXVECTOR3 v2=Vertices[index2].Position-Vertices[index0].Position; D3DXVECTOR3 v3=Vertices[index3].Position-Vertices[index4].Position; D3DXVECTOR3 v4=Vertices[index5].Position-Vertices[index4].Position; D3DXVECTOR3 Cross1,Cross2; D3DXVec3Cross(&Cross1,&v1,&v2); D3DXVec3Cross(&Cross2,&v3,&v4); D3DXVec3Normalize(&Cross1,&Cross1); D3DXVec3Normalize(&Cross2,&Cross2); Vertices[index0].Normal=Cross1; Vertices[index1].Normal=Cross1; Vertices[index2].Normal=Cross1; Vertices[index3].Normal=Cross2; Vertices[index4].Normal=Cross2; Vertices[index5].Normal=Cross2; } } m_pVB->Unlock(); } void CTerrain::LightTerrain(D3DXVECTOR3 LightSource) { TerrainVertex *Vertices; m_pVB->Lock(0,0,(void **)&Vertices,0); for (int i=0;i<m_iNumCellsPerCol;i++) { for (int j=0;j<m_iNumCellsPerRow;j++) { int index=i * m_iNumVertsPerRow + j; D3DXVECTOR3 ToLight=LightSource-Vertices[index].Position; D3DXVec3Normalize(&ToLight,&ToLight); float dot=D3DXVec3Dot(&Vertices[index].Normal,&ToLight); if (dot>=0.0f) { Vertices[index].r*=dot; Vertices[index].g*=dot; Vertices[index].b*=dot; Vertices[index].Diffuse=D3DXCOLOR(Vertices[index].r, Vertices[index].g, Vertices[index].b, 1.0f); } } } m_pVB->Unlock(); }