- Home /
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: http://www.calculatorsoup.com/calculators/algebra/percent-change-calculator.php
Deter$$anonymous$$e your planet's size on the screen:
float getScreenSize ()
{
transform.LookAt(Camera.main.transform, transform.up);
Bounds bounds = gameObject.GetComponent().bounds;
Vector3 v1 = Camera.main.WorldToScreenPoint(transform.position - 0.5f * bounds.size.y * transform.up);
Vector3 v2 = Camera.main.WorldToScreenPoint(transform.position + 0.5f * bounds.size.y * transform.up);
return Vector3.Distance(v1, v2);
}
I have assumed the shape of your planets is spherical. Note that the results of the above will not be reliable with the planets screen size is around or exceeds the screen height.
Then rescale the object to the desired size by stetting transform.localScale.
Interesting take on the problem, but I am not sure using the camera to deter$$anonymous$$e screen size would work as the camera isn't always seeing these objects. Basically body that isn't the active planet needs to be scaled down, in case the player does move the camera in such a way as to see them.
In any case, I finally found my problem with fresh eyes this morning. I should not have been transfor$$anonymous$$g the orbital values from Local to World space. Once I changed that it started working well.
Answer by Glurth · Dec 31, 2016 at 11:49 PM
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
Answer by elenzil · Jan 01, 2017 at 05:19 AM
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.
Your answer
Follow this Question
Related Questions
How to get the correct ratio of collision distance to total scale? 1 Answer
Sprite doesn't flip correctly. 1 Answer
How to simplify the equation of a moving vertex if its object is squeezed? 0 Answers
Calculate launch angle based on launch direction 2 Answers
Very big numbers (size, mass, etc), Scientific Notation 2 Answers