Calculating distance

Started by Chrille, Wed 27/01/2010 17:58:47

Previous topic - Next topic

Chrille

I'm trying to make a function for calculating the distance between characters. The trick is that I'd like to add the factor of a character's scale in there. For example:

Character A is at 160x220, unscaled at 100. Character B is at 192x195 at a scale of 25. So instead of just getting the pixel distance from 160x220 to 192x195, Character's B values should be much higher since he is further away in perspective. Also, perhaps the Y value should be slightly higher than X because of the depth.

I tried to calculate this but I'm not happy with the results, my head just spins trying to figure it out. I'd be very grateful if anyone has any suggestions for doing this.
GASPOP software
http://www.gaspop.com

Snarky

First of all, if we assume that all characters are standing on a flat, even plane, you only need the X-coordinate and the depth (let's call it Z).

The distance D between two characters, by Pythagoras, is calculated thus:

D = sqrt( (X1-X2)^2 + (Z1-Z2)^2 )

But here the X and Z coordinates are in the real-world plane, not screen coordinates. So first you need the values of X1, X2, Z1, and Z2.

The scaling factor is inversely proportional to the depth Z. So if we assume that a character at 100% scaling is at distance of 1 unit (let's say 10 meters), a character at 50% scaling is at a distance of 2 units, 20 meters. That gives you Z1 and Z2.

Then you need to figure out the horizontal scaling. Let's say that at 100% scaling, the distance from the left to the right edge of the screen is 20 meters. So that's 10 meters on each side of the center line. Then the same way you get twice the distance at half the scaling level, so it'd be 20 meters at 50% scaling, and so on. That gives you X1 and X2, and hey presto!

Khris

You need to factor in a z coordinate.
First, get from scaling to z.
scaling=100 -> z=100
scaling=25 -> z=400
(arbitrary definition)
Thus: z=10000/scaling (This relation is fine for perspective calculations; basically 2Dx=x/z and 2Dy=y/z)

Now we need the x coord difference. This is sorta easy; since we're looking for the difference, the point of reference can be anywhere. We'll take x=0.
So a character at scaling=50 is at z=200; all we need is double his x coord (a distance appears half as wide at z*2)
3D_x = x * (z/100)

Using Character B:
z = 10000/25
z = 400
3D_x = 192*4 = 768.

dx = 608
dz = 300
distance: 678.

Code: ags
int Distance(Character*a, Character*b) {
  int z1 = 10000/a.Scaling, z2 = 10000/b.Scaling;
  int x1 = a.x*(z1/100), x2 = b.x*(z2/100);
  int dx = x1-x2, dz = z1-z2;
  return FloatToInt(Maths.Sqrt(IntToFloat(dx*dx+dz*dz)));
}

Snarky

#3
The trick is that you have to know the proportion between Z and X. (Khris's function assumes that the proportion is 100:320, on a 320x200 screen.) In other words, how far away is a character at 100% scaling, and how far is it in real-world distance to each edge of the screen at that distance? I think you can probably calculate this from the Y-coordinate of the horizon (i.e. 0% scaling) and the Y-coordinate where you have 100% scaling, but you can also eyeball it.

Edit: Also, you can't take the x point of reference to be anywhere, since you're scaling the value by the distance (which varies) before you calculate the difference. Your origin should therefore be in the middle of your field of view (presumably x=160 on a 320x200/240 screen). Otherwise you're saying that your vanishing point is on the left edge of the screen, which will cause massive perspective distortion on the right side of the screen.

Here's an illustration:



And in pseudo-
Code: ags
x_scale = 320/8; // = 40
z_scale = 8/2; // Half the x-width. Implies 60-degree FOV
A.3D_x = (A.x - 160) * (100 / A.scale) / x_scale; // (200 - 160) * 1 / 40 = 1
B.3D_x = (B.x - 160) * (100 / B.scale) / x_scale; // (120 - 160) * 2 / 40 = -2

A.3D_z = z_scale * (100 / A.scale); // = 4
B.3D_z = z_scale * (100 / B.scale); // = 8


dx = 1-(-2) = 3 and dz = 4-8 = -4, so do the Pythagoras thing and you get distance = 5. The top-down view makes it clearer:



If the characters are about 1.8 m tall then one unit is 0.85 m, they're standing 4.25 m apart, and character A is 3.4-3.5 m away from the viewer (depending on whether we use the distance implied by the scaling factor, which varies with z-distance only, or the Pythagorean distance).

Khris

Right, disregard my solution :)
I didn't think of x being 0 equals putting the VP at the left edge.

Goldfish

Snarky, if we could vote for best thread- this would get my vote. Fantastic.

Snarky

Thanks. I should warn you though that the diagram and image don't match (x-width at A-depth is 8 and 4, resp.) and the scaling in the image is therefore too extreme. B should be at 66.6...% scaling, not 50% to make it consistent with a corrected diagram.

Goldfish

It's still terrific, and terrifically clear. I have actually solved this problem independently, but couldn't explain it with the wit and wisdom you showed.

Chrille

The function works perfectly! Thanks for taking the time, guys. The illustrations made it much easier for me to understand.
GASPOP software
http://www.gaspop.com

SMF spam blocked by CleanTalk