Sign in to follow this  
McFury

bezier curves

Recommended Posts

Hi, I am currently using cubic bezier curves (4 control points) to direct paths my camera moves on. Using similar code as described in this wiki: http://www.gamedev.net/reference/articles/article1808.asp However, I need to expand this to be a 6 point bezier curve, however it was hard for me to find information on how to do this. The code im using for a cubic curve is like so:
// where alpha is incremented elsewhere
double a = 1.0 - m_alpha;
double b = m_alpha;

position.x = m_curvePoints[0].x * a * a * a + m_curvePoints[1].x * 3 * a * a * b + m_curvePoints[2].x * 3 * a * b * b + m_curvePoints[3].x * b * b * b;

position.y = m_curvePoints[0].y * a * a * a + m_curvePoints[1].y * 3 * a * a * b + m_curvePoints[2].y * 3 * a * b * b + m_curvePoints[3].y * b * b * b;

position.z = m_curvePoints[0].z * a * a * a + m_curvePoints[1].z * 3 * a * a * b + m_curvePoints[2].z * 3 * a * b * b + m_curvePoints[3].z * b * b * b;
Any help would be great. Thanks.

Share this post


Link to post
Share on other sites
Thanks for your reply jyk!

I must have missed that when i skimmed over it before. I have modified the code for a 6 point curve (using that wiki) that seems to be working okay, but I did have another question of its use.

At the moment my camera is rotating around a planet sized sphere. I am trying to get the camera to do a 6 point curve to get to / look at a specific surface point.

I can do the rotation easy enough, this is just for positioning
I hope this doesn't sound like a mess...

// 'totalLength' is the length of a vector between the starting point and the ending point

// 'upDirection' is a directional vector from the sphere centre to the midpoint of a vector between the starting point and end point

My points are:

1) The starting position of the camera

2) The starting position plus a point that is backwards along the camera's forward vector by totalLength

3) The starting position plus a point that is along upDirection by totalLength

4) The ending position plus a point that is along upDirection by totalLength

5) The ending position plus a point that is backwards along the camera's forward vector by totalLength

6) The ending position of the camera

I thought that this would give me a nice curve that moves backwards out of the starting position, moves around the sphere and then goes into the ending position. But it seems to act strangely when far away from the target point (around the other side of the sphere for example).

Am I going about this type of problem all wrong? xD

Thanks.

Share this post


Link to post
Share on other sites
Quote:
1) The starting position of the camera

2) The starting position plus a point that is backwards along the camera's forward vector by totalLength

3) The starting position plus a point that is along upDirection by totalLength

4) The ending position plus a point that is along upDirection by totalLength

5) The ending position plus a point that is backwards along the camera's forward vector by totalLength

6) The ending position of the camera

I thought that this would give me a nice curve that moves backwards out of the starting position, moves around the sphere and then goes into the ending position. But it seems to act strangely when far away from the target point (around the other side of the sphere for example).
Keep in mind that with a Bezier curve, the curve itself is only guaranteed to pass through the first and last control points. I can't quite visualize what you described above, but it seems like you could pretty easily end up with a curve that passes through the sphere or otherwise behaves incorrectly.

In any case, if the camera is just dollying in and out and moving around a sphere, I'm not sure that Bezier curves are the best choice here. Why not just have the camera follow the shortest arc from the start point to the end point, while moving away from the sphere at the beginning and then back towards the sphere at the end?

Share this post


Link to post
Share on other sites
Thanks for the replies again!

jyk, your answer seems quite logical and I would like to try that, I suppose the only hurdle for me was how to vary the alpha variable over the course of the transition to make it zoom right out and then back in again (which is why I started looking at curves with control points in the first place).

Before I was just doing a standard slerp for the rotation (and then position), and using the alpha variable (starts from 0.0 and goes to 1.0 at completion) to gradually get to the height needed at the end point. But this did not have a zooming in and out pattern, just a gradual increase or decline in height depending on what the final desired height was.

Would you have any advice on how to go about achieving that dolly in/out effect? I guess it would need to dolly out more if the camera was further around the other side of the sphere, but I have no idea how to get it to do this.

My code that currently does the rotation and positioning (works fine):


WorldQuaternion transitionSlerp = WorldQuaternion::Slerp(m_alpha, m_transitionStart, m_transitionEnd);
transitionSlerp.Normalize();
transitionSlerp.ToRotation(rotation);
WorldMatrix3D orgRotation;
m_transitionStart.ToRotation(orgRotation);
WorldMatrix3D rotationDiff = rotation * orgRotation.Inverse();
position = rotationDiff * m_transitionStartPos;


My code that currently alters the position again to dolly in/out (this works but is not the effect that I want):


float centreToStartRadius = m_transitionStartPos.Length();
float centreToEndRadius = m_transitionEndPos.Length();
float offsetDistance = centreToStartRadius - centreToEndRadius;
float radiusChange = centreToStartRadius - (centreToStartRadius - (offsetDistance * m_alpha));
WorldPoint3D PosToCentre = -position;
PosToCentre.Unitize();
position += (PosToCentre * radiusChange);


I have a function that currently calculates alpha depending on the time, and the selected duration that the transition is suppose to take.


// where fTime is the current time
m_alpha = ((fTime - m_transitionStartTime) / m_transitionDuration);

// clamp alpha to maximum to stop transition
if (m_alpha >= 1.0f)
{
m_alpha = 1.0f;
ClearMovement();
return false;
}

return true;


Again, any help would be great. Thanks for the responses so far.

Share this post


Link to post
Share on other sites
I'm not 100% clear on the behavior you're after, so I can probably only offer general suggestions at this point.

One possibility would be to use a different type of spline, as suggested by Wan. If you want to handle the orbiting and dollying separately though, it seems there'd be any number of functions you could come up with to control the camera distance. For example, you could interpolate from the initial distance to a max 'orbital' distance over the first half of the rotation, and then from the 'orbital' distance to the goal distance over the second half, using an 'ease in, ease out' function to smooth the effect.

Share this post


Link to post
Share on other sites
About the Catmull–Rom splines. I'm having trouble finding a site that can explain it so that I can expand it into code for 6 control points. Every example I see seems to deal with only 4 control points. But it seems like a good option if I can get something working with it.

At the moment im just trying to alter the dolly in / out for a maximum height at the half way point as you suggested.

[Edited by - McFury on March 10, 2010 11:52:41 PM]

Share this post


Link to post
Share on other sites
Hi again,

Okay so I am just testing using a 4 point Catmull-rom curve at the moment. I noticed that the curve seems to only move between the middle two control points (not the starting and ending points). Is this because its not a closed curve and I need to do something else to the equation?

The code im using (found on web):


void PointOnCurve(WorldPoint3D &out, float t, TrackPoint p0, TrackPoint p1, TrackPoint p2, TrackPoint p3)
{
float t2 = t * t;
float t3 = t2 * t;
out.x = 0.5f * ( ( 2.0f * p1.x ) +
( -p0.x + p2.x ) * t +
( 2.0f * p0.x - 5.0f * p1.x + 4 * p2.x - p3.x ) * t2 +
( -p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x ) * t3 );


out.y = 0.5f * ( ( 2.0f * p1.y ) +
( -p0.y + p2.y ) * t +
( 2.0f * p0.y - 5.0f * p1.y + 4 * p2.y - p3.y ) * t2 +
( -p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y ) * t3 );


out.z = 0.5f * ( ( 2.0f * p1.z ) +
( -p0.z + p2.z ) * t +
( 2.0f * p0.z - 5.0f * p1.z + 4 * p2.z - p3.z ) * t2 +
( -p0.z + 3.0f * p1.z - 3.0f * p2.z + p3.z ) * t3 );
}


I also realize now that I need to have multiple segements (each with 4 control points, but each only describing the p1 -> p2 parts of the curve. So I need a way to connect the curve segments. Does anyone know any good way to do this with what im doing?

Thanks

[Edited by - McFury on March 11, 2010 1:01:24 AM]

Share this post


Link to post
Share on other sites
Did you think about it for your own?

You have control points, and tangents. (tangents are defined by the two "end" control points).

What does "joining" mean?
The endpoints are joining and the tangents are unidirectional.
So you have to make the endpoints and the control points (defining the tangent) collinear.

Same goes for bézier(Hermite)-joining, it's just the control point (defining the tangent) in "on the other side".

Look into the topic, so that you will know what's behind the formulas, not just copy it. It's not "high-mathematics" or whatever.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this