Normalizing normals of an indexed vertex array does not seem to work

Hello, im trying to render some simple map using the VBO and Shader.
Im trying to fix this annoying stoff for an few days now, but i cant seem to fix it.
Does anyone have suggestions?

VBO Code:


    public void Draw(){       
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindBufferARB(GL_ARRAY_BUFFER_ARB, pointbufferid);
        bindBufferData();
        
        glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexbufferid);
        if(update){  glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexbuferdata, type); }

        
        
        glVertexPointer(3, GL_FLOAT, stride, 0); // float at index 0
        glNormalPointer(GL_FLOAT, stride, 12);
        glTexCoordPointer(2, GL_FLOAT, stride, 24); // float at index 6
        
        //glEnableVertexAttribArray(attrib);
        //glVertexAttribPointer(attrib, 4, GL_UNSIGNED_BYTE, false, stride, 32);

        glDrawElements(GL_TRIANGLES, indexsize, GL_UNSIGNED_INT, 0);
        
        
        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

        
        //glDisableVertexAttribArray(attrib);
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_NORMAL_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        
        update = false;
    }

Calculating normals for Vertex points:


    private void calcNormals(){
        normal = new Vector3f(1,1,1);
        
        for(TriangleIndice f : faces){
            Vector3f.add(normal, f.getNormal(), normal);
        }
     
        normal.normalise();
        //System.out.println(normal.x + " x " + normal.y + " x " + normal.z);
    }

Shader (just simple lightning):


varying vec3 normal, lightDir, eyeVec;
varying vec3 pos;

uniform vec3 lightpos;

vec4 color, c;

void main()
{   
    vec3 N = normalize(normal);
    vec3 L = normalize(lightDir);
	float lambertTerm = dot(N,L);

	float val = clamp(lambertTerm, 0, 1);
	c = vec4(val, val, val, 1);
	
    

    gl_FragColor = vec4(c.xyz, 1.0);
}

Result:

As visible, the normals are kinda messed up at some places.

Actually that is correct. The visual artifacts are the result of triangles not being curved surfaces.

Interpolating the normals (and even renormalizing it) is not enough, if you look at the actual normals per vertex of the triangle. The normals in the corners of your triangle are simply too different to produce an accurate continuous ‘surface’.

You can work around this issue by increasing the density of height-samples (in rough areas), or using a normalmap with significantly higher resolution than your geometry heightmap.

Last but not least:


    private void calcNormals(){
-        normal = new Vector3f(1,1,1);
+        normal = new Vector3f(0,0,0);
        
        for(TriangleIndice f : faces){
            Vector3f.add(normal, f.getNormal(), normal);
        }
     
        normal.normalise();
        //System.out.println(normal.x + " x " + normal.y + " x " + normal.z);
    }

Thank you, but i think im already doing this, the maxheight is 5000.

With this function im generating points:


    private TrianglePoint getTrianglePoint(int xoffset, int zoffset){
        float px = (x+xoffset)*16;
        float pz = (z+zoffset)*16;
        
        //Vector3f position, Vector2f Texture
        return new TrianglePoint(new Vector3f(px, (float)height[xoffset*size+zoffset] / 150f, pz), new Vector2f(px / (float)size, pz / (float)size));
    }

*The fix you posted did not do much:

Just increase the density of your heightmap, and you’ll see the problem is fixed - just like I suggested.

As this is probably too heavy on the geometry side, I suggested normalmaps to fake it.

It fixed a bug. Thanks for the gratitude.

Thank you, the problem is clear, i guess using vertex normals wont work so well with this rotation.
(small changes are not very visible, big ones get glitched.
Im going to follow your advise for normal maps.

Im gratefull for your help.
I was just talking about the problem iself, and i already sayd thanks in the post, so i thought twice is a little to much :slight_smile:

[quote=“RobinB,post:4,topic:41267”]
You can’t be doing that already. The problem is that ‘max height’ doesn’t influence ‘roughness’ in a meaningful way. In the end you want curvy slopes, and one way or another you’ll have to create accurate normals for them, so there’s no way around providing high resolution geometry - whether that translates into a higher vertex count (either for the full map, or for problematic regions) or a normalmap is up to you, but there is no way to ‘fix’ this problem with ‘max height’ or any other mathematical corrections in the current setup.

Imagine trying to render normals for a sphere, where you sample 8 points (they form a cube). You’ll never get the normals to look right, because the ‘samples’ and the accompanying normals are not accurate enough to create smooth (interpolated) normals. The more samples points you throw at it, the better the quality of the interpolated normals (and therefore shading) becomes.

Thanks, i understand.
Now im trying to get some normals from my height map, but it gets really messed up:

Top image is the heightmap, bottom image are the calculated normals from this texture.
Does ayone knos why it does get so messed up?

Shader code:


	vec2 size = vec2(2.0,0.0);
	float NORMAL_OFF = (1.0 / 256.0);
	vec3 offset = vec3(-NORMAL_OFF, 0, NORMAL_OFF);

	float s11 = texture2D(Texture0, gl_TexCoord[0].xy).x;
    float s21 = texture2D(Texture0, gl_TexCoord[0].xy + offset.zy).x;
    float s12 = texture2D(Texture0, gl_TexCoord[0].xy + offset.yz).x;
    vec3 va = normalize( vec3(offset.z, 0.0, s21 - s11) );
	vec3 vb = normalize( vec3(0.0, offset.z, s12 - s11) );
	
	vec3 N = normalize( cross(va, vb) );

Scale s11, s21 and s12 way down, so that they make sense relative to NORMAL_OFF.

I think my whole code was off, even scaling the values did not change much.
I found some c++ code to create normals really nicely, so i just took this and ported it to glsl.
Thansk for your help Riven :smiley:


float getHeightMap(int xoff, int yoff){
	return texture2D(Texture0, gl_TexCoord[0].xy + vec2(NORMAL_OFF * xoff, NORMAL_OFF * yoff)).x;
}

vec3 CalculateNormal()
{
            // Value from trial & error.
            // Seems to work fine for the scales we are dealing with.
            float strength = 4;
 
            float tl = getHeightMap(-1, -1);
            float l = getHeightMap(-1, 0);
            float bl = getHeightMap(-1, 1);
            float b = getHeightMap(0, 1);
            float br = getHeightMap(1, 1);
            float r = getHeightMap(1, 0);
            float tr = getHeightMap(1, -1);
            float t = getHeightMap(0, -1);
 
            // Compute dx using Sobel:
            //           -1 0 1 
            //           -2 0 2
            //           -1 0 1
            float dX = tr + 2 * r + br - tl - 2 * l - bl;
 
            // Compute dy using Sobel:
            //           -1 -2 -1 
            //            0  0  0
            //            1  2  1
            float dY = bl + 2 * b + br - tl - 2 * t - tr;
 
            vec3 N = normalize(vec3(dX, dY, 1.0f / strength));
 
    return N;
}