According to the Hairy Ball theorem, it is not possible to get consistently oriented normals at any point on the curve.
What I want to achieve is a game object moving beneath a procedurally-generated rail (plain cylinder). To generate a tube I use a spline which consists of bezier curves. Thus, I need to get a correctly oriented normals at any point of the curve.
The code looks like this:
Vector3 q2 = GetCurveTangent (...);
Quaternion lookAt = Quaternion.LookRotation (q2);
Vector3 normal = lookAt * Vector3.up;
normal = Quaternion.AngleAxis (angle, q2) * normal;
return point + normal * size;
On horizontal segments everything is correct, but on vertical ones, when tangent is oriented like Vector3.up, everything goes wrong.
The only advice I’ve received is to try and use the previous tangent instead of global up vector. But I can not get any good result out of it. What I tried to do is:
So, the question is: how can one create a cylindrical rail and an object moving beneath it (using the normal facing strictly down the curve)? If curve is vertical, “down” is of course globally forward and so on.
As far as my understanding of my work with bezier curves is that there is just not enough information to try and build each required axis for this without making some assumptions. If you assume world up vector is always aligned with the percieved local up direction you are limited to not passing straight up or straight down without causing significant rotations around world up.
I faced these problems myself last year and opted for a rather manual approach where I gave each bezier point an additional normal to be able to define the local up vector. So i basically had two curves for each spline. One for position with derived forward vector, and another for up normal, then you just cross them to get right.
It felt a bit cumbersome working with but also gave good control. In the end I had a quaternion rotation coupled with position and an in and out vector as editable points, then built the required splines using these.
When moving horizontally we calculate our left/right normals via a cross product with up, then we can even normalize are up off the left/right.
When moving vertically, an issue arises with the cross product of the heading with ‘up’ results in a zero vector…
OK
I agree with the advice given to you… use the historical up vector.
Cross product your heading/tangent with the previous up vector of your object moving along the spline to get the left/right (order of operations defines left or right).
Then with that you can cross the left/right with your heading/tangent to get the up at that position.
Then with this your rotation will just be:
Quaternion.LookRotation(heading, normalizedUp)
Thank you lordofduct. But what should I do with this part: Vector3normal = lookAt * Vector3.up; ?
Because after this I multiply it by an angle.
I need to get a normal at any given angle, and 180 degrees should always be down.
And, how can I get “previous up vector”? For example, for the first point it is global up. And for the second?
Start with Vector3.up the first time you call it, and then use the normal that is returned for the next call to it.
What you now do with this normal… well, you can do anything with it. Add it to ‘point’ multiplied by ‘size’ to draw your gizmo if need be.
(caution, I may have screwed up the order of operations on the cross products… I always forget. If your normal is upside down, just swap the order of the inputs on Cross.)
If you want to rotate it, do as you please… not sure why you’re rotating it.
If you plan to rotate it to get the normal… you don’t have to… it’s already rotated to the direction you need. Because it’s the normal.
…
In your picture, the normal returned by this method should be the direction of that blue line. If you add it to point, scaled by size… you get the end of the blue line. ‘point’ to this end of the blue line, IS the blue line.
How about you just… give it a run, see what you get. It’s usually the best option at figuring out what something does… pull the trigger, see what happens!
As I already explained in the topic, I rotate the normal to construct the cylindrical pipe around a bezier curve. Thus, I need to get a circle of points around each point on a curve, thus a full circle of rotated normals plus “down-rotated” (180 degrees) normal for a movement position (because it’s the ceiling-based rail, and an object boves beneath it). So, I need to supply an angle and size and get a point in space around the curve.