PDA

View Full Version : Normal question (well, kinda weird actualy)

c_olin
07-17-2003, 02:15 PM
I wrote a program that can load and render .obj files with textures, but the .obj file does not have normals data, is there a way to calculate normals?

how can i draw an .obj with lighting?

thanks!

zix99
07-17-2003, 02:34 PM
The normals is an equation to calculate it for each verticy, i don't know it. I use DirectX calls to calculate all my normals for me.

c_olin
07-17-2003, 07:13 PM
im trying to stick with opengl, is there a way to calculate normals in opengl?

Some guy
07-17-2003, 07:53 PM
See appendix E from the red book, also recommended to zix99 so he does not have to depend on some helper functions. http://www.opengl.org/discussion_boards/ubb/smile.gif
If you really do not want to make the effort is low level libraries like OpenGL and Direct3D not what you want.

You probably need to calculate the cross product. Here is two libraries with that function and others. http://plib.sourceforge.net/sg/ http://www-2.cs.cmu.edu/~ajw/doc/svl.html

Once you have the normals can you use the standard OpenGL lights.

errno
07-17-2003, 10:38 PM
the normal of a vertex is the normalized sum of the normal of the triangles that share the vertex.

for each triangle
normal[triangle.vertex[0]] += triangle.normal
normal[triangle.vertex[1]] += triangle.normal
normal[triangle.vertex[2]] += triangle.normal
end for

gvm
07-18-2003, 01:10 AM
it's strange that there is not normals in obj file! i using maya's exported obj models and they contain normals data!
like this: vn 1 0 0

zix99
07-18-2003, 03:22 PM
thanks some guy, i'll try not to use DX this time. Its a pain to use DX for just ONE call in my whole program.

c_olin
07-18-2003, 06:20 PM
simple math question, it says that the normal = [v1 - v2] × [v2 - v3].

How do you subtract 2 vectors? is it: (x1+y1+z1 - x2+y2+z2) or: (x1-x2 y1-y2 z1-z2)
i think its (x1-x2 y1-y2 z1-z2) because its the only one resulting in a vector, but imnot sure... and also, how do you muliply?

07-18-2003, 11:35 PM
The cross product of 2 given vectors v1 and v2 is as follows:
v1 x v2 = ( v1.x*v1.z - v1.z*v2.y , v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x )

I think it would be better for you if you get a math book and take a look at vector math, so you can understand where this formula comes from.

Some guy
07-18-2003, 11:38 PM
Here is a description on how to calculate the cross product, its really very simple. http://www.lighthouse3d.com/opengl/maths/index.php3?crossproduct
Note that the x means cross pruduct and not multiplication.

If you need some reference material about matrices could perhaps the matrix FAQ be used. http://www.j3d.org/matrix_faq/

07-18-2003, 11:41 PM
Uh, I forgot something :P.
Yeah you're right, the second formula is the correct for vector substraction.

c_olin
07-23-2003, 12:39 PM
don't get to mathy on me, im only in ninth grade!

but now i jsut realsized somthing, im working with triangles... is it done the same way?

DJSnow
07-23-2003, 03:26 PM
while exporting OBJ files from your favorite 3D-modeller app it is possible, in the most apps, to "configure" if you want to have normals.

and yes, you have to calculate the cross-product of the vectors, describing a triangle. this is called "the normal vector"; it's that vector which "stands" perpendicular on a triangle.
by applying this normal to a polygon, you get lightning - but keep in mind that, if you use this way, you have so called "face normals" - this means, all vertices of a triangle have the same normal; if you want to do vertex normals, this means different normals per each vertex, you have to calculate the "average" normal for each vertex by calculating the average values of all faces, which are connected to this vertex.

[This message has been edited by DJSnow (edited 07-23-2003).]

c_olin
07-23-2003, 06:29 PM
no, i mean im drawing in triangles, not quads... can you explain the formula for find a normal of a triangle??

thanks!

dorbie
07-23-2003, 09:15 PM
It's not subtracting vectors, it's subtracting points to produce edge vectors.

The cross product of two triangle edge vectors will produce the normal of the triangle.

c_olin
07-23-2003, 09:48 PM
so i would use this formula for any 2 points on the triangle?? :
v1 x v2 = ( v1.x*v1.z - v1.z*v2.y , v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x )

dorbie
07-23-2003, 10:26 PM
No.

You need two vectors, generated from 3 points. You then do a cross product on the vectors.

Triangle consisting of 3 points p1 p2 p3

v1 = p2 - p1
v2 = p3 - p2

This subtraction is simply (x2-x1, y2-y1, z2-z1)

normal = v1 x v2

Now this x means a vector cross product.
http://mathworld.wolfram.com/CrossProduct.html

The code would look something like this:

normalx = v2.y*v1.z - v2.z*v1.y;
normaly = v2.z*v1.x - v2.x*v1.z;
normalz = v2.x*v1.y - v2.y*v1.x;

Finally you need to normalize, using pythagoras theorem to compute the length of the vector then divide x, y and z by the length of the vector.

length = sqrtf( normalx * normaly + normaly * normaly + normaly * normaly )

normalx /= length
normaly /= length
normalz /= length

This is winding dependent (the normal direction (out or in) will depend on the vertex winding order, clockwise vs anti-clockwise. If this is wrong for your data then reverse the vector directions with the subtractions.

P.S. there is a typo in your cross product equation.

[This message has been edited by dorbie (edited 07-24-2003).]

07-24-2003, 02:30 AM
Originally posted by dorbie:

length = sqrtf( normalx * normaly + normaly * normaly + normaly * normaly )

Excellent explanation but the above should be
length = sqrtf( normalx * normalx + normaly * normaly + normalz * normalz )

c_olin
07-24-2003, 09:11 AM
Originally posted by dorbie:
No.

You need two vectors, generated from 3 points. You then do a cross product on the vectors.

Triangle consisting of 3 points p1 p2 p3

v1 = p2 - p1
v2 = p3 - p2

This subtraction is simply (x2-x1, y2-y1, z2-z1)

normal = v1 x v2

Now this x means a vector cross product.
http://mathworld.wolfram.com/CrossProduct.html

The code would look something like this:

normalx = v2.y*v1.z - v2.z*v1.y;
normaly = v2.z*v1.x - v2.x*v1.z;
normalz = v2.x*v1.y - v2.y*v1.x;

Finally you need to normalize, using pythagoras theorem to compute the length of the vector then divide x, y and z by the length of the vector.

length = sqrtf( normalx * normaly + normaly * normaly + normaly * normaly )

normalx /= length
normaly /= length
normalz /= length

This is winding dependent (the normal direction (out or in) will depend on the vertex winding order, clockwise vs anti-clockwise. If this is wrong for your data then reverse the vector directions with the subtractions.

P.S. there is a typo in your cross product equation.

[This message has been edited by dorbie (edited 07-24-2003).]

The website that you posted has a different equation then you! on theirs, there is no x's... you don't have to give me the code, jsut the equation!

thanks!

c_olin
07-24-2003, 02:15 PM
*bump

john
07-24-2003, 04:15 PM
Don't bump topics; it is childish and counter-productive. It is also unnecessary in a forum that uses cookies to keep track of new messages.

Think about what would happen if everyone bummped their topic every time it wasn't top.

Oh, and you didn't ask a question: you merely stated an observation.

c_olin
07-24-2003, 05:29 PM
Im sorry, but it was half way down the page.

john
07-24-2003, 05:58 PM
I can read more than half a page before my brain hurts. <nods wisely>

You still didn't ACTUALLY ask a question, btw.

john
07-24-2003, 06:08 PM
Maybe you are confused by Wolfram's notation. The two vectors in his notation are u and v. The components for U are thus U_x (U subscript x), U_y and U_z. So... the "x's" are actually U_x and V_x.

c_olin
07-24-2003, 06:34 PM
but compare the Wolfram equation to Dorbie's equation:
normalx = v2.y*v1.z - v2.z*v1.y;
normaly = v2.z*v1.x - v2.x*v1.z;
normalz = v2.x*v1.y - v2.y*v1.x;

they are different!

Do i use Wolfram's or Dorbie's?

john
07-24-2003, 07:00 PM
hello,

they are the same equation, actually.

check out the equation: http://mathworld.wolfram.com/c3img1196.gif

that is the same as what dorbie wrote, albeit using a different notation.

x'hat (x with a caret (^) above it) et al are basis vectors; it indicates the magnitude in the corresponding direction.

I apologise for being snakey before.

c_olin
07-24-2003, 07:03 PM
no, i deserved it.

i still don't quiet get it, but ill just go with dorbies Math, thansk for the help!

john
07-24-2003, 07:38 PM
no, no, getting it is all part of the trick bcause then you'll understand MORE stuff, and that has to be a good thight.

It's kinda like this: the decimal number 1234 can also be written as 1*1000 + 2*100 + 3*10 + 4*1, right? Well, a three-dimensional vector <1, 2, 3> can be written as 1*<1, 0, 0> + 2*<0, 1, 0> + 3*<0, 0, 1>. So... when dorbie says that the x component of a normal is A (where A is u.y*u.z - u.z*u.y), the y component is B and the z component is C, then what he's saying is you can decompose the vector like so: A*<1, 0, 0> + B*<0, 1, 0> + C*<0, 0, 1>. the X^ from wolfram is just short-hand for writing <1, 0, 0>, i.e. a vector in the x-direction.

now, does THAT make sense?

cheers,
John

c_olin
07-24-2003, 08:08 PM
woah, ill print that out and read it a dozen times before i go to bed... lol

im only in algebra 1!

c_olin
07-24-2003, 08:53 PM
ok, i think i understand, and i got it to code... he it is:

for(i = 0; i < h1.num_faces; i++)
{
faces[i].normalx = vertices[faces[i].vertexindices[1]].y * vertices[faces[i].vertexindices[0]].z - vertices[faces[i].vertexindices[1]].z * vertices[faces[i].vertexindices[0]].y;
faces[i].normaly = vertices[faces[i].vertexindices[1]].z * vertices[faces[i].vertexindices[0]].x - vertices[faces[i].vertexindices[1]].x * vertices[faces[i].vertexindices[0]].z;
faces[i].normalz = vertices[faces[i].vertexindices[1]].x * vertices[faces[i].vertexindices[0]].y - vertices[faces[i].vertexindices[1]].y * vertices[faces[i].vertexindices[0]].x;
float length = sqrtf( faces[i].normalx * faces[i].normalx + faces[i].normaly * faces[i].normaly + faces[i].normalz * faces[i].normalz );
faces[i].normalx /= length;
faces[i].normaly /= length;
faces[i].normalz /= length;
}

but weird problems, i get weird triangles, some black and some regular whenever i enable lighting... please help!

[This message has been edited by c_olin (edited 07-24-2003).]

john
07-24-2003, 09:45 PM
hello,

Why is this important to know? Because if you haev two vectors, u and v, and computed the crossproduct(u, v) and crossproduct(v, u) (note the change in ordering), then you'll get _two vectors in opposite directions_.

So, the problem you have, I think, is that you're sometimes computing the wrong normal.

to fix this,
1) decide on a winding order for your veritices. I suggest counter-clockwise (the opengl default).
2) make sure all your triangles are in couter-clockwise order, and
3) make sure you compute the normals in the right order for your winding.

for example, if you choose counter clockwise, then the front side of your triangle would look like

0
|\
| \
1--2

(0, 1, 2 travel counterclockwise). You could compute the normal as crossProduct(1-0, 2-0) and get a normal pointing towards you (since you're looking down at this triangle).

If you ensure that your winding order is ALWAYS clockwise then you can always comute your nromals that way and gauarantee they point outwards.

hope this helps
chees
JOhn

c_olin
07-25-2003, 07:04 AM
hmm... i can't change the order at wch it is drawn, because its being read from a file. but, if i used quads instead, would i not have to do that?

john
07-26-2003, 07:39 PM
changing to quads won't make a difference because you still have to pick to vectors for the dot product.

reading from a file shouldn't be an impediment on Correct Vector Ordering, for two reasons
- you can always buffer, and;
- the file should be correct, not ad hoc.

cheers
john

c_olin
08-13-2003, 07:34 PM
ok, im still working on this.... this is my code:

for(i = 0; i < h1.num_faces; i++)
{
faces[i].normalx = vertices[faces[i].vertexindices[1]].y * vertices[faces[i].vertexindices[2]].z - vertices[faces[i].vertexindices[1]].z * vertices[faces[i].vertexindices[2]].y;
faces[i].normaly = vertices[faces[i].vertexindices[1]].z * vertices[faces[i].vertexindices[2]].x - vertices[faces[i].vertexindices[1]].x * vertices[faces[i].vertexindices[2]].z;
faces[i].normalz = vertices[faces[i].vertexindices[1]].x * vertices[faces[i].vertexindices[2]].y - vertices[faces[i].vertexindices[1]].y * vertices[faces[i].vertexindices[2]].x;
float length = sqrtf( faces[i].normalx * faces[i].normalx + faces[i].normaly * faces[i].normaly + faces[i].normalz * faces[i].normalz );
faces[i].normalx /= length;
faces[i].normaly /= length;
faces[i].normalz /= length;
}

still doesnt work!

[This message has been edited by c_olin (edited 08-13-2003).]