i have the following code for calculating Heightmap normals
void CalcMapNormals(HeightMap * map, Vec3f normals[])
{
int dst, i, j, right, bottom;
Vec3f p0, p1, p2;
Vec3f n0;
/* Avoid writing map->rows|cols - 1 all the time */
right = map->cols - 1;
bottom = map->rows - 1;
dst = 0;
for (i = 0; i < map->rows; i++) {
for (j = 0; j < map->cols; j++) {
Vec3Set(normals[dst], 0, 0, 0);
/* Vertex can have 2, 3, or 4 neighbours horizontally and vertically */
if (i < bottom && j < right) {
/* Right and below */
GetHeightPoint(map, i, j, p0);
GetHeightPoint(map, i + 1, j, p1);
GetHeightPoint(map, i + 1, j + 1, p2);
CalcTriNormal(n0, p0, p1, p2);
VecAdd(normals[dst], normals[dst], n0);
}
/* TODO: the other three possibilities */
VecNormalize(normals[dst]);
dst += 1;
}
}
/* Sanity check */
if (dst != map->rows * map->cols)
Fail("Internal error in CalcMapNormals: normals count mismatch");
}
I understand that the code get the three vertexes of the triangle, calculate its normal and then add them and normalize them to get averaged normal. But i don't know how you can get the other three possibilities, ive been doing something like the following:
void CalcMapNormals(HeightMap * map, Vec3f normals[])
{
int dst, i, j, right, bottom;
Vec3f p0, p1, p2;
Vec3f n0;
Vec3f p3, p4, p5;
Vec3f n1;
Vec3f p6, p7, p8;
Vec3f n2;
Vec3f p9, p10, p11;
Vec3f n3;
/* Avoid writing map->rows|cols - 1 all the time */
right = map->cols - 1;
bottom = map->rows - 1;
dst = 0;
for (i = 0; i < map->rows; i++) {
for (j = 0; j < map->cols; j++) {
Vec3Set(normals[dst], 0, 0, 0);
/* Vertex can have 2, 3, or 4 neighbours horizontally and vertically */
if (i < bottom && j < right) {
/* Right and below */
GetHeightPoint(map, i, j, p0);
GetHeightPoint(map, i + 1, j, p1);
GetHeightPoint(map, i + 1, j + 1, p2);
CalcTriNormal(n0, p0, p1, p2);
VecAdd(normals[dst], normals[dst], n0);
}
if ( i > bottom && j > 0)
{
GetHeightPoint(map, i, j, p3);
GetHeightPoint(map, i + 1, j, p4);
GetHeightPoint(map, i, j -1, p5);
CalcTriNormal(n1, p3, p4, p5);
VecAdd(normals[dst], normals[dst], n1);
}
if ( i > 0 && j > 0)
{
GetHeightPoint(map, i, j, p6);
GetHeightPoint(map, i, j - 1, p7);
GetHeightPoint(map, i - 1, j, p8);
CalcTriNormal(n2, p6, p7, p8);
VecAdd(normals[dst], normals[dst], n2);
}
if ( i > bottom && j < right)
{
GetHeightPoint(map, i, j, p9);
GetHeightPoint(map, i-1, j, p10);
GetHeightPoint(map, i, j+1, p11);
CalcTriNormal(n3, p9, p10, p11);
VecAdd(normals[dst], normals[dst], n3);
}
/* TODO: the other three possibilities */
VecNormalize(normals[dst]);
dst += 1;
}
}
/* Sanity check */
if (dst != map->rows * map->cols)
Fail("Internal error in CalcMapNormals: normals count mismatch");
}
But i don't think its giving me the result i wanted, i get the concept of normal averaging, but can't figure out the code.
Hi Yzwboy here is one way I would try to make "smoothed" normals (averaged based on adjacent triangles):
In order to compute "smoothed" normals you will need to assign to each vertex a normal which is averaged across the normals of the triangles adjacent to the vertex.
I would calculate a weighted average based on the angle between the two edges adjacent to the vertex in question (cross product which is an easy calculation):
Pseudocode:
And then to vary the normal by vertex:
You could also compute the area of a each triangle to use as the weighting, though I find using the angles works best for looks most times.
I have tried to use names which match the Vec3f spec, as well as inbuilt functions to save work, but you will need to do some coding to get the pseudocode working (I dont have access to a GL Test environment here).
Hope this helps :)