PDA

View Full Version : problem with normals computation



airseb
01-23-2005, 01:08 PM
Hi !
I try to calculate normals per vertex, but i have wrong values. Can you help me ?
this is an idea of the result :
par vertex -0.57735 -0.57735 -0.57735
par vertex -0.0901489 0.243461 -0.965712
par vertex 0.488888 -0.637189 -0.595801
par vertex -0.57735 -0.57735 -0.57735
par vertex -0.57735 -0.57735 -0.57735
par vertex -0.57735 -0.57735 -0.57735
par vertex -0.57735 -0.57735 -0.57735
par vertex -0.451648 0.88473 -0.115186
par vertex -0.57735 -0.57735 -0.57735

this my code :

for (polyCounter = 0 ; polyCounter< myObjects[counterObj].nbVertices ; polyCounter++)
{
myObjects[counterObj].perVertexNormals[polyCounter].x=0 ;
myObjects[counterObj].perVertexNormals[polyCounter].y=0 ;
myObjects[counterObj].perVertexNormals[polyCounter].z=0 ;

for (polyCounter2 = 0 ; polyCounter2< 100 ; polyCounter2++)
{
tableIndices[polyCounter][polyCounter2]= -1 ;//-1 because 0 is used as an indice
}
}

int nIndice = 0 ;
int counter, j=0 ;
do
{
for(counter=0 ; counter < myObjects[counterObj].nbPoly ; counter++)
{
for(i=0 ; i<3 ; i++)
{
if(myObjects[counterObj].myIndices[counter][i]==nIndice)
{
normalIndice = (counter*3)+i ;/*thanks to this operation i can go from a two dimension array to a one dimension array*/
myObjects[counterObj].perVertexNormals[normalIndice].x += myObjects[counterObj].perFaceNormals[counter].x ;
myObjects[counterObj].perVertexNormals[normalIndice].y += myObjects[counterObj].perFaceNormals[counter].y ;
myObjects[counterObj].perVertexNormals[normalIndice].z += myObjects[counterObj].perFaceNormals[counter].z ;

/*if(myObjects[counterObj].myIndices[counter][i]==1)
cout<<"indice "<<myObjects[counterObj].perVertexNormals[normalIndice].x<<endl ;*/

tableIndices[nIndice][j]=normalIndice ;//array storing for a same vertex the number of indices

j++ ;
}
}
}
nIndice++ ;
j=0 ;
}
while(nIndice != (myObjects[counterObj].nbVertices-1)) ;

i=0 ;//counters
c=0 ;
c2=0 ;
do
{
do
{
do
{
if(i != c2)
{
myObjects[counterObj].perVertexNormals[tableIndices[c][i]].x += myObjects[counterObj].perVertexNormals[tableIndices[c][c2]].x ;
myObjects[counterObj].perVertexNormals[tableIndices[c][i]].y += myObjects[counterObj].perVertexNormals[tableIndices[c][c2]].y ;
myObjects[counterObj].perVertexNormals[tableIndices[c][i]].z += myObjects[counterObj].perVertexNormals[tableIndices[c][c2]].z ;
}
c2++ ;
}
while(tableIndices[c][c2] != -1) ;
i++ ;
c2=0 ;
}
while(tableIndices[c][i] != -1) ;
c++ ;
i=0;
}
while(c < myObjects[counterObj].nbVertices) ;

for(counter=0 ; counter < myObjects[counterObj].nbVertices ; counter++)
{
magnitude=sqrt(myObjects[counterObj].perVertexNormals[counter].x * myObjects[counterObj].perVertexNormals[counter].x +
myObjects[counterObj].perVertexNormals[counter].y * myObjects[counterObj].perVertexNormals[counter].y +
myObjects[counterObj].perVertexNormals[counter].z * myObjects[counterObj].perVertexNormals[counter].z) ;
myObjects[counterObj].perVertexNormals[counter].x /= magnitude ;
myObjects[counterObj].perVertexNormals[counter].y /= magnitude ;
myObjects[counterObj].perVertexNormals[counter].z /= magnitude ;
}

rgpc
01-23-2005, 02:45 PM
a. What is it that makes you think this is an ADVANCED question? This isn't even an Opengl question (it's a math question).

b. What makes you think there is something wrong with your Normals? They look fine to me.

SirKnight
01-23-2005, 07:50 PM
1) Have you tried using them in your lighting equation or just looked at the values? Just b/c they may "look weird" doesn't mean they're wrong.

2) It is a good idea for debugging to have a method to render your normals by using a small GL_LINES primitive so you can "see" the normals at each vertex.

-SirKnight

airseb
01-24-2005, 03:28 AM
rgpc >a)sorry next time i'll post in the other section.
b)I think the normals are wrong because there are calculated in the .ase file which contain the same objects. I searched some values that i have found with my computations and i don't find them in the .ase file. I find weird too of having the same values for several normals.

SirKnight > 1)idem
2)thanks i didn't think to it

jide
01-24-2005, 10:15 AM
If I'm not wrong (sorry to often say only hints not facts), ASE is just like 3ds. So this is not the same vectorial space (y points at -z, and z points to y). That might be why you don't have the same results. But I might be wrong.

Anyway, your code looks right.

airseb
01-24-2005, 10:56 AM
ok thanks for your help (i'm from france too :) )
if somebody can comfirm what jide has said, it would be helpful.

jide
01-24-2005, 12:26 PM
You can confirm on yourself, just with checking if the model you are loading appears as intended (under 3dsmax surely). Otherwise, it's simple to check if 2 of your 3 vertex x,y,z are swapped.

Hope this helps.

airseb
01-24-2005, 12:31 PM
i don't know if some vertices are swapped because some vertex values which i search don't appears in the .ase file. Thus my normals are false ?

jide
01-25-2005, 03:37 AM
Originally posted by airseb:
i don't know if some vertices are swapped because some vertex values which i search don't appears in the .ase file. Thus my normals are false ?Well, first try to see if your normals points out in the good direction like SirKnight said it. You'll easily see if they are swapped. If not, I guess your normals are well computed.

airseb
01-25-2005, 08:09 AM
i have find an error : i computed 'c' to 'a' vector and it seems that it's 'a' to 'c'
but i still not have the same values than the .ase file.
Other thing : when i put the type 'double' for the normals i have completly different values than with the type float. :confused:

jide
01-25-2005, 08:16 AM
Originally posted by airseb:
i have find an error : i computed 'c' to 'a' vector and it seems that it's 'a' to 'c'
but i still not have the same values than the .ase file.
Other thing : when i put the type 'double' for the normals i have completly different values than with the type float. :confused: I don't doubt on your mathematical knowledges, so ahve a look at your C knowledges. If you always have bad results after, then try the mathematic forum.

fpo
01-25-2005, 09:00 AM
Hi... here is a simple (fast and accurate) code for calculating vertex normals. All you need to do is accumulate face normals at each vertex and normalize it at end. Also it is good to add a weight to each face normal which is the angle from the triangle at that vertex (resolves cases like a cube where some vertices have more tris then others).


// initialize vertices data
for( i=0;i<m.numVerts;i++ )
{
vpos.add(pVector(m.verts[i].x,m.verts[i].y,m.verts[i].z));
vnorm.add(pVector(0,0,0,0));
}
// face normals
for( i=0;i<m.numFaces;i++ )
{
v1=vpos[m.faces[i].v[1]]-vpos[m.faces[i].v[0]];
v2=vpos[m.faces[i].v[2]]-vpos[m.faces[i].v[0]];
v3.cross(v1,v2);
v3.normalize();
fnorm.add(v3);
}

// vertex normals
for( i=0;i<m.numFaces;i++ )
{
for( j=0;j<3;j++ )
{
v1=vpos[m.faces[i].v[(j+1)%3]]-vpos[m.faces[i].v[j]];
v2=vpos[m.faces[i].v[(j+2)%3]]-vpos[m.faces[i].v[j]];
v1.normalize();
v2.normalize();

f=VECDOT(v1,v2);
f=acosf(f);

vnorm[m.faces[i].v[j]]+=f*fnorm[i];
}
}

// normalize vert normals
for( i=0;i<m.numVerts;i++ )
vnorm[i].normalize();

airseb
01-25-2005, 09:34 AM
ok thanks, but i would like to manage myself, otherwise what do you mean by "add a weight to each face normal" ?

fpo
01-25-2005, 03:00 PM
Consider a cube made of triangles. If cube is smooth, each vertex should have normal as a vector from center to vertex. Like (0.57735, 0.57735, 0.57735) or variantions of that just changing signs.

But a vertex from the cube can have from 3 to 6 triangles depeneding face organization as each quad face is made from 2 triangles (12 tris total for cube).

So if you have 3 tris you just average together the three face normals. But if one vertex has 4 tris for example you would be adding one normal twice and having a wrong result at end. So each normal you add you must be multiplied by the angle formed in trinagle at that vertex.

This angle (or normal weight if you prefer) is the acos(dot(v1,v2)) for v1 and v2 being the normlized adge vectors for the triangle starting at the vertex you are considreing.

Hope it helps you... just look at the above code and you will understand it.

airseb
01-26-2005, 04:54 AM
thanks but i have a few questions :
i don't understand : "So each normal you add you must be multiplied by the angle formed in trinagle at that vertex"

what are v1, v2, vnorm and m.faces in the for loop of the vertex normals ?

what you have described, does it work about another model than a cube ?

airseb
01-26-2005, 10:29 AM
i have found two errors : the sign of the per face normals was inverted and i didn't normalized the per face normals. But all what i get it's a sign inverted for the per vertex normals, i thought that it would change their values :-/ ...

fpo
01-26-2005, 11:29 AM
Yes it works for any mesh. Just explained in cube so you could understand the importance of the angle weight when you add the face normal to the vertices.

vnorm is vertex normal array. vnorm[i] is vertex normal for vertex i (0 to numverts-1).

v1 and v2 are the triangle edge vectors leaving from vertex you are considering at the moment. normalied other vertex minus current vertex in triangle.

The code is from a 3dsmax export plugin I have so it uses 3dsmax mesh classes.

m.faces[i].v[j] is an integer and means traingle face i (from 0 to numfaces-1) and vertex j (from 0 to 2).

Hope it helps... this is so simple stuff I'm sure you will get it correct soon.

airseb
01-27-2005, 01:16 PM
Originally posted by fpo:
Yes it works for any mesh. Just explained in cube so you could understand the importance of the angle weight when you add the face normal to the vertices.

vnorm is vertex normal array. vnorm[i] is vertex normal for vertex i (0 to numverts-1).

v1 and v2 are the triangle edge vectors leaving from vertex you are considering at the moment. normalied other vertex minus current vertex in triangle.

The code is from a 3dsmax export plugin I have so it uses 3dsmax mesh classes.

m.faces[i].v[j] is an integer and means traingle face i (from 0 to numfaces-1) and vertex j (from 0 to 2).

Hope it helps... this is so simple stuff I'm sure you will get it correct soon.to come back to the angle weight, let's suppose that we have two triangles, if i determine the weight normal at vertex 'A', how can i be sure that the normal weight will be determinate at the vertex 'A' of the other traingle ?
does normal weight works like a coefficient ?
i don't understand how works this system because it calculates the coefficient just for one vertex per face, can you explain me why ?

fpo
01-27-2005, 01:46 PM
Each vertex in the triangle will have its own angle. I call it weight as you just multiply the normal by the angle before adding it to the accumulated normal at the vertices.

Imagine a tiangle so thin it has a angle almost 0 at some vertex... it should not add much for the vertex normal at that vertex. In the other hand a triangle with 90 degrees on some vertex(corner of a box for example) should add a lot for the vertex normal there.

Also say two triangle with 45 degree should add the same as one trangle with 90 degree at a vertex. Got it? I can make a drawing for you if you want... mail me for that.

airseb
01-28-2005, 05:02 AM
i don't understand something :
vnorm[m.faces[i].v[j]]+=f*fnorm[i]; the same normal weight is given at the three vertices of the face ? if yes, let's suppose that the angle is of 20 degrees, the three angles of the triangle would be of 20 ? what is not possible for a triangle. there is surely something that i haven't understood, can you explain me what ?

fpo
01-28-2005, 05:42 AM
No each vertex in the triangle will have its own angle. Adding all 3 angles from the 3 vertices together will get 180.

If you check in my code, I compute the angle (f variable) for each vertex in traingle. So it is different for each vertex.

airseb
01-28-2005, 05:51 AM
yes but the lines :
v1=vpos[m.faces[i].v[1]]-vpos[m.faces[i].v[0]];
v2=vpos[m.faces[i].v[2]]-vpos[m.faces[i].v[0]]; will always compute the angle at vertex V[0] three times ?

fpo
01-28-2005, 08:15 AM
Sorry, should read:


v1=vpos[m.faces[i].v[(j+1)%3]]-vpos[m.faces[i].v[j]];
v2=vpos[m.faces[i].v[(j+2)%3]]-vpos[m.faces[i].v[j]]; PS. Updated original post so other people do not get confused with the mistake.

airseb
01-28-2005, 01:44 PM
ok thanks !

michagl
04-26-2005, 03:16 PM
thanks, good advice on the angle weights... i've never read that (much less thought about it) before. just saying someone else found this helpful and maybe bump it so someone else might find it helpful.