Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Spherical Coordinate Interpolation

Started by GTowse Jul 5, 2004 at 1:58 AM 6 replies 4.7k views
Original Post
GTowse
GTowse
Hi GameDev Readers, I have tried to create a C++ function that takes two points on a sphere (their cartesian coordinate values) and finds a third surface point that is interpolated between the two points based on a scalar ( 0.0 - 1.0 ). Here's the code: Vector3 SphereCoordFind( const Vector3 _vStart, const Vector3 _vEnd, const float _fScalar ) { // Start, End and Interpolated Cartesian Coordinates Vector3 vStart = _vStart; Vector3 vEnd = _vEnd; Vector3 vPoint; // vStart Spherical Coordinates float fStartAzimuth; float fStartPolar; float fStartLength; float fStartSqrX; float fStartSqrY; float fStartSqrZ; // vEnd Spherical Coordinates float fEndAzimuth; float fEndPolar; float fEndLength; float fEndSqrX; float fEndSqrY; float fEndSqrZ; // vPoint Spherical Coordinates float fAzimuth; float fPolar; float fLength; float fPolarSin; float fAzimuthSin; float fPolarCos; float fAzimuthCos; // Calculate vector lengths fStartLength = _vStart.Magnitude(); fEndLength = _vEnd.Magnitude(); // Normalize vectors vStart.Normalize(); vEnd.Normalize(); // Calculate squares of vStart[x,y,z] fStartSqrX = vStart.x * vStart.x; fStartSqrY = vStart.y * vStart.y; fStartSqrZ = vStart.z * vStart.z; // Calculate squares of vEnd[x,y,z] fEndSqrX = vEnd.x * vEnd.x; fEndSqrY = vEnd.y * vEnd.y; fEndSqrZ = vEnd.z * vEnd.z; // Find Azimuth angle of vStart/vEnd fStartAzimuth = atan2f( vStart.y, vStart.x ); fEndAzimuth = atan2f( vEnd.y, vEnd.x ); // Find Polar angle of vStart/vEnd fStartPolar = acosf( vStart.z / fStartLength ); fEndPolar = acosf( vEnd.z / fEndLength ); // Interpolate the angles between start and finish fLength = fEndLength + ( (fStartLength - fEndLength) * _fScalar ); fAzimuth = fEndAzimuth + ( (fStartAzimuth - fEndAzimuth) * _fScalar ); fPolar = fEndPolar + ( (fStartPolar - fEndPolar) * _fScalar ); // Find the interpolated Cartesian Coordinates fPolarSin = sinf( fPolar ); fPolarCos = cosf( fPolar ); fAzimuthSin = sinf( fAzimuth ); fAzimuthCos = cosf( fAzimuth ); vPoint.x = fLength * fAzimuthCos * fPolarSin; vPoint.y = fLength * fAzimuthSin * fPolarSin; vPoint.z = fLength * fPolarCos; return vPoint; } Can anyone tell me what I'm doing wrong here? It doesn't seem to generate a valid vector. For example, when I pass in: _vStart.x = 1.0f; _vStart.y = 0.0f; _vStart.z = 0.0f; _vEnd.x = -1.0f; _vEnd.y = 0.0f; _vEnd.z = 0.0f; _fScalar = 0.5f the returned vector is: x = -4.37114e-008f y = 1.0f z = -4.37114e-008f when it should be x = 0.0f y = 1.0f z = 0.0f Any thoughts? Graham
GTowse
GTowse
Juh? What's the markup for a code segment? Tis my first post...
vicviper
vicviper

I don't know the exact maths you're trying to do, but...

to do what you want, (spherical interpolation between two points in a 0-1 interval), it is common to use Quaternion maths.

I suggest you to look in gamedev articles, there are a bunch of very good quaternion faqs... you must search for "quaternion slerp" for what you want.
Shadowdancer
Shadowdancer
Quote:
Original post by GTowse
the returned vector is:

x = -4.37114e-008f
y = 1.0f
z = -4.37114e-008f

when it should be

x = 0.0f
y = 1.0f
z = 0.0f

Any thoughts?

Graham


This seems pretty good to me, there are minimal rounding errors which are to be expected in that magnitude when doing trigonometric math with float values.

For proper code markup, have a look at the FAQ link on the top right.
GTowse
GTowse
Thanks vicviper, I think it is about time I got into Quaternions. They were going to be a part of my intitial solution, but then I found the formula at
http://mathworld.wolfram.com/SphericalCoordinates.html and knew that I could use it to calculate my interpolation (and understand the process) in a small amount of time. As opposed to calling Slerp on a few Quaternions and not having as much control (simply because of my limited knowledge of Quaternions).

And Shadowdancer, when you say "This seems pretty good to me", I take it that you mean the values are correct? In this case do you think that I should just check for values close to zero in the returning vector (using some sort of tolerance) and set them to zero?

Thanks for the responses,

Graham Towse
LilBudyWizer
LilBudyWizer
You can see the markup used in any post by just clicking quote. That will show you what the author typed in.
Keys to success: Ability, ambition and opportunity.
Aprosenf
Aprosenf
Well one error I see is you're doing this:

// Find Polar angle of vStart/vEnd
fStartPolar = acosf( vStart.z / fStartLength );
fEndPolar = acosf( vEnd.z / fEndLength );


However, since you've already normalized the vectors at this point, you shouldn't be dividing by the original lengths. Also, in this piece of code:

// Interpolate the angles between start and finish
fLength = fEndLength + ( (fStartLength - fEndLength) * _fScalar );
fAzimuth = fEndAzimuth + ( (fStartAzimuth - fEndAzimuth) * _fScalar );
fPolar = fEndPolar + ( (fStartPolar - fEndPolar) * _fScalar );


You're interpolating in the wrong direction. If you plug in fScalar == 0, you'll get the end point, and if you put fScalar == 1, you'll get the start point. To make it the other way around, do:

fLength = fStartLength + ( (fEndLength - fStartLength) * _fScalar );
fAzimuth = fStartAzimuth + ( (fEndAzimuth - fStartAzimuth) * _fScalar );
fPolar = fStartPolar + ( (fEndPolar - fStartPolar) * _fScalar );


One other thing - for each pair of starting and ending points, you should compute the spherical coordinates only once and cache them. That way, for each value of fScalar, you don't do redundant calculations.

To make code in a fixed-pitch font that preserves spacing, but [code] and around your code. For a nice syntax-colored source box, but [source] and [/source] around your code.
GTowse
GTowse
Thanks for the correction Aprosenf :)

OK, I've tried using spherical coords, and now I'm going to have a go at using quaternions.

Can someone run me through the process of interpolating two points on a unit sphere? I am using a graphics engine so there is no need for big maths explanations, just a few tips would be good.

Here's my current process, which generates bogus values:

// number of points between start and end vectorint iRes = 1;// create 2 points on a unit sphereVector3 vStart(  1.0f,  0.0f,  0.0f );Vector3 vEnd(   -1.0f,  0.0f,  0.0f );Quaternion qStart;Quaternion qEnd;qStart.SetAngleAxis( 0.0f, vStart );qEnd.SetAngleAxis( 0.0f, vEnd );for( int i=1; i < res+1; i++ ){   float fScalar  = float(i) / float(res+1);   Quaternion qInterp;   qInterp.Slerp( qStart, qEnd, fScalar );   float   fTheta;   Vector3 vPoint;   qInterp.GetAngleAxis( fTheta, vPoint );}


Can someone please tell me what I'm doing wrong here,

Thanks,

Graham Towse

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.