How can work time between ticks into this movement function? - c++

I have a function that moves a planet around a star. This function takes a parameter t, which is the time in milliseconds since the last update. In other movement functions I've written, I like to use time to dictate movement so the movement will always be the same on all computers and instances instead of based on processing power. However, all methods I have tried for including time in this physics equation have resulted in erratic results. Any ideas?
void Planet::update(int t){
double grav_const = 6.6742e-11;
double earth_mass = 5.975e24;
double starX = 1920/2 * 10000;
double starY = 1080/2 * 10000;
double diffX = xPos - starX;
double diffY = yPos - starY;
double radius = sqrt(pow(diffX,2) + pow(diffY,2));
double grav_accel = (grav_const * (earth_mass / pow(radius,2)));
double angle = atan2(diffX, diffY);
xVel += (sin(angle) * grav_accel);
yVel += (cos(angle) * grav_accel);
xPos -= xVel;
yPos -= yVel;
}

It's been a while since I dealt with physics at this level, but I think you can go back to fundamental reasoning about the units involved.
Acceleration is distance over time squared (m/s^2 or whatever your units are). So to get velocity (distance over time) then you need to multiply by time.
m/s = (m/s^2) * s
And then after that you want to turn your velocity into a specific change in distance. So multiply it by the time again and there you go.
m = (m/s) * s
If things still don't seem right afterwards, then you may need to check over the rest of your equations and constants. Make sure the units match up (seconds vs minutes, metere vs kilometers, etc). Make sure you aren't suffering rounding in places you didn't intend. And so on.
In the worst case, work the math yourself for a few iterations (perhaps with larger time values) and maybe even plot the results on a piece of paper to make sure it looks sensible.

When you describes the results as "erratic" exactly what do you mean?
If you mean:
A. "t changes by a varying amount between each call". Then you need to look at the architecture of the calling application since that will vary with processing power and other work going on in the system (assuming a preemptive multitasking OS).
B. "the floating point values have strange rounding characteristics". Then welcome to using floating point numbers. The representations of double, float and the like are simply imperfect and exhibit rounding areas in certain circumstances and you may have problems if you are taking deltas that are too small relative to the size of the other values you are combining.
C. "t has no effect on my results". I don't see any references to the input parameter in your example.
You should post the entire Planet class, or at least more of it.
EDIT: The best way to calculate position based on times like this is to come up with an absolute function that returns position based on time and NOT accumulate position, but only accumulate time. For example:
timeAbsolute += tDelta;
xPos = fxPos(timeAbsolute);
yPos = fyPos(timeAbsolute);
xVel = fxVel(timeAbsolute);
yVel = fyVel(timeAbsolute);
My orbital mechanics fu is not strong enough to give you those functions in general, but in your case (where you seem to be assuming a circular orbit), you can simply take the arc angle instead. So, assuming 1 orbit every 360 seconds (and using degrees), you would get
angle = (timeAbsolute % 360);
then calc velocity and position from angle.
P.S. Be careful with fmod ...
How to use fmod and avoid precision issues

Related

Rotating vectors in space and high precision in C++

This is my function to compute 3D rotation in C++ defined by an angle in radiant around axis.
Vector rotate(const Vector& axis, const Vector& input, const double angle) {
double norm = 1/axis.norm();
if(norm != 1)
axis *= norm;
double cos = std::cos(angle);
double mcos = 1 - cos;
double sin = std::sin(angle);
double r1[3];
double r2[3];
double r3[3];
double t_x, t_ym t_z;
r1[0] = cos + std::pow(axis.x, 2)*mcos;
r1[1] = axis.x*axis.y*mcos - axis.z * sin;
r1[2] = axis.x*axis.z*mcos - axis.y * sin;
r2[0] = axis.x*axis.y*mcos + axis.z*sin;
r2[1] = cos + std::pow(axis.y, 2)*mcos;
r2[2] = axis.x*axis.z*mcos - axis.x * sin;
r3[0] = axis.x*axis.z*mcos - axis.y * sin;
r3[1] = axis.z*axis.y*mcos - axis.x * sin;
r3[2] = cos - std::pow(axis.z, 2) * mcos;
return Vector(t_x, t_y, t_z);
}
The thing is if you try yourself to rotate the vector a n times pi/4 where n multiple of 4 (so you do complete revolution around the axis by doing four quarter of rotations) the error will propagate pretty fast.
Example (where err = input-output):
input: (1.265, 3.398, 3.333)
rotation axis: (2.33, 0.568, 2.689)
n: 8 (so two completes revolutions)
output: (1.301967, 1.533389, 4.138940)
error: (0.038697, -0.864611, 0.805940)
n: 400 (so 100 completes revolutions)
error: (472..., 166..., 673...)
What can I do ?
Constraints:
Rotations are not predictable so not possible to do something like angle = pi/4 *n % 2*pi like #molbdnilo suggests. Because I have to chain translations and rotations to test if there's a collision.
This is one of the typical problems that you can run into with floats.
Floating point numbers are pretty exact on singular operations. In fact, for many operations you are guaranteed to get the most exact result that can be represented in the format, so any rounding errors that you get are solely due to fitting it into the representation.
However, as soon as you start chaining floating point operations, even those errors can accumulate. If you are lucky, you can make your algorithm numerically stable, so that the rounding errors cancel each other out in the end and you always stay in the ballpark of the correct result. Getting this right can be quite a challenge though, especially for complex computations. For instance, in your particular implementation, there is lots of potential for catastrophic cancellation introducing large rounding errors into the computation chain.
The easier solution is: Avoid chaining the float operations in the first place! Or to be more precise: Only chain those parts which you can keep numerically stable. Since you mentioned this is for a computer game: In a game you transform the geometry according to the camera matrix each frame. You never touch the geometry in memory, instead you simply adjust the camera matrix. That way, your source geometry is always fresh and the rounding error in each frame is simply the error from that single transformation.
Similarly, you usually don't update the camera matrix incrementally. Instead, you read the player's position and view and build the complete matrix from scratch from those vectors. Now the only challenge that you have left is make sure that you don't accumulate errors into the player position and view, but this is much easier than ensuring stability at the other end of the transformation pipeline.
Just store the original base vector and the rotation angle together, and do the calculation every time you need the current rotated value. You can cache this and invalidate every time the angle changes, but always work from the original base vector and total aggregate rotation.
Presto! No cumulative errors, because no chained calculations.
Also, if you're concerned about cumulative errors in the angle itself, store that in degrees and convert to radians when required. Again, pi is touched once in the degree->radian conversion, and you don't have a chain of approximate pi/n values contributing more errors.
You could try and discretize your rotations so that they add up to multiples of pi/2. You clamp your rotation value to the closest discretized value and then do the calculation. If you find one small enough it will be still perceived as smooth and you should not accumulate an error.
In the end I used Rodrigues' rotation formula and the performances are way better.
Though this is not the solution as #ComicSansMs points it out:
Avoid chaining the float operations in the first place!
So combining a new algorithm and using Rodrigues' formula was ok.
I suspect mistakes in my first matrix implementation.
Thanks everyone for your answers and insights.

Create objects in a circle around a point

I need to create a circle of regularly spaced doors around a reference point in space. Each time the program is run, a different number of items will be in the circle, and thus it automatically rescales to accommodate the increased number of items. I know this is more of a mathematic question rather than a programming question, but I am stumped! The following code is as close as I got:
block->setPosition(core::vector3df(sin(segdeg*itemnumber)*radius+referencepoint.X,
0,
cos(segdeg*itemnumber)*radius+referencepoint.Z));
block is the object, and this code is run for each item.
segdeg is 360/the number of items. that is to say, the SEGment DEGrees.
Radius is how far away from the central point the items need to be.
Itemnumber is the index of the item in question - Which number item it is.
For some reason, this code makes each door pretty close, but still about 10-15 degrees off. (The first door is always spot on though) The items are all the correct distance away from the centre point though. I'm sure that this is a really obvious answered question, but I haven't been able to solve it for hours and I've googled my arse off.
Can anyone fix my algorithm?
sin and cos take their arguments in radians, not degrees. You want segrad = 2 * pi / the_number_of_items (SEGment RADians) instead of segdeg = 360.0 / the_number_of_items (SEGment DEGrees).
Your implementation might provide a value for pi, but there's none in the standard so you might have to use boost::math::constants::pi<double>() or put your own in.
Your first item is correct because 0 is 0 in any measure.
int doors = 5;
double rotation = 2 * M_PI / doors;
for(int door = 0; door < doors; ++door)
{
double door_rotation = door * rotation;
double door_x = reference_x + cos(door_rotation);
double door_y = reference_y + sin(door_rotation);
}

Fast equivalent to sin() for DSP referenced in STK

I'm using bits of Perry Cook's Synthesis Toolkit (STK) to generate saw and square waves. STK includes this BLIT-based sawtooth oscillator:
inline STKFloat BlitSaw::tick( void ) {
StkFloat tmp, denominator = sin( phase_ );
if ( fabs(denominator) <= std::numeric_limits<StkFloat>::epsilon() )
tmp = a_;
else {
tmp = sin( m_ * phase_ );
tmp /= p_ * denominator;
}
tmp += state_ - C2_;
state_ = tmp * 0.995;
phase_ += rate_;
if ( phase_ >= PI )
phase_ -= PI;
lastFrame_[0] = tmp;
return lastFrame_[0];
}
The square wave oscillator is broadly similar. At the top, there's this comment:
// A fully optimized version of this code would replace the two sin
// calls with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known.
I don't know where to start looking for these "fast two-multiply algorithms" and I'd appreciate some pointers. I could use a lookup table instead, but I'm keen to learn what these 'fast sin oscillators' are. I could also use an abbreviated Taylor series, but thats way more than two multiplies. Searching hasn't turned up anything much, although I did find this approximation:
#define AD_SIN(n) (n*(2.f- fabs(n)))
Plotting it out shows that it's not really a close approximation outside the range of -1 to 1, so I don't think I can use it when phase_ is in the range -pi to pi:
Here, Sine is the blue line and the purple line is the approximation.
Profiling my code reveals that the calls to sin() are far and away the most time-consuming calls, so I really would like to optimise this piece.
Thanks
EDIT Thanks for the detailed and varied answers. I will explore these and accept one at the weekend.
EDIT 2 Would the anonymous close voter please kindly explain their vote in the comments? Thank you.
Essentially the sinusoidal oscilator is one (or more) variables that change with each DSP step, rather than getting recalculated from scratch.
The simplest are based on the following trig identities: (where d is constant, and thus so is cos(d) and sin(d) )
sin(x+d) = sin(x) cos(d) + cos(x) sin(d)
cos(x+d) = cos(x) cos(d) - sin(x) sin(d)
However this requires two variables (one for sin and one for cos) and 4 multiplications to update. However this will still be far faster than calculating a full sine at each step.
The solution by Oli Charlesworth is based on solutions to this general equation
A_{n+1} = a A_{n} + A_{n-1}
Where looking for a solution of the form A_n = k e^(i theta n) gives an equation for theta.
e^(i theta (n+1) ) = a e^(i theta n ) + b e^(i theta (n-1) )
Which simplifies to
e^(i theta) - e^(-i theta ) = a
2 cos(theta) = a
Giving
A_{n+1} = 2 cos(theta) A_{n} + A_{n-1}
Whichever approach you use you'll either need to use one or two of these oscillators for each frequency, or use another trig identity to derive the higher or lower frequencies.
How accurate do you need this?
This function, f(x)=0.398x*(3.1076-|x|), does a reasonably good job for x between -pi and pi.
Edit
An even better approximation is f(x)=0.38981969947653056*(pi-|x|), which keeps the absolute error to 0.038158444604 or less for x between -pi and pi.
A least squares minimization will yield a slightly different function.
It's not possible to generate one-off sin calls with just two multiplies (well, not a useful approximation, at any rate). But it is possible to generate an oscillator with low complexity, i.e. where each value is calculated in terms of the preceding ones.
For instance, consider that the following difference equation will give you a sinusoid:
y[n] = 2*cos(phi)*y[n-1] - y[n-2]
(where cos(phi) is a constant)
(From the original author of the VST BLT code).
As a matter of fact, I was porting the VST BLT oscillators to C#, so I was googling for good sin oscillators. Here's what I came up with. Translation to C++ is straightforward. See the notes at the end about accuumulated round-off errors.
public class FastOscillator
{
private double b1;
private double y1, y2;
private double fScale;
public void Initialize(int sampleRate)
{
fScale = AudioMath.TwoPi / sampleRate;
}
// frequency in Hz. phase in radians.
public void Start(float frequency, double phase)
{
double w = frequency * fScale;
b1 = 2.0 * Math.Cos(w);
y1 = Math.Sin(phase - w);
y2 = Math.Sin(phase - w * 2);
}
public double Tick()
{
double y0 = b1 * y1 - y2;
y2 = y1;
y1 = y0;
return y0;
}
}
Note that this particular oscillator implementation will drift over time, so it needs to be re-initialzed periodically. In this particular implementation, the magnitude of the sin wave decays over time. The original comments in the STK code suggested a two-multiply oscillator. There are, in fact, two-multiply oscillators that are reasonably stable over time. But in retrospect, the need to keep the sin(phase), and sin(m*phase) oscillators tightly in synch probably means that they have to be resynched anyway. Round-off errors between phase and m*phase mean that even if the oscillators were stable, they would drift eventually, running a significant risk of producing large spikes in values near the zeros of the BLT functions. May as well use a one-multiply oscillator.
These particular oscillators should probably be re-initialized every 30 to 100 cycles (or so). My C# implementation is frame based (i.e. it calculates an float[] array of results in a void Tick(int count, float[] result) method. The oscillators are re-synched at the end of each Tick call. Something like this:
void Tick(int count, float[] result)
{
for (int i = 0; i < count; ++i)
{
...
result[i] = bltResult;
}
// re-initialize the oscillators to avoid accumulated drift.
this.phase = (this.phase + this.dPhase*count) % AudioMath.TwoPi;
this.sinOsc.Initialize(frequency,this.phase);
this.mSinOsc.Initialize(frequency*m,this.phase*m);
}
Probably missing from the STK code. You might want to investigate this. The original code provided to the STK did this. Gary Scavone tweaked the code a bit, and I think the optimization was lost. I do know that the STK implementations suffer from DC drift, which can be almost entirely eliminated when implemented properly.
There's a peculiar hack that prevents DC drift of the oscillators, even when sweeping the frequency of the oscillators. The trick is that the oscillators should be started with an initial phase adjustment of dPhase/2. That just so happens to start the oscillators off with zero DC drift, without having to figure out wat the correct initial state for various integrators in each of the BLT oscillators.
Strangely, if the adjustment is re-adjusted whenever the frequency of the oscillator changes, then this also prevents wild DC drift of the output when sweeping the frequency of the oscillator. Whenever the frequency changes, subtract dPhase/2 from the previous phase value, recalculate dPhase for the new frequency, and then add dPhase/2.I rather suspect this could be formally proven; but I have not been able to so. All I know is that It Just Works.
For a block implementation, the oscillators should actually be initialized as follows, instead of carrying the phase adjustment in the current this.phase value.
this.sinOsc.Initialize(frequency,phase+dPhase*0.5);
this.mSinOsc.Initialize(frequency*m,(phase+dPhase*0.5)*m);
You might want to take a look here:
http://devmaster.net/forums/topic/4648-fast-and-accurate-sinecosine/
There's some sample code that calculates a very good appoximation of sin/cos using only multiplies, additions and the abs() function. Quite fast too. The comments are also a good read.
It essentiall boils down to this:
float sine(float x)
{
const float B = 4/pi;
const float C = -4/(pi*pi);
const float P = 0.225;
float y = B * x + C * x * abs(x);
return P * (y * abs(y) - y) + y;
}
and works for a range of -PI to PI
If you can, you should consider memorization based techniques. Essentially store sin(x) and cos(x) values for a bunch values. To calculate sin(y), find a and b for which precomputed values exist such that a<=y<=b. Now using sin(a), sin(b), cos(a), cos(b), y-a and y-b approximately calculate sin(y).
The general idea of getting periodically sampled results from the sine or cosine function is to use a trig recursion or an initialized (barely) stable IIR filter (which can end up being pretty much the same computations). There are bunches of these in the DSP literature, of varying accuracy and stability. Choose carefully.

C++ gamedev: truncating float to int

I'm making a game in C++ where is a tank that can moves on a stage. The tank has an angle (float, in degrees, and i'm supposing the tank is at 0º when his cannon points to the right), a speed (float), and there is a time constant called "deltaT" (float).
When the player moves the tank forward, I use trigonometry and the physic equation of position in function of time (I mean X(t), I don't know how it says in English) in order to calculate the new tank's coordinates in the stage.
This is my problem: due to the passage from float to int, the values closest to zero are not taken into account. So, at certain angles, the tank appears rotated, but moves in a different direction.
This is what my code does:
1 - first, I separate the speed in its components X and Y, by using the angle in which the tank is moving:
float speedX = this->speed * cos(this->angle);
float speedY = this->speed * sin(this->angle);
2 - then use the equation I mentioned above to get the new coordinates:
this->x = (int) ceil(this->x + (speedX * deltaT));
this->y = (int) ceil(this->y - (speedY * deltaT));
The problem begins at the first step: at certain angles, the value of the cos or the sin is very close to zero.
So, when I multiply it for speed to obtain, say, speedX, I still got a very low number, and then when I multiply it for deltaT it is still too low, and finally when apply the ceil, that amount is totally lost.
For example, at 94º, with deltaT = 1.5, and speed = 2, and assuming initial value of X is 400, we have:
speedX = -0.1395...
this->x = 400 //it must be 399.86..., but stays in 400 due to the ceiling
So, in my game the tank appears rotated, but moves straight forward. Also, sometimes it moves well backwards but wrong forward, and viceversa.
How can I do to make the direction of the tank more accurate? To raise the speed or the value of deltaT are not options since it's about a tank, not a formula 1.
How can I do to make the direction of the tank more accurate? To raise the speed or the value of deltaT are not options since it's about a tank, not a formula 1 :P
You should store your position values as floats, even though they are ultimately used as ints for on-screen positioning. That way, you won't lose the non-integer portion of your position. Just cast to int right at the end when you do your drawing.
Keep the location of the tank in floats all the time. Alternatively, only let the tank rotate in increments of 45 degrees. Decide on whether your game will use approximate positions and headings or exact ones and stick to that decision all the way through.
Your problem is not accuracy! Floating-point math has 24-bit accuracy, that's plus/minus 1/16,777,216. No problem there.
It's your rounding mode.
ceil rounds up.
Try:
int x = this->x + (speedX * deltaT) +.5f;
ceil creates a rounding error (E) of 0<E<1, casting as above gives -.5<E<+.5, which has half the absolute error.
Also, avoid using double math. ceil is the double version, you mean ceilf. Technically, your code casts float->double->int. You gain nothing from this, but it takes time.
And finally... The real problem:
Your accuracy problem really is because you are accumulating it!
So 0<E<1 ... PER FRAME!
at 60Hz => 0<E<60*seconds. Thus after a minute 0<E<3600
If X/Y are pixel coordinates, that's a whole screen! No wonder you are struggling.
No matter how you round, this is always going to be a problem.
Instead, you to store the floating point result before rounding. Thus the absolute error is always 0<E<1 ... or -.5f < E < .5f for mid-point rounding. Try adding a new floating point position - XPos/YPos
this->XPos += speedX * deltaT;
this->YPos += speedY * deltaT;
this->x = static_cast<int>(this->XPos+.5f);
this->y = static_cast<int>(this->YPos+.5f);
You should now move around smoothly.
PS: The word in English is "parametric", https://en.wikipedia.org/wiki/Parametric_equation

Very fast 3D distance check?

Is there a way to do a quick and dirty 3D distance check where the results are rough, but it is very very fast? I need to do depth sorting. I use STL sort like this:
bool sortfunc(CBox* a, CBox* b)
{
return a->Get3dDistance(Player.center,a->center) <
b->Get3dDistance(Player.center,b->center);
}
float CBox::Get3dDistance( Vec3 c1, Vec3 c2 )
{
//(Dx*Dx+Dy*Dy+Dz*Dz)^.5
float dx = c2.x - c1.x;
float dy = c2.y - c1.y;
float dz = c2.z - c1.z;
return sqrt((float)(dx * dx + dy * dy + dz * dz));
}
Is there possibly a way to do it without a square root or possibly without multiplication?
You can leave out the square root because for all positive (or really, non-negative) numbers x and y, if sqrt(x) < sqrt(y) then x < y. Since you're summing squares of real numbers, the square of every real number is non-negative, and the sum of any positive numbers is positive, the square root condition holds.
You cannot eliminate the multiplication, however, without changing the algorithm. Here's a counterexample: if x is (3, 1, 1) and y is (4, 0, 0), |x| < |y| because sqrt(1*1+1*1+3*3) < sqrt(4*4+0*0+0*0) and 1*1+1*1+3*3 < 4*4+0*0+0*0, but 1+1+3 > 4+0+0.
Since modern CPUs can compute a dot product faster than they can actually load the operands from memory, it's unlikely that you would have anything to gain by eliminating the multiply anyway (I think the newest CPUs have a special instruction that can compute a dot product every 3 cycles!).
I would not consider changing the algorithm without doing some profiling first. Your choice of algorithm will heavily depend on the size of your dataset (does it fit in cache?), how often you have to run it, and what you do with the results (collision detection? proximity? occlusion?).
What I usually do is first filter by Manhattan distance
float CBox::Within3DManhattanDistance( Vec3 c1, Vec3 c2, float distance )
{
float dx = abs(c2.x - c1.x);
float dy = abs(c2.y - c1.y);
float dz = abs(c2.z - c1.z);
if (dx > distance) return 0; // too far in x direction
if (dy > distance) return 0; // too far in y direction
if (dz > distance) return 0; // too far in z direction
return 1; // we're within the cube
}
Actually you can optimize this further if you know more about your environment. For example, in an environment where there is a ground like a flight simulator or a first person shooter game, the horizontal axis is very much larger than the vertical axis. In such an environment, if two objects are far apart they are very likely separated more by the x and y axis rather than the z axis (in a first person shooter most objects share the same z axis). So if you first compare x and y you can return early from the function and avoid doing extra calculations:
float CBox::Within3DManhattanDistance( Vec3 c1, Vec3 c2, float distance )
{
float dx = abs(c2.x - c1.x);
if (dx > distance) return 0; // too far in x direction
float dy = abs(c2.y - c1.y);
if (dy > distance) return 0; // too far in y direction
// since x and y distance are likely to be larger than
// z distance most of the time we don't need to execute
// the code below:
float dz = abs(c2.z - c1.z);
if (dz > distance) return 0; // too far in z direction
return 1; // we're within the cube
}
Sorry, I didn't realize the function is used for sorting. You can still use Manhattan distance to get a very rough first sort:
float CBox::ManhattanDistance( Vec3 c1, Vec3 c2 )
{
float dx = abs(c2.x - c1.x);
float dy = abs(c2.y - c1.y);
float dz = abs(c2.z - c1.z);
return dx+dy+dz;
}
After the rough first sort you can then take the topmost results, say the top 10 closest players, and re-sort using proper distance calculations.
Here's an equation that might help you get rid of both sqrt and multiply:
max(|dx|, |dy|, |dz|) <= distance(dx,dy,dz) <= |dx| + |dy| + |dz|
This gets you a range estimate for the distance which pins it down to within a factor of 3 (the upper and lower bounds can differ by at most 3x). You can then sort on, say, the lower number. You then need to process the array until you reach an object which is 3x farther away than the first obscuring object. You are then guaranteed to not find any object that is closer later in the array.
By the way, sorting is overkill here. A more efficient way would be to make a series of buckets with different distance estimates, say [1-3], [3-9], [9-27], .... Then put each element in a bucket. Process the buckets from smallest to largest until you reach an obscuring object. Process 1 additional bucket just to be sure.
By the way, floating point multiply is pretty fast nowadays. I'm not sure you gain much by converting it to absolute value.
I'm disappointed that the great old mathematical tricks seem to be getting lost. Here is the answer you're asking for. Source is Paul Hsieh's excellent web site: http://www.azillionmonkeys.com/qed/sqroot.html . Note that you don't care about distance; you will do fine for your sort with square of distance, which will be much faster.
In 2D, we can get a crude approximation of the distance metric without a square root with the formula:
distanceapprox (x, y) =
which will deviate from the true answer by at most about 8%. A similar derivation for 3 dimensions leads to:
distanceapprox (x, y, z) =
with a maximum error of about 16%.
However, something that should be pointed out, is that often the distance is only required for comparison purposes. For example, in the classical mandelbrot set (z←z2+c) calculation, the magnitude of a complex number is typically compared to a boundary radius length of 2. In these cases, one can simply drop the square root, by essentially squaring both sides of the comparison (since distances are always non-negative). That is to say:
√(Δx2+Δy2) < d is equivalent to Δx2+Δy2 < d2, if d ≥ 0
I should also mention that Chapter 13.2 of Richard G. Lyons's "Understanding Digital Signal Processing" has an incredible collection of 2D distance algorithms (a.k.a complex number magnitude approximations). As one example:
Max = x > y ? x : y;
Min = x < y ? x : y;
if ( Min < 0.04142135Max )
|V| = 0.99 * Max + 0.197 * Min;
else
|V| = 0.84 * Max + 0.561 * Min;
which has a maximum error of 1.0% from the actual distance. The penalty of course is that you're doing a couple branches; but even the "most accepted" answer to this question has at least three branches in it.
If you're serious about doing a super fast distance estimate to a specific precision, you could do so by writing your own simplified fsqrt() estimate using the same basic method as the compiler vendors do, but at a lower precision, by doing a fixed number of iterations. For example, you can eliminate the special case handling for extremely small or large numbers, and/or also reduce the number of Newton-Rapheson iterations. This was the key strategy underlying the so-called "Quake 3" fast inverse square root implementation -- it's the classic Newton algorithm with exactly one iteration.
Do not assume that your fsqrt() implementation is slow without benchmarking it and/or reading the sources. Most modern fsqrt() library implementations are branchless and really damned fast. Here for example is an old IBM floating point fsqrt implementation. Premature optimization is, and always will be, the root of all evil.
Note that for 2 (non-negative) distances A and B, if sqrt(A) < sqrt(B), then A < B. Create a specialized version of Get3DDistance() (GetSqrOf3DDistance()) that does not call sqrt() that would be used only for the sortfunc().
If you worry about performance, you should also take care of the way you send your arguments:
float Get3dDistance( Vec3 c1, Vec3 c2 );
implies two copies of Vec3 structure. Use references instead:
float Get3dDistance( Vec3 const & c1, Vec3 const & c2 );
You could compare squares of distances instead of the actual distances, since d2 = (x1-x2)2 + (y1-y2)2+ (z1-z2)2. It doesn't get rid of the multiplication, but it does eliminate the square root operation.
How often are the input vectors updated and how often are they sorted? Depending on your design, it might be quite efficient to extend the "Vec3" class with a pre-calculated distance and sort on that instead. Especially relevant if your implementation allows you to use vectorized operations.
Other than that, see the flipcode.com article on approximating distance functions for a discussion on yet another approach.
Depending slightly on the number of points that you are being used to compare with, what is below is pretty much guaranteed to be the get the list of points in approximate order assuming all points change at all iteration.
1) Rewrite the array into a single list of Manhattan distances with
out[ i ] = abs( posn[ i ].x - player.x ) + abs( posn[ i ].y - player.y ) + abs( posn[ i ].z - player.z );
2) Now you can use radix sort on floating point numbers to order them.
Note that in practice this is going to be a lot faster than sorting the list of 3d positions because it significantly reduces the memory bandwidth requirements in the sort operation which all of the time is going to be spend and in which unpredictable accesses and writes are going to occur. This will run on O(N) time.
If many of the points are stationary at each direction there are far faster algorithms like using KD-Trees, although implementation is quite a bit more complex and it is much harder to get good memory access patterns.
If this is simply a value for sorting, then you can swap the sqrt() for a abs(). If you need to compare distances against set values, get the square of that value.
E.g. instead of checking sqrt(...) against a, you can compare abs(...) against a*a.
You may want to consider caching the distance between the player and the object as you calculate it, and then use that in your sortfunc. This would depend upon how many times your sort function looks at each object, so you might have to profile to be sure.
What I'm getting at is that your sort function might do something like this:
compare(a,b);
compare(a,c);
compare(a,d);
and you would calculate the distance between the player and 'a' every time.
As others have mentioned, you can leave out the sqrt in this case.
If you could center your coordinates around the player, use spherical coordinates? Then you could sort by the radius.
That's a big if, though.
If your operation happens a lot, it might be worth to put it into some 3D data structure. You probably need the distance sorting to decide which object is visible, or some similar task. In order of complexity you can use:
Uniform (cubic) subdivision
Divide the used space into cells, and assign the objects to the cells. Fast access to element, neighbours are trivial, but empty cells take up a lot of space.
Quadtree
Given a threshold, divide used space recursively into four quads until less then threshold number of object is inside. Logarithmic access element if objects don't stack upon each other, neighbours are not hard to find, space efficient solution.
Octree
Same as Quadtree, but divides into 8, optimal even if objects are above each other.
Kd tree
Given some heuristic cost function, and a threshold, split space into two halves with a plane where the cost function is minimal. (Eg.: same amount of objects at each side.) Repeat recursively until threshold reached. Always logarithmic, neighbours are harder to get, space efficient (and works in all dimensions).
Using any of the above data structures, you can start from a position, and go from neighbour to neighbour to list the objects in increasing distance. You can stop at desired cut distance. You can also skip cells that cannot be seen from the camera.
For the distance check, you can do one of the above mentioned routines, but ultimately they wont scale well with increasing number of objects. These can be used to display data that takes hundreds of gigabytes of hard disc space.