I am currently looking for some guidance on how to correctly calculate my normals on the CPU for my terrain as the results I'm getting seem to be incorrect. Eventually I will attempting to calculate them on the GPU as I'm aiming for terrain deformation in real-time.
These are the results
The different colours on the image represent different normal values.
Here is the code I'm using to generate them.
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int index1 = (j * width) + i;
int index2 = (j * width) + (i + 1);
int index3 = ((j + 1) * width) + i;
int index4 = ((j + 1) * width + i);
int index5 = ((j * width + (i + 1)));
int index6 = ((j + 1) * width + (i + 1));
//vertices of triangle
Vertex vertex1 = vertices->at(index1);
Vertex vertex2 = vertices->at(index2);
Vertex vertex3 = vertices->at(index3);
Vertex vertex4 = vertices->at(index4);
Vertex vertex5 = vertices->at(index5);
Vertex vertex6 = vertices->at(index6);
//each vertex as XMVECTOR
XMVECTOR point1 = XMVectorSet(vertex1.Pos.x, vertex1.Pos.y, vertex1.Pos.z, 0.0f);
XMVECTOR point2 = XMVectorSet(vertex2.Pos.x, vertex2.Pos.y, vertex2.Pos.z, 0.0f);
XMVECTOR point3 = XMVectorSet(vertex3.Pos.x, vertex3.Pos.y, vertex3.Pos.z, 0.0f);
XMVECTOR point4 = XMVectorSet(vertex4.Pos.x, vertex4.Pos.y, vertex4.Pos.z, 0.0f);
XMVECTOR point5 = XMVectorSet(vertex5.Pos.x, vertex5.Pos.y, vertex5.Pos.z, 0.0f);
XMVECTOR point6 = XMVectorSet(vertex6.Pos.x, vertex6.Pos.y, vertex6.Pos.z, 0.0f);
//lines to compute the cross product
XMVECTOR line1 = XMVectorSubtract(point2, point1);
XMVECTOR line2 = XMVectorSubtract(point3, point1);
XMVECTOR line3 = XMVectorSubtract(point5, point4);
XMVECTOR line4 = XMVectorSubtract(point6, point4);
//cross product to get our unnormalized normal
XMVECTOR cross = XMVector3Cross(line1, line2);
XMVECTOR cross2 = XMVector3Cross(line3, line4);
//normalize to get our normal value
cross = XMVector3Normalize(cross);
cross2 = XMVector3Normalize(cross2);
vertices->at(index1).Normal = Operations::vectorToXMFLOAT3(cross);
vertices->at(index2).Normal = Operations::vectorToXMFLOAT3(cross);
vertices->at(index3).Normal = Operations::vectorToXMFLOAT3(cross);
vertices->at(index4).Normal = Operations::vectorToXMFLOAT3(cross2);
vertices->at(index5).Normal = Operations::vectorToXMFLOAT3(cross2);
vertices->at(index6).Normal = Operations::vectorToXMFLOAT3(cross2);
}
}
Edit: I have made some changes to the code to account for the second triangle in the triangle pair but still produces similar results. The green (grass) represents a normal value of 0. The pink represents a normal value of 1. The red represents a normal value of -1
Why is the majority of the mesh 0, and where the normals are calculated, they are incorrect?
Edit 2
I have removed the use of the indices array in this loop and now the whole plane is processed, but results are still incorrect.
Edit 3
I did not realise I was referencing the indices array in more than one place. When I corrected this, I am now seeing better results. Although there is a slight problem of the normal that is being calculated is -1 instead of the expected +1
Edit 4:
Normals are calculated per vertex and don't take other touching faces into account, that is the next step. I'm guessing some parts of the texturing/terrain look a little weird due to this.
At the moment my terrain is just a flat plane, so all of the normals should be the same, right? However the values seem to be different when rendering/printing out.
There are some values that are 0, some are -1 and the rest are +1. Does anyone know where I'm going wrong?