Adjust scale of object based on distance to maintain same perceived size

Hi all,

Having a little trouble explaining what I am trying to do so please bear with me.
I am working on a demo that involves massive scales in the space. To make things more manageable I want to do is keep the planets closer together in game units, but scale them so that they appear to be the real world size as seen from that location.

For example let’s say the camera is at the Earth. Instead of putting the sun 150 million kilometers away and making it have a radius of 695,700km, I want to put it say just 10,000 meters away from the Earth but scale it down (some unknown amount) so that the PERCEIVED size would be the same.

However despite an hour or so of Googling I can’t seem to figure out how to calculate the scale factor based on distance. I ran into some topics about perceived angle, but I don’t understand what that means, nor how I could even translate an “angle” into a size in game.

I feel like I am close to the answer, spiraling in on it but not quite hitting it. Here is the code I am currently using. This is in C#

Vector3d activeRealPosition = activeBody.GetOrbitPosition("real");
Vector3d activeGamePosition = activeBody.GetOrbitPosition("play");
Vector3 realOrbitPosition = Vector3.zero;
Vector3 actualOrbitPosition = Vector3.zero;
if (TypeOfBody != BodyType.Star)
{
	realOrbitPosition = transform.TransformPoint(_orbits["real"].position); // CelestialOrbit stores position in local space
	actualOrbitPosition = transform.TransformPoint(_orbits["play"].position);
}
double realDistance = Vector3d.Distance(activeRealPosition, realOrbitPosition);
double actualDistance = Vector3d.Distance(activeGamePosition, actualOrbitPosition);

Debug.Log("Real Distance: " + realDistance + ", Actual Distance: " + actualDistance);
// actual distance should always be much smaller than real distance
if (actualDistance > realDistance)
	Debug.LogWarning("[UpdateScale] Actual distance is larger than real distance");
double difference = (realDistance - (realDistance-actualDistance)) / (realDistance);
Debug.Log("Difference: " + difference);
double newScale = RealRadius * difference;
transform.localScale = Vector3.one * (float)newScale;

I am basing it on some manual tests I did just positioning two objects at different distances and looking if they appear the same size, and in those manual setups they did. So I then tried to apply that math to the real deal, but it doesn’t work. The math is based on: Percentage Change Calculator

Note: I have not actually tested this out. Please let me know if it fails, so I can remove this post.

I think you can use the law of similar triangles to figure this out.

Givens:

SunActualRadius, SunActualDistanceFromCamera, SunGameUnitDistanceFromCamera

Desired output:

SunGameUnitRadius

Make a right triangle using SunActualRadius as side A, and SunActualDistanceFromCamera as side B. The angle to the hypotenuse defines how “big” the sun looks from the camera position.
How we use this angle, is simply by duplicating it: Draw an identical right triangle, with the same angles.
Now, label side A of this new triangle SunGameUnitRadius and side B SunGameUnitsFromCamera.
Since these two triangles are identical, the ratio of sides A and B will also be identical.
Expressed as a formula:

SunActualRadius/ SunActualDistanceFromCamera = SunGameUnitRadius/ SunGameUnitDistanceFromCamera

Solve for our desired output:

SunGameUnitRadius = SunActualRadius * SunGameUnitDistanceFromCamera / SunActualDistanceFromCamera

i think you’re making this too hard.

just scale everything down by some constant factor.

in this case your scale factor would be 10,000 meters divided by 150,000,000,000 meters.
so just multiply 695,700,000 by (10,000 / 150,000,000,000) to get the scaled radius.