# How many normals are needed to have a smooth surface?

I'm trying to draw a smooth cloth surface and I have a per-pixel shader. I expect to have a smooth surface but it's not the case. I think the problem comes from my normals.

The image show the surface drawn with multiple triangles. The surface is lit; the white zone are specular reflection.

Here is the way I calculate normals

ofVec3f v0(ps[i].pos.x, ps[i].pos.y, ps[i].pos.z);
ofVec3f v3(ps[i+cols+1].pos.x, ps[i+cols+1].pos.y, ps[i+cols+1].pos.z);
ofVec3f v1(ps[i+1].pos.x, ps[i+1].pos.y, ps[i+1].pos.z);
ofVec3f v2(ps[i+cols].pos.x, ps[i+cols].pos.y, ps[i+cols].pos.z);

ofVec3f n0 = (v1-v0).cross(v3-v0);
n0.normalize();
ofVec3f n2 = (v0-v2).cross(v3-v2);
n2.normalize();
ofVec3f n3 = (v0-v3).cross(v1-v3);
n3.normalize();
ofVec3f n1 = -(v0-v1).cross(v3-v1);
n1.normalize();


Here is the code to draw my surface. It's a 64x64 array of double triangles

glBegin(GL_TRIANGLES);

for (int i=0; i<ps.size()-(cols+1); i++) {
//  v0 - v1
//  | \  |
//  v2 - v3

// v0
glNormal3f(n0.x, n0.y, n0.z);
glVertex3f(ps[i].pos.x, ps[i].pos.y, ps[i].pos.z);

//v3
glNormal3f(n3.x, n3.y, n3.z);
glVertex3f(ps[i+cols+1].pos.x, ps[i+cols+1].pos.y, ps[i+cols+1].pos.z);

//v1
glNormal3f(n1.x, n1.y, n1.z);
glVertex3f(ps[i+1].pos.x, ps[i+1].pos.y, ps[i+1].pos.z);

//v0
glNormal3f(n0.x, n0.y, n0.z);
glVertex3f(ps[i].pos.x, ps[i].pos.y, ps[i].pos.z);

//v2
glNormal3f(n2.x, n2.y, n2.z);
glVertex3f(ps[i+cols].pos.x, ps[i+cols].pos.y, ps[i+cols].pos.z);

//v3
glNormal3f(n3.x, n3.y, n3.z);
glVertex3f(ps[i+cols+1].pos.x, ps[i+cols+1].pos.y, ps[i+cols+1].pos.z);


I don't know how many normals I need and where to put them: at each vertex, one by face ? four by vertex ? I still have a flat triangulated surface although I have a per pixel glsl shader

Thanks for help.

• Looks quite smooth to me, apart from those holes in the top right. Is that what you want to fix? – Anko Aug 14 '14 at 11:06
• @Anko I expect not to see the triangles nor the quads but a uniform smooth surface – user46759 Aug 14 '14 at 11:24
• You've shown us a fragment of code for drawing six vertices, each of which have a texture coordinate and three of which have normals. What primitive type are you drawing? What is your screenshot showing? Is that a screenshot of a single quad, or a pair of triangles, or a lot of triangles? Or something else? Are the colors we see in the screenshot coming from the texture? And why are you only putting normals on three of your six vertices? Give us at least a little help in terms of what you're doing, or we can't have any real idea of what's going wrong. – Trevor Powell Aug 14 '14 at 13:01
• @TrevorPowell you're right. So I edited a little. I put only normals on three vertices because I'm not sure how and where to put normals in such a case. So I added three more and the result is the same – user46759 Aug 14 '14 at 14:23
• You might want to look into VBOs and VAOs. That probably doesn't have anything to do with your question, but using newer "techniques" might help people answer your questions, as they might be more familiar with newer and possibly not deprecated stuff. – Tyyppi_77 Aug 14 '14 at 15:12

The way you are computing vertex normals only considers an individual quad and not its neighbours. Thus you get the discontinuities between the somewhat flat quads.

If you want smooth normals, the way to compute them is to consider the gradient of nearby vertices on your grid.

If you've got points on the form

a-b-c
| | |
d-e-f
| | |
g-h-i


then you want to use the gradient between b,h and d,f when computing your normal for the vertex e. Alternatively, you can compute face normals for each surrounding quad and normalize the average of them to be your vertex normal.

All in all, you need to consider the neighbourhood of your vertices in order to get smooth shading across them. No amount of per-pixel shading will help you if the interpolated quantities are essentially constant.

• I think you got it. I'll give a try. What do you mean by gradient? average ? – user46759 Aug 14 '14 at 18:59

Smooth shading can be enabled with glShadeModel(GL_SMOOTH) which is, however, the default. Your screenshot does look like you have the flat shading set.

• I've enabled smooth shading – user46759 Aug 14 '14 at 14:04