Jump to content
  • Advertisement
Sign in to follow this  
MickeMan

Smooth shading problem

This topic is 3887 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

Hi I have a class called Model which has index, vertex, uvcoords and face normals. I can successfully load meshes and the render function looks like this:
void Model::Render()
{
	glPushMatrix();
	
	glTranslatef(pos_x, pos_y, pos_z);
	
	glShadeModel(GL_SMOOTH);

	for(int i = 0; i < numfaces; i++)
	{
		glBegin(GL_TRIANGLES);								
			glNormal3f(pvfaceNormals.x, pvfaceNormals.y, pvfaceNormals.z);
			glVertex3f( vertices[index.a].x, vertices[index.a].y, vertices[index.a].z);
			glVertex3f( vertices[index.b].x, vertices[index.b].y, vertices[index.b].z);
			glVertex3f( vertices[index.c].x, vertices[index.c].y, vertices[index.c].z);

		glEnd();
	}
	glPopMatrix();
}
glNormal3f defines the Face normal for each triangle being drawn. glVertex3f specifies the vertexes for our triangle I thought defining our facenormal would be enough (and the lighting works because of this) for smoothing to work. Some claim that you only need the triangle coordinates and the face normal to make a good smoothing, calculating the vertex normals as we go. But I dont really want to calculate the vertex normals for each render and would prefer loading the normals from file, already defined. So I have all my vertex normals, called pvVertexNormals*, how do I define the vertex normals inside the Render function? Or am I wrong when I think the reason the smooth shading doesnt work because I havent defined the vertex normals? Thank you.

Share this post


Link to post
Share on other sites
Advertisement
For smooth shading to work properly you have to pass a normal per vertex and not only per triangle as you are currently doing.
So before each glVertex call you would have to call glNormal and pass the per vertex normal.
And while we are discussing this let me point out that using immediate mode as you are doing is the slowest possible way to draw models. Using vertex buffer objects (VBO) and using glDrawElements or something similar is the prefered way.

Share this post


Link to post
Share on other sites
OpenGL will not calculate vertex normal for you. You have to do it yourself. And, to calculate vertex normal from face normal, you need to gather all face normals of the same vertex, and then the averaged face normal will be your vertex normal.

Why don't you just export your model with vertex normal? Most (may be all) of the 3D design software offer this.

Share this post


Link to post
Share on other sites
Thank you for your replies.

Quote:

Why don't you just export your model with vertex normal? Most (may be all) of the 3D design software offer this.


Yes, I use the ASE format which has the vertex normal data and I load those from the file. The question was really how to put them into our rendering function.

Youre saying that an implementation would look like this:


for(int i = 0; i < numfaces; i++)
{
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glNormal3f(pvfaceNormals.x, pvfaceNormals.y, pvfaceNormals.z);
glNormal3f(pvVertexNormals[index.a].x, pvVertexNormals[index.a].y, pvVertexNormals[index.a].z);
glVertex3f( vertices[index.a].x, vertices[index.a].y, vertices[index.a].z);
glNormal3f(pvVertexNormals[index.b].x, pvVertexNormals[index.b].y, pvVertexNormals[index.b].z);
glVertex3f( vertices[index.b].x, vertices[index.b].y, vertices[index.b].z);
glNormal3f(pvVertexNormals[index.c].x, pvVertexNormals[index.c].y, pvVertexNormals[index.c].z);
glVertex3f( vertices[index.c].x, vertices[index.c].y, vertices[index.c].z);

glEnd();
}



Is that correct?


Quote:

Using vertex buffer objects (VBO) and using glDrawElements or something similar is the prefered way.


Why dont we stay on this topic for a while. I've been using the OpenGL bible for reference and it doesnt really tell me which way to go on complex models.
How does VBO use and interpret Normal data?

Share this post


Link to post
Share on other sites
The source of your last post is almost correct. Setting the face normal isn't as you currently do is isn't necessary as this will be overwritten by the directly following glNormal call.

VBOs are just buffers of memory located on your gfx card. You create a VBO, load data into it and set pointers to the data with glVertexPointer, glNormalPointer, etc.. You then draw with glDrawElements passing your indices. By the way the indices can also be stored in its own VBO.

Share this post


Link to post
Share on other sites
I toyed around with VBO and am able to draw a custom mesh with the following render code:


glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vVerts);
glDrawElements(GL_TRIANGLES, numfaces*3, GL_UNSIGNED_SHORT, uiIndexes);


vVerts being a GLfloat (*)[3] with our vertices
and uiIndex being GLushort [numfaces*3] holding index data for all triangles.

Next step is to implement the UV coordinates which I'm pretty certain on how to do that.

Question is why is this way more efficient? Its all still a matter of drawing vertices on the screen, isnt it?

But to stick to the topic: smoothing

Im guessing I should specify vertex normals to make smoothing work. But youre also saying that we dont need any face normals? Or do we?

If we do need the face normal for anything please tell me for what purpose and how to define the face normal when you have vertex normals already defined.

Share this post


Link to post
Share on other sites
When passing vertices in immediate mode, you encounter a bottleneck on your way to the gfx card. So, that's where using VBOs comes in handy.

If your ASE model already produces vertex normals for you, then there is no need for surface normals. If not, then they are required, because a vertex normal is usually calculated in one of 2 ways:

1) A normalized sum of the surface normals (surface normals normalized or not, apparently the results are mostly the same)
2) An average of the normalized surface normals

If you do have to compute this yourself, I have personally gotten better results with the second option, as it seems to eliminate certain lighting artifacts in extreme cases (very dark or very bright).

Share this post


Link to post
Share on other sites
Quote:
Original post by MickeMan
I toyed around with VBO and am able to draw a custom mesh with the following render code:

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vVerts);
glDrawElements(GL_TRIANGLES, numfaces*3, GL_UNSIGNED_SHORT, uiIndexes);

...


This is not actually using VBOs; what you do here is using vertex arrays since vVertes is a pointer to client memory! For VBOs you would have to create a vertex buffer object and upload the data to it, bind the buffer and then use glVertexPointer and others specifying an offset into you VBO and not a client memory pointer directly.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!