Sign in to follow this  
NickGravelyn

Error Computing Terrain Normals

Recommended Posts

NickGravelyn    855
I followed a tutorial here on GameDev for calculating normals for heightfields. It works as far as creating surface normals, but somehow does not manage to smooth them out, though I have the code that is supposed to do it. Any trouble you see in the code?
normals = new SimVector[width * depth];

    SimVector *sNormals = new SimVector[width * depth * 10];

    int normalIndex = 0;
    float height0, height1, height2;
    SimVector normal1, normal2, normal3, normal4, normal5, normal6;

    for(j = -1; j < depth; j++)
    {
        for(i = -1; i < width; i++)
        {
            if(!IsValidCoord(i, j) || !IsValidCoord(i + 1, j) ||
                !IsValidCoord(i, j + 1) || !IsValidCoord(i + 1, j + 1))
            {
                normalIndex += 2;
                continue;
            }

            height0 = GetHeight(i, j);
            height1 = GetHeight(i, j + 1);
            height2 = GetHeight(i + 1, j);
            normal1.x = height0 - height2;
            normal1.y = 1;
            normal1.z = height0 - height1;

            height0 = height2;
            height2 = GetHeight(i + 1, j + 1);
            normal2.x = height1 - height2;
            normal2.y = 1;
            normal2.z = height0 - height2;

			SimStructs::Normalize(normal1);
			SimStructs::Normalize(normal2);

            sNormals[normalIndex++] = normal1;
            sNormals[normalIndex++] = normal2;
        }
    }


    int triIndex = 1;
    int indexPlusOne = 2;
    int indexPlusTwo = 3;
    int vertIndex = 0;
    int rowOffset = ((width + 1) * 2) - 1;
    SimVector vertNormal;

    for(j = 0; j < depth; j++)
    {
        for(i = 0; i < width; i++)
        {
            indexPlusOne = triIndex + 1;
            indexPlusTwo = triIndex + 2;

            normal1 = sNormals[triIndex];
            normal2 = sNormals[indexPlusOne];
            normal3 = sNormals[indexPlusTwo];
            normal4 = sNormals[rowOffset + triIndex];
            normal5 = sNormals[rowOffset + indexPlusOne];
            normal6 = sNormals[rowOffset + indexPlusTwo];

            vertNormal = normal1 + normal2 + normal3 + normal4 + normal5 + normal6;
            vertNormal /= 6.0f;

			SimStructs::Normalize(vertNormal);

            normals[vertIndex] = vertNormal;

            triIndex += 2;
            vertIndex++;
        }
        triIndex += 2;
    }
	delete[] sNormals;

Share this post


Link to post
Share on other sites
skow    248
That does look "smoothed" to me, but the problem may be the terrain its self. I cant be for sure, could you post a wireframe version of the terrain?

Share this post


Link to post
Share on other sites
Rockoon1    104
The "appearance" of non-smoothness is on edges that border both light and dark triangles

The reason for this (I believe) is that:

A) The diffuse color uses a straight bilinear [B]color[/B] interpolation between vertices.

B) The specular color uses a straight bilinear [B]normal[/B] interpolated between the vertices.

There is thus a mismatch between the interpolation types

one is interpolating color while the other is interpolating normals. Combining these two methods in an additive way is sure to create artifacts.

Fixed function pipeline with no texturing, right?

Share this post


Link to post
Share on other sites
Leo_E_49    228
It looks like you're using a regular grid of triangles, this probably contributes to the problem.

You appear to be using this pattern:

- -
|\|\|
- -
|\|\|
- -




You might want to use the diamond square pattern, which looks like this:


- -
|/|\|
- -
|\|/|
- -




You'll probably have to use an index array to accomplish this.

Hopefully this helps with the problem, although there does appear to be something else amiss with that picture.

Edit: Are you sure you are calculating your normals with the correct triangles? I had a similar problem when I was calculating the normals on triangles which were not along the correct diagonal (see the \ in the top source block, you may be calculating your normals in the direction of / instead by accident).

Share this post


Link to post
Share on other sites
Hamster    247
I only had a brief skim over the code, but it looks like you're using a slightly unorthodox method to keep your normals unit length. You shouldn't normalize them until the very last step, when you've added all contributing normals at a given vertex together. When you've done that sum, then normalize, don't divide by six and don't normalise any of the vectors you take in the earlier steps. If you do it this way, which I understand is a fairly standard way to do it with smooth shading, the influence of each triangle that uses the vertex on the direction of the final vertex normal will be proportional to the area of that triangle. It should speed up the code a bit too. Good luck with it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this