OpenGL Fundamental problem with smooth normals

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

Recommended Posts

Hello from Germany :) I created 2 triangles with different vertex order (counter clockwise and clockwise). This orders are user data and may not be changed. For the flat shading the view is ok. But for the smooth shading I get partial or full black triangles for the clockwise orders :( The problem is that I have only 1 averaged normal for a vertex. Is there a openGl statement to correct this mistake? Are the normals to be set principle after the "right hand rule"? Thanks in advance Greetings hoon Here's is a pic: And here's is the code with jogl (executable):
import javax.swing.*;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;
import java.nio.FloatBuffer;

public class NormalProblem
extends JFrame
implements GLEventListener
{
private static final boolean SMOOTH = true;
private int angle = 0;

public static void main(final String[] args)
{
new NormalProblem();
}

public NormalProblem()
{
final GLCanvas canvas = new GLCanvas();

setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

while (isWoken())
canvas.display();
}

public void display(final GLAutoDrawable drawable)
{
final GL gl = drawable.getGL();

gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

gl.glTranslatef(0, 0, -6);
gl.glRotated(angle, 1, 1, 1);
gl.glRotated(angle++, 0, 1, 0);

/*           3
*          /          *         / 1 \    triangle 1 [1, 2, 3] (counter clockwise vertex order)
*       1/_____\ 2
*        \     /
*  y      \ 2 /    triangle 2 [1, 2, 4] (clockwise vertex order)
*  ^       \ /
*  |        4
*  '---> x
*/

if (SMOOTH)

else

drawTriangles(gl);
drawNormals(gl);
}

private void drawTriangles(final GL gl)
{
gl.glBegin(GL.GL_TRIANGLES);

if (SMOOTH)
{
// triangle 1 [1, 2, 3]
gl.glNormal3f(0, 0, 1);
gl.glVertex3f(-2, 0, 0);

gl.glNormal3f(0, 0, 1);
gl.glVertex3f(2, 0, 0);

gl.glNormal3f(0, 0, 1);
gl.glVertex3f(0, 2, 0);

// triangle 2 [1, 2, 4]
gl.glNormal3f(0, 0, 1); // (0, 0, -1) is correct but I have only "one" vertex normal
gl.glVertex3f(-2, 0, 0);

gl.glNormal3f(0, 0, 1); // (0, 0, -1) is correct but I have only "one" vertex normal
gl.glVertex3f(2, 0, 0);

gl.glNormal3f(0, 0, -1);
gl.glVertex3f(0, -2, 0);
}

else
{
// triangle 1 [1, 2, 3]
gl.glNormal3f(0, 0, 1);
gl.glVertex3f(-2, 0, 0);
gl.glVertex3f(2, 0, 0);
gl.glVertex3f(0, 2, 0);

// triangle 2 [1, 2, 4]
gl.glNormal3f(0, 0, -1);
gl.glVertex3f(-2, 0, 0);
gl.glVertex3f(2, 0, 0);
gl.glVertex3f(0, -2, 0);
}

gl.glEnd();
}

private void drawNormals(final GL gl)
{
gl.glDisable(GL.GL_LIGHTING);
gl.glBegin(GL.GL_LINES);

if (SMOOTH)
{
gl.glColor3f(1, 1, 0);
// vertex normals of triangle 1 [1, 2, 3]
// common normal on vertex 1 for triangle 1 and 2
gl.glVertex3f(-2, 0, 0);
gl.glVertex3f(-2, 0, 1);
// common normal on vertex 2 for triangle 1 and 2
gl.glVertex3f(2, 0, 0);
gl.glVertex3f(2, 0, 1);
gl.glColor3f(0, 1, 0);
gl.glVertex3f(0, 2, 0);
gl.glVertex3f(0, 2, 1);

gl.glColor3f(1, 0, 0);
// vertex normals of triangle 2 [1, 2, 4]
/* normals for vertex 1 and 2 already exist
gl.glVertex3f(-2, 0, 0);
gl.glVertex3f(-2, 0, -1);
gl.glVertex3f(2, 0, 0);
gl.glVertex3f(2, 0, -1);
*/
gl.glVertex3f(0, -2, 0);
gl.glVertex3f(0, -2, -1);
}

else
{
gl.glColor3f(0, 1, 0);
// normal of triangle 1 [1, 2, 3]
gl.glVertex3f(0, 1, 0);
gl.glVertex3f(0, 1, 1);

gl.glColor3f(1, 0, 0);
// normal of triangle 2 [1, 2, 4]
gl.glVertex3f(0, -1, 0);
gl.glVertex3f(0, -1, -1);
}

gl.glEnd();
gl.glEnable(GL.GL_LIGHTING);
}

public void init(final GLAutoDrawable drawable)
{
final GL gl = drawable.getGL();

gl.glEnable(GL.GL_DEPTH_TEST);

gl.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE);

gl.glEnable(GL.GL_LIGHT0);
gl.glEnable(GL.GL_LIGHTING);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, FloatBuffer.wrap(new float[]{0, 0, 0, 1}));
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, FloatBuffer.wrap(new float[]{1, 1, 1, 1}));
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, FloatBuffer.wrap(new float[]{1, 1, 1, 1}));
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, FloatBuffer.wrap(new float[]{0, 0, 6}));

gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, FloatBuffer.wrap(new float[]{0.2f, 0.1f, 0, 1}));
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, FloatBuffer.wrap(new float[]{0.6f, 0.2f, 0.1f, 1}));
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, FloatBuffer.wrap(new float[]{0.6f, 0.2f, 0.1f, 1}));
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, FloatBuffer.wrap(new float[]{0, 0, 0, 1}));
gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, 50);

gl.glMatrixMode(GL.GL_PROJECTION);
new GLU().gluPerspective(50, drawable.getWidth() / drawable.getHeight(), 1, 1000);
gl.glMatrixMode(GL.GL_MODELVIEW);

gl.glLineWidth(3);
}

private boolean isWoken()
{
try
{
}

catch (InterruptedException e)
{
e.printStackTrace();
}

return true;
}

public void reshape(
final GLAutoDrawable drawable,
final int x,
final int y,
final int width,
final int height)
{
}

public void displayChanged(
final GLAutoDrawable drawable,
final boolean mode,
final boolean device)
{
}
}


[Edited by - hoonsworld on January 28, 2008 3:01:33 PM]

Share on other sites
Yes, this is a fundamental problem in OpenGL. In order for the lighting to look good the polygon winding and normals have to be consistent. I haven't tested this, but could probably solve the problem like this:

Draw front facing polygons:
- Enable back face culling
- Draw the scene

Draw back facing polygons:
- Flip the normals
- Enable front face culling
- Draw the scene again

Share on other sites
Quote:
 Is there a openGl statement to correct this mistake?

there is also:

glFrontFace(GLenum mode);

(for mode: GL_CCW, GL_CW i.e. counterclockwise and clockwise respectively)
to match the simple, hardcoded and constrained nature of your sample code.

Editorial comment:It is a fundamental issue the programmer (or modeller?) should/may account for with regard to 3d geometry in both Opengl and DirectX.

Share on other sites
Quote:
 Original post by deathkrushYes, this is a fundamental problem in OpenGL.

I won't say this is a problem in OpenGL. Polygon winding and normals need not to be consistant. In fact, if the normals are correct, your 3D model can still look good even its polygons have a lousy winding.

For hoon: When we use averaged normals, we are expecting a smooth surface. If you are not, why are you averaging your normals in the first place? The polygons share the same vertices doesn't mean they need to share normals. And, if your artist give you a 3D model that share/not-share normals, just let it be.

For more details about how and when to average the normals, please refer to
http://www.xmission.com/~nate/smooth.html

Share on other sites
Hi

Quote:
 Original post by ma_htyThe polygons share the same vertices doesn't mean they need to share normals.

Yes, I tried it with a second inverse normal on the shared vertices and it works correct :)
I thought it exist an OpenGL statement for this problem :(

OK, now I write a net algorithm to recognize the opposite wound triangles over the adjacent edges and their vertex order. A wound triangle obtains a boolean flag for usage the inverse normal.

I think it is a good idea :)
Or are there other ideas?

Here is our mini project:
gui3d.org

Best regards from Hamburg
hoon

Share on other sites
The correct way is to obtain a 3D model with a consistant winding, instead of struggling about the winding problem. In general, I can easily construct a 3D model with a winding so ambiguous that impossible to be fixed. Therefore, no matter how much effort you spend on your routine, you cannot handle all cases.

By the way, any 3D model designing software or 3D model scanner will, try their best to, produce a 3D model with consistant winding. Why bother?

Share on other sites
Arr......

In case your 3D model have its back-face visible, you can command OpenGL to flip the normal whenever the face is backward facing via

glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1.0);

Share on other sites
Hi ma_hty :)

In the example I set up the statement:

gl.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE);

It works correct but it is not the solution for the problem :(

Yes, you are right! Any 3D modeler will try to produce consistant windings. But our program/engine works with simulation data too :) This simulation data based on finite elements. The user has the full control about the winding for each element (polygon) or element groups. Here are 2 links for the background and a little simulation video:
en.wikipedia.org/wiki/Finite_element_analysis
ncac.gwu.edu

This is the reason for our effort.
The inconsistent winding is a feature in our engine but I have to visualize it correctly.

OK, Thanks again :)

Regards from Germany
hoon

Share on other sites
May I ask you what is the role of winding in your application? How is it get related to user's interaction? If you can give more information, may be I can help.

Share on other sites
Hi :)

In our program we have to manage the windings. The windings are important for the
most finite element solvers. These solvers are very sophisticated programs in
view of mathematics and physics.

For example: An airbag has internal pressure!
But in which direction does the pressure have an effect?
The user has to set up this information over the windings or the finite
element normals. The following video shows an airbag simulation:
airbag deployment

This is not the only reason for the role of winding. There are contact problems, and many of much other ...
In our program the user can select one or several polygons or groups and can invert the winding direction.
The selecting is possible over picking or an intelligent fence mechanism with box or polygon selecting.

For flat shading it is not a problem but the smooth shading is difficult :(

I think, I write a net algorithm to recognize the opposite wound triangles or quads!?

Regards
hoon

1. 1
2. 2
Rutin
18
3. 3
4. 4
5. 5

• 14
• 12
• 9
• 12
• 37
• Forum Statistics

• Total Topics
631432
• Total Posts
3000040
×