# Need Help with vector math to move sphere on road

This topic is 3230 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Can anyone help me with the math I need to get a sphere(ball) on a road to move left or right as its rolling forward? Basically I have a sphere on a road and when the player pushes forward it moves forward, but I can't get the math to move the sphere to the left or right when they press move left/right... I am thinking I need the Dot product of the fwd vector and the left or right vector? and then move the ball to that angle?

##### Share on other sites
Cross the forward vector with the road's "up" vector to get a "right" vector, scale this and add it to the sphere's position to offset it to either side of the spline.

You'll need the other reference vector though, the up. Most peoples road splines interpolate this along the path as well, to make the road bank.

My spline object has a GetBasisAtTime(float) which returns a matrix representing the complete coordinate space at that point on the spline. Then it's a simple matter of transforming your sphere's local coordinate (Vector(0,heightAboveRoad,sidewaysOffset,1)) by the splines coordinate frame at that point.

##### Share on other sites
Hello Bzroom, been awhile... I am still a bit confused on the whole idea you have shot my way, but would angular velocity be what I am looking for?

Thanks

##### Share on other sites
So this is physically simulated and not just animated along the spline?

How are you getting it to follow the center of the spline in the first place, post a little psuedo code sniplet.

##### Share on other sites
the angular velocity would be the linear velocity amount along the road surface, over the radius of the ball.

velocity = ball.linear_velocity - (road.normal.dotProduct(ball.linear_velocity) * road.normal);

ball.ang_velocity = velocity.length() / ball.radius;

the axisof rotation would be the cross product of the velocity direction, and the road surface normal.

rotation_axis.normalise();

then in openGL or whatever, you can use that in the glRotate() function.

EDIT : could be you need the opposite...

ball.ang_velocity = -(velocity.length() / ball.radius);

and also, there are probably optimisations you can do as well.

##### Share on other sites
Sorry Bzroom I been busy...

I have a procedurally created road and I have the normals stored for later use, and the centerline is stored also.

I will post in a bit after I move to the computer with this code on it....

##### Share on other sites
I call this to get the players pos

playerPos = track.GetPosition(distance + 10.0f, false); //on centerline

then in the render()
//Draw Player
glPushMatrix();
matrix.Translate(playerPos);
rotMatrix.Rotate(NX::MATH::DegToRad(angle), true, false, false);
matrix *=rotMatrix;
glMultMatrixf(matrix.matrix);
DrawBall();
glPopMatrix();

What I need is when the player presses left/right on the keyboard move the ball to the left or right and keeps rolling forward.

oliii Thanks for the reply, I tried the code you pasted but I can't get it to work with my code as of yet...

##### Share on other sites
Alright, so lets just be clear though, you're manually animating the object along the road, and not using some kind of physics engine to integrate it's position based on forces/torques and collision?

Either way, given the information you provided you can create a coordinate space at any point along the spline.

You have some point P(t) on the spline, N(t) is the normal at P(t), F(t) is the forward direction F(t) = (P(t+0.0001) - P(t)).Normalized(); and you are looking for R(t) which is the right vector at P(t). R(t) = Cross(F(t), N(t));

Construct a matrix with those columns: Matrix transform(F(t), N(t), R(t), P(t)).

That matrix describes the coordinate system at "t" along the spline. I assume you are incrementing "t" to make your ball "travel" along the road.

Now you want to get him off the origin of that coordinate space that we created.

So what you have currently is equivalent to

Vector ballPos = transform * Vector(0,0,0,1); //ball will be placed on spline

And you want to add some horizontal offset, in the R(t) axis.

float sideOffset = 2;
Vector ballPos = transform * Vector(0, 0, sideoffset, 1); //ball will be placed 2 units to the "right" of the spline.

If you wanted the ball to "jump" up off the spline:
Vector ballpos = transform * Vector(0, ballHeight, sideOffset, 1);

Notice that the X component is always zero, that's because we are only moving in the spline space that we created at a specific "t", we wouldn't want to translate any further forward or backward along the spline without updating "t".

edit: your "distance" is equivalent to my "t", and your track.GetPosition is equivalent to my P(t).

##### Share on other sites
This could also be represented as:
Vector ballPos = N(t) * ballHeight + R(t) * sideOffset + P(t);

Which is what i was kind of hinting at in my original post.

You currently have:
Vector ballPos = P(t);

##### Share on other sites
Bzroom, I will have a look when I get home. I am sorry, I forgot, I am doing this manually, no Physics libs, its just a simple arcade game.

I will let you know what I find later with the code you posted.

Thanks

##### Share on other sites
This is what I have, I think we are on the right track, but when I leave the initial Position and move left the ball disappears, and the ball does move to the right but its not at the same angle the left move does...

Setup of matrix transform
NX::MATH::Matrix4x4<float>& Track::GetTransformMatrix(NX::MATH::Matrix4x4<float>& m, 											          float dist, bool linearInterpolate){	NX::MATH::vec3<float> pos    = GetPosition(dist, linearInterpolate);	NX::MATH::vec3<float> normal = GetNormalAtPosition(dist, linearInterpolate);	NX::MATH::vec3<float> fwdvec = GetPosition(dist + 1.0f, linearInterpolate) - pos.GetNormalizedVec();	NX::MATH::vec3<float> rightvec = NX::MATH::vec3<float>::Cross(fwdvec, normal);	m.Set(fwdvec.x,   fwdvec.y,   fwdvec.z,   0.0f,	 	  normal.x,   normal.y,   normal.z,   0.0f,		  rightvec.x, rightvec.y, rightvec.z, 0.0f,		  pos.x,      pos.y,      pos.z,      1.0f);	return m;}

//Draw ball
//setup matrixtrack.GetTransformMatrix(playerTransformMatrix, distance + 10.0f, false);//playerDirif(playerRight)		playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 100.0f);	else if(playerLeft)		playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, -100.0f);	else		playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 0.0f);glPushMatrix();		playerPos = playerTransformMatrix & playerDir;	playerPos.y +=75.0f;	matrix.Translate(playerPos);	glMultMatrixf(matrix.matrix);	DrawBall();glPopMatrix();

Thanks

##### Share on other sites
This is wrong:
NX::MATH::vec3<float> fwdvec = GetPosition(dist + 1.0f, linearInterpolate) - pos.GetNormalizedVec();

It should be, normalized after the subtraction:
NX::MATH::vec3<float> fwdvec = (GetPosition(dist + 1.0f, linearInterpolate) - pos).GetNormalizedVec();

Also, 1.0 is a rather large interval for approximating a derivitive. You should use 0.1f.

Also rightvec needs to be normalized. And you're copying F(t) N(t) and R(t) into the _columns_ of the matrix, not the rows correct? The way you've illustrated it in the source code it looks like rows, it should be setting them as the columns.

Also this is failed logic:
if(playerRight)  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 100.0f);else  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 0.0f);	if(playerLeft)  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, -100.0f);else  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 0.0f);

If playerLeft is false, then you will get (0,0,0) regardless of the state of playerRight.

try:

if(playerRight)  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 100.0f);else if(playerLeft)  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, -100.0f);else  playerDir = NX::MATH::vec3<float>(0.0f, 0.0f, 0.0f);

Also, moving it by 100 units seems kind of large? might be why it's going off the screen, try a smaller number like 3 or 5 for starters.

This seems arbitrary but i'm sure it's for good reason:
playerPos.y +=75.0f;

Translate sets the aboslute translation of the matrix right? And doesnt increment it? You want it to set the absolute translation.
matrix.Translate(playerPos);

[Edited by - bzroom on April 21, 2009 4:34:17 PM]

##### Share on other sites
I will evaluate it further when I get back from eating... So far I think the few issues you seen may have fixed it... I will let you know.

##### Share on other sites
It looks like it's working now, only thing left that I can see is what do I do about limiting the movements for side to side to match my road width...

When I do this
playerPos = playerTransformMatrix & NX::MATH::vec3<float>(0.0f, 0.0f, playerDir);
playerPos isn't going to match up to the road width that I have. From what I see its about -25 to 25 wide. When I setup the road the track width is 450 wide...

thanks for the help!! ++