Smoothing & Tangents

Started by
10 comments, last by Toji 18 years, 7 months ago
Hi, My first question, how does smoothing exactly work? For example, I have a simple cube, rendered per triangle (GL_TRIANGLE or something) and using indices. So that would be 12 polygons, 8 vertices and 36 indices. The problem is that each vertex is used by 3 different polygons in this case. And each polygon has an entire different direction in case of a box of course. There are only 8 normals as well so when rendering a triangle it could pick a wrong direction. I could make 24 normals instead of 8 so that each triangle has its own normals but then I also have to use 24 vertices instead of 8 in case of using indices right? That would be a waste of memory and then I also get that ugly flat shading (although that's not bad for a box model, but what about cylinders...). How to solve this? The reason why I asked this was because I'm having troubles with bumpmapping. First I didn't really noticed it until I used it on a simple box model. The lighting just isn't right (weird highlighted stripes from the specular coefficient). I tried different shaders and approaches to calculate tangents/binormals but the problem didn't dissapear. So I thought it might had to do with the smoothing... I also noticed it with different exported models. I had a 3DS box exported from LightWave and another from Milkshape. The Lightwave box seemed to have correct bumpmapping/specular highlighting but there was painly noticable flat-shading. The Milkshape box was smooth shaded but the bumpmap effect looked like crap on it. Probably they export their 3DS differently... Greetings, Rick
Advertisement
Generally, if the modeling program exports the normals, you must tell it where you want sharp or smooth edges, and it will export the vertexes appropriately. The feature might be called "smoothing groups", but I don't know the details for your modeling software.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
In Lightwave you can disable/enable smoothing per surface/material. But I don't think it directly modifies normals or other geometry data as the lwo file is the the same for a smoothed or unsmoothed cube for example. When loading the file you know which polygons are smoothed, but you still have to do the math behind it yourself. And I'm a disaster with math, that's why I'm calling for help :)

Given the cube example from the first post, what to do to smooth it? And does it still work with TBN bump-mapping? Like I said, the Milkshape cube was smoothed (had only 8 vertices=8 normals with indices) but the bump-mapping/specular was completely wrong on this model. Maybe it has another reasons but I thought it could have to do with that.

Thanks for your help,
Rick

which fileformat do you open .3ds ?
i can remember that the .3ds normals where screwed but this might be fixed already

the problem was the different facing of the triangels you either had to flip the normals or recalculate them on your own but your problem doesn t sound like this

i thought i d just mention this, beware the information might be dated already
http://www.8ung.at/basiror/theironcross.html
The cube is a bit of a horrible model really, despite it being used as the ubiquitous test object for years now :). Each of its edges are hard so it really needs a sperate set of normals for each vertex-face. If you want to texture it in a way that makes good use of the texture space, you need to have different texture coords at each vertex-face as well. I imagine the lighting might be a bit bonkers with only 8 sets of texture coords since there will be *lots* of mirroring going on, which can cause problems with normal mapping (i.e. tangent space calculations).

For simple test stuff I prefer to use a quad or occasionally a cylinder, but you mention that it seems to work with other objects? Sounds like the math is most likely working to me.

As for smoothing stuff, most art packages have a threshold as to how sharp an edge can be before it is considered discontinuous (with regard to lighting), and multiple normals are formed. I'd imagine LightWave is duplicating vertices to make the cube edges hard, whereas Milkshape is averaging the normals to make it smooth.

T.
Thanks for the information guys! This cube was driving me nuts but I think I understand the problem now. I guess the best thing I can do is sub-dividing the box and make the edges softer in the model itself. This way the normals won't differ that much.

Edit
I tried the new box and a shader showed the normals were (almost) fine now. But those tangents... If I'm right, a tangent is the same a normal but with a 90 degrees rotation right? And ifso, what about the bi-normal? I think something goes wrong in the calculation (I used some stuff from GLScene, so I don't know what this code exactly does). The geometry seems right (also texcoords) so what could could mess up the calculation?
Maybe this is impossible, but could somebody give me an example how to calculate a tangent for 1 vertex, given the vertices, normals, texcoords and indices?

Thanks,
Rick

[Edited by - spek on August 23, 2005 11:16:49 AM]
First off: I've been working ona Lightwave exporter recently, so I feel your pain :) Seriously, they made a lot of really weird design decisions when building this thing. Maya is much nicer to work with. (Though not without it's own oddities)

Anyway, to answer your question: A tangent is not, actually, just a 90 degrees rotation of the normal. (Well, it IS, but thats not how you find it. How do you know which direction to rotate?) Also, you can't find the tangent by only evaluating a single point. You must consider the entire triangle. I'm still implementing it myself, so I can't provide any code samples, but the basic idea is that you find the direction that the "s" coordinate of the texture coords is increasing in and point your tangent in that direction. On a triangle the tangent will always be flush against the tri surface. The Bi-tangent is simply the cross product of the Normal and Tangent. I'll see if I can post some sample code for all of that later.

Oh, and as for generating the normals for each vert, here's how I did it. (Note that this doesn't account for any smoothing or material groups, or sharp corners)

void exportMesh::CalculateNormals( void ){	uint i;	uint a, b, c;	for(i = 0; i < verts.Size(); i++)	{		verts.normal = aQVect3( 0.0f, 0.0f, 0.0f );		verts.polys = 0; //Each vertex stores how many polygons share it	}		for(i = 0; i < polys.Size(); i++)	{		a = polys.x; //x, y, and z are indexes into the vertex array		b = polys.y;		c = polys.z;				Vec3 q = verts[a].pos - verts.pos;		Vec3 p = verts[c].pos - verts.pos;				polys.normal = q.Cross(p);		verts[a].normal += polys.normal;		verts[a].polys++;		verts.normal += polys.normal;		verts.polys++;		verts[c].normal += polys.normal;		verts[c].polys++;	}	for(i = 0; i < verts.Size(); i++)	{		if( verts.polys != 0 )		{			verts.normal /= (float)verts.polys;			verts.normal.Normalize();		}	}}


Hope that helps somewhat!
// The user formerly known as Tojiro67445, formerly known as Toji [smile]
Thanks! Yeah, the LWO format was certainly a pain, especially with those inverted bit orders but I love that program so. I'm gonna look into those tangent calculations again and hope I can solve it for once and for all!
Quote:Original post by spek
Thanks! Yeah, the LWO format was certainly a pain, especially with those inverted bit orders but I love that program so. I'm gonna look into those tangent calculations again and hope I can solve it for once and for all!


Computing TS is a lot more tricky, that computing normals.
First - subdivide your vertices by all parameters (texcoords, smoothing groups,TS-mirroring,..).
Then find all base vertices (with different positions), subdivide them *only* by SG and TS-mirroring, and do the calculation on them. Them map the results back onto fully subdivided vertex buffer. Computation of TS on a vertex, where mirroring is present must be done, as averaging all the tangents and binormals, then choosing the longest one, and computing the other as a cross-product. And just inverting it, for the vertices that belong to the mirrored-vertex.
Quote:Original post by Zemedelec
Computing TS is a lot more tricky, that computing normals. First...


Uh... wow. And here I thought I was pretty up to date with my graphics terminoligy. I don't think I understood a word of that!

*reads over 5 more time*

So what do you mean by subdividing the verticies by their paramaters? Do you mean creating an array of texcoords, a seperate array of positions, a seperate array of normals, etc? Why is that nessicary? I know that mirroring needs to be handled carefully, but this seems a little extreme.

(Oh, and just as a sidenote: It's biTANGENT, not biNORMAL. The terminology got mixed up a while back and binormal seems to have just stuck. Stop the spread of bad technical terms! ^_^)

// The user formerly known as Tojiro67445, formerly known as Toji [smile]

This topic is closed to new replies.

Advertisement