Help on Normals

Hi everyone, I made a cloth simulation using vertex_strip and I’m having hard time with normals.

I have attached an image that will make things more clear…
So if you can see it you can notice that there is a kind of cross between the quads and the quads edges are darker and made of a flat color. I placed a sphere in the scene for collision detection, and it’s working perfectly. I also changed two two times shaders and normals calculation , bui tnothing I always get the same problem.
If you have an idea why I got it please let me know.

P.s
Light is done in the pixel shader

Thanks

It seems like the normals are just interpolated in the Fragment Shader, yielding normals with a length less than 1.

Are you re-normalizing the normals every fragment?

I wasn’t doing it for the spec component. I was passing to it Normal instead of normalizedNormal. So thank you I fixed the specular component. But the the other problem persist. I attached another picture to show you.

Anyway thank you for your help.

Looks good! :smiley:
I know your prolly not supposed to post useless things but I figured a compliment is just as important as some code/explanation.

I hate to say it, but it looks to me the gouraud shading also need re-normalized normals… ?

Because the shade in the corners is good, it just has linear interpolation of the shade over the triangle, which looks weird, but in the end it seems to be exactly the same problem as what you had with specular lighting.

What confuses me, is that you can use the same normal for both gouraud shading and specular shading, so maybe you are not working with the already re-normalized normal, but accessing interpolated (non-normalized) gl_Normal again for gouraud shading?

I’m not sure I completely understood what you say ( because of me…) so I posted the shader code

varying vec3 Normal;
varying vec3 Light;
varying vec3 HalfVector;

void main(void)
{
    Normal = normalize(gl_NormalMatrix * gl_Normal);

    Light = normalize(gl_LightSource[0].position.xyz);

    HalfVector = normalize(gl_LightSource[0].halfVector.xyz);

   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

Fragment

varying vec3 Normal;
varying vec3 Light;
varying vec3 HalfVector;

void main(void)
{


vec3 lightNorm = normalize(Light);

vec3 normalizedNormal = normalize(Normal);


vec3 Diffuse = gl_FrontMaterial.diffuse.xyz*gl_LightSource[0].diffuse.xyz * max(dot(normalizedNormal.xyz, lightNorm.xyz),0.0);

vec3 Ambient = gl_FrontMaterial.ambient.xyz * gl_LightSource[0].ambient.xyz;

vec3 Specular = gl_FrontMaterial.specular.xyz * gl_LightSource[0].specular.xyz * pow(max(dot(normalizedNormal,HalfVector),0.0),gl_FrontMaterial.shininess);

vec3 total= Ambient + Diffuse  + Specular;
gl_FragColor = vec4(total,1.0);
}

Thank you…

At first glance the shader code seems fine to me. Are you sure you’re computing the normals of the mesh correctly when you update the simulation? (you did say the sphere was shaded correctly, right?)

Are the normals calculated by taking one triangle’s normal, or by calculating the average of all normals of the connecting triangles?

Vertex normals are calculated by taking the average of the triangles faces connected.

I’m not sure I’m doing it correctly, but I changed to different algorithm and I got always the same problem.

As you can see from the image , you can perfectly notice the grid path darker, and that’s really weird to me and a brighter cross in the middle. I don’t no I tried everything but I work that out.

This is puzzling, but here are some suggestions:

  1. What does it look like with standard ffp flat and smooth shading?
  2. Try computing the half-vector on the fragment stage.
  3. Visualize the normals:
    a. Actually draw all of the vertex normals as small lines
    b. Instead of computing lighting, just set gl_FragColor to the normal vector.

So… that is what I found out following your suggestions:

1 standard ffp smooth shading: same problem
2 flat shading: no problems ( see picture attached)
3 half vector in the fragment: same problem;
4 gl_FragColor to the normal: same problem( see picture attached)

I think it’s because normals are calculate or assigned
Do you think the the cross could be due to the fact that opposite vertex in the quad have the same normal value ?

I don’t wan to bother you with code but please if you could check how I calculate normals I would really appreciate:

		Vec3 diff0=new Vec3(0,0,0);
		Vec3 diff1=new Vec3(0,0,0);
		Vec3 diff2=new Vec3(0,0,0);
		Vec3 diff3=new Vec3(0,0,0);
		Vec3 diff4=new Vec3(0,0,0);
		Vec3 diff5=new Vec3(0,0,0);
		
		if((col+1)<numberOfParticles)
			 diff0=Vec3.subtract(getPosition(row, col+1), getPosition(row, col));
		if(((col+1)<numberOfParticles) && ((row+1)<numberOfParticles))
			diff1=Vec3.subtract(getPosition(row+1, col+1), getPosition(row, col));
		if((row+1)<numberOfParticles)
			diff2=Vec3.subtract(getPosition(row+1, col), getPosition(row, col));
		if((col-1)>-1)
		 diff3=Vec3.subtract(getPosition(row, col-1), getPosition(row, col));
		if(((col-1)>-1) && ((row-1)>-1))
			diff4=Vec3.subtract(getPosition(row-1, col-1), getPosition(row, col));
		if(((col+1)<numberOfParticles) && ((row-1)>-1))
			diff5=Vec3.subtract(getPosition(row-1, col+1), getPosition(row, col));
		
		Vec3 normSum=Vec3.crossProduct(diff1, diff0).toVersor().sum(Vec3.crossProduct(diff2, diff1).toVersor()
				.sum(Vec3.crossProduct(diff3, diff2).toVersor()
						.sum(Vec3.crossProduct(diff4, diff3).toVersor().sum(Vec3.crossProduct(diff5, diff4).toVersor()))));

		
		Vec3 normal = normSum.toVersor();
		normSum.glNormal3d(gl);
		getPosition(row, col).glVertex3d(gl);

Thank you

ffp smooth shading should give better results. Please double check if you are calculating the normls correctly and/or uploaded your VBO properly.

i think the easiest way to calculate per vertex normals is to first calculate them per face and interpolate in a second pass between all six faces in the neighborhood of each vertex. (haven’t looked at your code, currently a bit busy)

i attached my ffp smooth shaded flag

I think I have to re calculate the normal form scratch… That really bother me…
Anyway bienator I saw your simulation looks great I can almost achieve that result only with about 60x60 and my solver (a simple verlet) but i need to get a lower step and my framerate go down to 15fps…

Did you use an implicit solver? like implicit euler for example?
Did you perform collision within the cloth mesh?

last question … you said about VBO I did not know what it was so I checked and I was wondering : will be the simulation faster even if I have to fill the VBO every frame with new vertex?

Those results are, unfortunately, what I expected :expressionless:

At first glance, late at night, your algorithm looks okay, with a few questions:

  1. Why do you use only 6 difference vectors, instead of 8? It looks like you’re missing (row-1, col) and (row+1, col-1).
  2. You calculate normSum.toVersor() but you don’t pass that in to openGL. If you’re passing in unnormalized normals, it may be screwing up your card’s interpolator?? It’s just a thought.

I think he used 6 out of 8 as only 6 triangles actually connect to the center.

In theory 6 would be enough, because those other 2 would, in reality, not affect the normal.

If you are averaging the results (smoothing pass) you do care about the remaining 2.

yes exactly I thought I had to sum only the faces connected to the vertex.
This is the other way I calculated the normals obtaining the same result… I really don’t know what to do… I’m really sorry again to bother you with long pieces of code but please take a look at it …

	//--------------------------------------------------------------
	// Drawing particleGrid
	//--------------------------------------------------------------
	
	public void draw(GL gl)
	{
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
		
		clearNormals();
		for (int row = 0; row < numberOfParticlesLessOne; row++)
		{
			gl.glBegin(GL.GL_TRIANGLE_STRIP);
			for (int col = 0; col < numberOfParticles; col++)
			{
				drawVertex(row, col, gl);

				drawVertex(row + 1, col, gl);
			}

			gl.glEnd();
		}

	}
	
	
	private void drawVertex(int row, int col, GL gl)
	{
		Vec3 normal = getVertexNormal(row, col);
		normal.toVersor().glNormal3d(gl);
		getPosition(row, col).glVertex3d(gl);
	}
	
	private Vec3 getPosition(int row, int col)
	{
		return getParticles().get(col + (row * numberOfParticles)).getPosition();
	}
	
	private Vec3 getFaceNormal(int row, int col, int half)
	{
		Vec3 faceNormal = faceNormals[row][col][half];
		if (faceNormal == null)
		{
			Vec3 a = getPosition(row + 1, col);
			Vec3 b = getPosition(row, col + 1);
			Vec3 c = null;
			if (half == 0)
			{
				c = getPosition(row, col);
			}
			else
			{
				c = getPosition(row + 1, col + 1);
			}
			Vec3 v1 = Vec3.subtract(b, a);
			Vec3 v2 = Vec3.subtract(c, a);
			faceNormal = (half == 0) ? v1.crossProduct(v2).toVersor() : v2
					.crossProduct(v1).toVersor();
			faceNormals[row][col][half] = faceNormal.toVersor();
		}
		return faceNormal;
	}
	
	

	private Vec3 getVertexNormal(int row, int col)
	{
		Vec3 vertexNormal = vertexNormals[row][col];
		if (vertexNormal == null)
		{
			vertexNormal = new Vec3();

			if ((row > 0) && (col < numberOfParticlesLessOne))
			{
				vertexNormal.sum(getFaceNormal(row - 1, col, 0));
				vertexNormal.sum(getFaceNormal(row - 1, col, 1));
			}

			if ((row < numberOfParticlesLessOne) && (col > 0))
			{
				vertexNormal.sum(getFaceNormal(row, col - 1, 0));
				vertexNormal.sum(getFaceNormal(row, col - 1, 1));
			}

			vertexNormal.quotient(2D);

			if ((row > 0) && (col > 0))
			{
				vertexNormal.sum(getFaceNormal(row - 1, col - 1, 1));
			}

			if ((row < numberOfParticlesLessOne)
					&& (col < numberOfParticlesLessOne))
			{
				vertexNormal.sum(getFaceNormal(row, col, 0));
			}

			vertexNormal.toVersor();
			vertexNormals[row][col] = vertexNormal;
		}
		return vertexNormal;
	}
	
	private void clearNormals()
	{
		for (int i = 0; i < numberOfParticles; i++)
		{
			for (int j = 0; j < numberOfParticles; j++)
			{
				vertexNormals[i][j] = null;
				if ((i < numberOfParticlesLessOne)
						&& (j < numberOfParticlesLessOne))
				{
					faceNormals[i][j][0] = null;
					faceNormals[i][j][1] = null;
				}
			}
		}

[quote]Vertex normals are calculated by taking the average of the triangles faces connected
[/quote]
this may not work properly, when you compute a vertex normal you must consider that all adjacent face doesn’t affect it the same, you have to use the size of the angle that touch the vertex to know how much it affect the vertex normal, at least it gave me better result.