PDA

View Full Version : is this a problem with normals?



Pody
09-19-2002, 06:50 AM
In my program I first render a sphere made of triangles, then I subdivide all the triangles using their centroids, and mid points of the edges.
Then I recalculate the normals and render it.
When I render the subdivided sphere I get some strange effects that you can see here
http://spazioinwind.libero.it/galilee/

Do you think it's a problem with the normals? (I calculate them in the same way as for the initial sphere).
The subdivided sphere should look the same as the first one, shouldn't it?

coredump
09-19-2002, 08:10 AM
hmmm...well, whatever you did, it looks like with a little tweaking you made the first golf-ball generator! did you try viewing it w/o lighting? then you could tell if the culprit is your subdivide function or your normal-generating function.

b

harsman
09-19-2002, 09:02 AM
It looks like your changing the winding order of the faces you add so that the new normals are fliped. Try reversing the vertex order in the faces you create when subdividing.

Pody
09-20-2002, 12:51 AM
I did some step by step tests, and the normals should be calculated well.
The polygons are also in the same order.
http://www.opengl.org/discussion_boards/ubb/frown.gif

harsman
09-20-2002, 01:25 AM
Try flipping _all_ your normals. Since you say you use the same code to calculate all the normals, this should be simple. If the dark spots move, you know they're caused by incorrect normals. Since the spots only appear when you subdivide, the subdivision must be causing the incorrect normals. If this is the case, ither you normal generation can't handle the new faces because it's bugged in some way, or (which I still think is the problem) you switch winding order of the vertices when you add faces. You might not switch winding order on *all* faces but my guess is it happens sometimes. If all else fails, post your code.

Pody
09-20-2002, 03:58 AM
I tried flipping the normals, but everything goes black.
Here's how i calculate the centroid and the midpoint of the edges for each triangle
centroid[j]=(el->vertTab[v[0]+j]+el->vertTab
for (j=0;j<3;j++) //calculate the coordinates of the centroid of the triangle
{// and new midpoint vertexes
[v[1]+j]+el->vertTab[v[2]+j])/3.0;
mid0[j]=(el->vertTab[v[0]+j]+el->vertTab[v[1]+j])/2.0;//midpoint of edge 0-1
mid1[j]=(el->vertTab[v[1]+j]+el->vertTab[v[2]+j])/2.0;//midpoint of edge 1-2
mid2[j]=(el->vertTab[v[2]+j]+el->vertTab[v[0]+j])/2.0;//midpoint of edge 2-0
}

Now i add the new vertexes v(centroid,mid0, mid1, mid2) to el->vertTab, and put in pos[0],pos[1], pos[2],pos[3] the position where these vertexes are in in el->vertTab

i then add the indexes of the vertexes of the new triangles
addMeshIndexes(el,v[0],pos[0],pos[3]);
addMeshIndexes(el,pos[0],v[1],pos[3]);
addMeshIndexes(el,pos[3],v[1],pos[1]);
addMeshIndexes(el,pos[3],pos[1],v[2]);
addMeshIndexes(el,v[2],pos[2],pos[3]);
addMeshIndexes(el,pos[2],v[0],pos[3]);

and calculate the normals like this:
GLfloat v[3];
GLfloat *ptr;
int count;
v[0]=v[1]=v[2]=0;

findFaces(el,vertNum);//finds the faces incident on the vertex vertNum and put them in a list in el->faces
f=el->faceList;
count=0;
while(f)
{
calcFaceNormals(el,f->face,v);//calculates the normal of the face pointed byt f->face and add its values to v
count++;
f=f->next;
}
if (count)
{//mediates the values of the normals
v[0]/=count;
v[1]/=count;
v[2]/=count;
}

ptr=&el->normalTab[el->normalTabCur];
//adds the coordinates of the normal to che normal vector
*ptr++=v[0];*ptr++=v[1];
*ptr++=v[2];
el->normalTabCur+=3;

This is the function calcFaceNormals:
void Models::calcFaceNormals(listModels *el,int face, GLfloat v[3])
{
GLfloat vA[3],vB[3];

int vert[3];
float x,y,z;
int j;

findVertexesOfFace(el,face,vert);

for (j=0;j<3;j++)
{
vA[j]=el->vertTab[vert[0]+j]-el->vertTab[vert[1]+j];
vB[j]=el->vertTab[vert[1]+j]-el->vertTab[vert[2]+j];
}
calculateNormalComponents(vA,vB,x,y,z);

v[0]+=x;
v[1]+=y;
v[2]+=z;
}

And this is calculateNormalComponents
void Models::calculateNormalComponents(GLfloat vA[3],GLfloat vB[3],float &x,float &y,float &z)
{
float mod;
float tolerance=0.00001f;

x=vA[1]*vB[2]-vA[2]*vB[1];
y=vA[2]*vB[0]-vA[0]*vB[2];
z=vA[0]*vB[1]-vA[1]*vB[0];

mod=sqrt(x*x+y*y+z*z);

x/=mod;
y/=mod;
z/=mod;

if ((x>0 && x<tolerance) &#0124; &#0124;(x<0 && x>-tolerance))
x=0;
if ((y>0 && y<tolerance) &#0124; &#0124;(y<0 && y>-tolerance))
y=0;
if ((z>0 && z<tolerance) &#0124; &#0124;(z<0 && z>-tolerance))
z=0;
}

Pody
09-20-2002, 04:02 AM
ehm the line
"centroid[j]=(el->vertTab[v[0]+j]+el->vertTab[v[1]+j]+el->vertTab[v[2]+j])/3.0;"
is also inside the "for" statement.
and
pos[0] holds the index of the vertex mid0
pos[1] of mid1
pos[2] of mid2
and pos[3] of the centroid

harsman
09-20-2002, 06:09 AM
I'm having a hard time following your code, so this is more of a guess than anything else. Your normal calculation seems ok.

However, it seems like you don't remove the old triangles and replace them with new ones when you subdivide. That's hard to tell however.

Then there's this statement at the top:


[v[1]+j]+el->vertTab[v[2]+j])/3.0;

which doesn't do anything at all. Here's what i suggest:

*Try rendering with glPolygonMode(GL_FRONT,GL_LINE). That should show you if it's the position of the vertices, the indices, or the normals that are at fault.

* Try rendering your normals as lines. Good thing to do to see any incorrect normals.

* Please use a vector struct or class instead of writing everything in loops. Your code will be easier to read *and* more efficient.

Pody
09-20-2002, 06:52 AM
the line which doesn't make sense was the continuation of
"centroid[j]=(el->vertTab[v[0]+j]+el->vertTab
"
i made a mistake while cut-and-pasting.
Well, I actually delete the old faces.
in el->vertTab I store the vertices, in el->meshIndexes the indexes of the vertexes for each face, and I delete el->meshIndexes at the beginning of the subdivision routine.
So i only add the indexes of the new triangles.

Regarding the vector class/struct, what do you mean?I use vectors, one for vertexes, one for indexes, one for edges and one for faces (i store data with winged-edge data structure)

I put 2 more complete examples at
spazioweb.inwind.it/galilee
It seems that even in the original cube the normals are a bit strange: you can see the edges...
It seems the illumination changes quite drastically when you are not on an egde.

Thanks for your help and time

coredump
09-20-2002, 07:54 AM
that subdivision looks kind of jumbled...almost as if some triangles overlap others.

b

Pody
09-20-2002, 09:30 AM
they don't overlap

Miguel_dup1
09-20-2002, 03:04 PM
I did not read every post on here. But I can see you have the right values for your normals. I am sure someone already told you to use glShadeModel( GL_SMOOTH ); so i will skip on this suggestion. But if none told you, then try that out.
What you need to do, however, is to compute the average normals. You compute them by simply adding the normal vertices of every shared vertex in your mesh and then divide them by the number of added normal vertices...


[This message has been edited by mancha (edited 09-20-2002).]

Pody
09-21-2002, 04:47 AM
I use glShadeModel(GL_SMOOTH),
and i calculate the average normals (in the lines
v[0]+=x;
v[1]+=y;
v[2]+=z;

and
v[0]/=count;
v[1]/=count;
v[2]/=count;