Sign in to follow this  

Error Computing Terrain Normals

This topic is 4261 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

This topic is 4261 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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