Calculating vertex normals for b-spline patches?

Started by
9 comments, last by GameDev.net 17 years, 6 months ago
Hey guys, I've never calculated vertex normals for any mesh. Funny that I should start with b-spline patches! I already have a function written which will take the 16 spline control points and tesselate the patch based on a given number of divisions. The result is a set of triangles which approximate the curve of the patch. In order to light the patch, I need to calculate the normals for each vertex. What method is usually used for spline patches? I suppose I could calculate the normal for each face, and then each vertex normal would be the average normal for each face that shares it. Alternately, I could use the splines themselves. Each vertex represents an intersection between two splines. I could calculate the tangent of each spline at the intersection point, find the vector which is perpendicular to each tangent, and then average them together. Mind you, I have no idea how to implement either solution, but I guess I'll start by asking what solution you guys think would be best?
Advertisement
Its is pretty easy to calculate the normals of a b-spline patch, it pretty much falls out of the patch calculation.. Simply calculate the derivative of spline in the U and V direction at that point, then cross product them.
Thanks.

I'm not very familiar with calculus. Do you by chance know how to calculate a derivitative of a 3D spline?
Are you asking about the multidimensionality, or the differentiation in general?
I think I can wrap my mind around obtaining the derivative of a curve in 2D space. I took a cursory look at it, and I think I have the general concept down. The way I picture it, the derivative allows me to determine the slope at some arbitrary point along the curve. The slope itself can be represented as a line, which is a tangent to that point.

But in 3D, there are an infinite number of coplanar lanes which are tangent to any point along the curve. So, it seems that the tangent of a 3D curve is a plane. Perhaps, if I could get the normal to that plane, then I would have the vector I'm looking for?

I think it's the multidimensionality of it that I'm confused about.
there are 2 ways to do it,

1. Calculate the derivatives in U & V, cross product, normalise, there's your normal.

2. Treat the whole thing as a bunch of tri's, calculate in the same way as for any other polymesh. Typically this is not as accurate, and you may need to manually fix seams on periodic surfaces.

I prefer the 2nd method for real time stuff. The difference in visual quality is only noticeable at low lods (when stuff is typically far away), and it tends to be more efficient and more generic when dealing with some of the more esoteric surface types.


Quote:Original post by uncle_rico
I suppose I could calculate the normal for each face, and then each vertex normal would be the average normal for each face that shares it.


The crap method (that 99.99% of people use - even maya & max) :

memset the normal array to zeroforeach triangle tri in tri_list   n = calculateFaceNormal(tri)   foreach vertex v in tri      v.normal += n;   endendforeach normal n in normals   normalise(n)

Quote:Original post by RobTheBloke
Quote:Original post by uncle_rico
I suppose I could calculate the normal for each face, and then each vertex normal would be the average normal for each face that shares it.


The crap method (that 99.99% of people use - even maya & max) :

memset the normal array to zeroforeach triangle tri in tri_list   n = calculateFaceNormal(tri)   foreach vertex v in tri      v.normal += n;   endendforeach normal n in normals   normalise(n)
I'll put in another vote for the above method. I eventually switched all of my procedural mesh generation code over to this method because even though the normals for many shapes (curved surfaces, spheres, cylinders, capsules, ellipsoids, etc.) can be computed directly from the shape definition, it's a pain to write and debug all that extra code, and the general solution usually produces close to the same results. In the end I found it more convenient to have a single ComputeNormals() function that could be used with any input. YMMV though.
Consider the middle point here, and assume these form some of the faces of a cube:
 ___ |\  || \ ||__\|___|\  |\  || \ | \ ||__\|__\|


The sides where two triangles meet the vertex contribute twice as much to the vertex normal campared to the sides where only one triangle is in contact with it. So I scale each surface normal by the angle of the trangle corner belonging to each vertex, before I add it to it's normal.
That leads to each of the two 45 degree triangle corners contributing half as much as the 90 degree one.

I assume this works better in general too, but I haven't proved that.
For a cubic beziers its this (beware of typos :-) ):

  float invU=1-u;  float invU2=oneMinusU*oneMinusU;  float u2=u*2;  return (-3*invU2*p0)+3*(invU2-2*u*invU)*p1)+3*(2*u*invU-u2)p2+3*u2*p3;


There is a lot of stuff online.... Here are few links from googling "bezier derivative":
http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html
http://www.cs.sunysb.edu/~qin/courses/geometry/4.pdf#search=%22bezier%20derivative%22
http://www.tsunamichannel.com/howto/java/25/index.html

This topic is closed to new replies.

Advertisement