16
\$\begingroup\$

So I was thinking about creating a 2D game where you can also move along the Z-axis, by changing in which layer you are. Depending on the depth I want to scale my 2D sprites.

Once, someone had shown me a demo in which he had a lot of 2d sprites, and by scrolling he could change the depth of the camera. So when zooming in, the objects would come closer to the player, and appear bigger. Then I wondered, how much bigger should an object be when it gets 1 unit closer. How would you calculate that? So the guy told me: There is one basic rule I am using: "objects twice as close, appear twice as big."

Now, by testing it myself, I know that rule doesn't apply in the real world ;) But is there some constant that is used in real world calculations for perspective or something? Or a formula?

I know this might not be the best place to ask such a question, but since this is the only site I use for game-related questions, and my context is a game, I thought I'd give it a try. Also, I am kind of expecting that there is this person here that knows everything about 3D perspectives and matrices or something, since it might relate to 3D games ;)

tl;dr:

"an object twice as close, appears twice as big" That is not true in the real world. But which constant or formula is correct?

\$\endgroup\$
6
  • 3
    \$\begingroup\$ I have no clue what the answer is but I know how I could find out. Take some pictures of something. Maybe a piece of paper. Take them from different known distances and then do some math to calculate how much of the image is taken up by the piece of paper and determine the ratio by that. Could be a fun experiment! \$\endgroup\$ Mar 15, 2013 at 17:12
  • \$\begingroup\$ I'm wondering why nobody has mentioned anything about natural logarithms... \$\endgroup\$ Mar 15, 2013 at 21:30
  • 4
    \$\begingroup\$ Why is it not true? I think it is true. \$\endgroup\$ Mar 15, 2013 at 23:07
  • \$\begingroup\$ @hydroparadise What do natural logarithms have to do with this question? \$\endgroup\$ Mar 16, 2013 at 0:47
  • \$\begingroup\$ I'm just being pedantic here I know, but "Twice as close" is an odd phrase. Shouldn't it be "Half as far away"? 'Twice' is bigger, but if something gets closer then the distance gets smaller. \$\endgroup\$
    – MrVimes
    Mar 16, 2013 at 11:20

6 Answers 6

20
\$\begingroup\$

Generally it is true, depending on your view point and in which direction it has moved, as well as the viewing angle.

Example of perspectives for objects

Note how in the first camera view, as the Red block is perpendicular to the camera view, the object seems to be twice as large in a perfect 1:2 ratio (Note the arrow pointing that it hits the edge of the view after being moved twice as close)

The second is the same size block rotated at 45 degrees. As it is rotated, the bottom edge is no longer at the same distance from the camera as the top edge, so it does not SEEM correctly scale to a 1:2 ratio but it in actual fact is twice as large (as it is at the same angle on the further away blue block as it is in the close blue block.)

In conclusion this actually means your friend was correct and a 1:1 ratio ("objects twice as close, appear twice as big.") for your objects is a good choice.

\$\endgroup\$
3
  • 5
    \$\begingroup\$ What does 3D perspective math have to do with viewing angels? ;) \$\endgroup\$ Mar 16, 2013 at 6:44
  • \$\begingroup\$ Great answer! The pictures definitely make it more clear. Actually I feel really stupid now, since I tried this before posting the question by holding my hand in front of my face and moving it closer. And then I thought: no it doesn't feel like twice as big.... I should've measured it more acurately ;) Perspective is a funny thing! Also, Ifeel like I should have been able to come up with the pictures myself ;) But great answer! Thanks! \$\endgroup\$
    – Berry
    Mar 16, 2013 at 9:11
  • \$\begingroup\$ @Mason Wheeler - Sorted :P \$\endgroup\$ Mar 16, 2013 at 11:03
9
\$\begingroup\$

An object twice as close does appear twice as big. It is a consequence of Thales's Theorem and it is true in the real world.

One could argue that Thales's Theorem is the core mathematical tool behind perspective projection and what's known in the graphics pipeline (OpenGL or DirectX) as perspective division. It a theorem you should definitely know, and learn to recognise when it can be used.

\$\endgroup\$
1
  • \$\begingroup\$ Great references! I will definitely check Thales Theorem out, and try to understand the graphics pipeline better. \$\endgroup\$
    – Berry
    Mar 16, 2013 at 9:14
7
\$\begingroup\$

Actually that's pretty much true (if you move an object twice as far away it looks half as big) but it obscures how the visual size of objects should change as the viewers moves. Specifically, objects appear to get bigger faster the closer they are. That's because the viewer covers half the distance a lot faster when the object is close, compared to when the object is further away. Or to put it another way, while the viewer's speed is constant, the value of "half the distance" changes as the distance to the object changes.

\$\endgroup\$
2
\$\begingroup\$

Since you're not actually working in 3D space, we can assume the sprites never rotate (rotation can be simulated with skewing, etc.) This simple constraint makes it pretty easy to get somewhat accurate numbers on what the size should be depending on distance from the camera.

First, you need to understand how 3D objects are rendered. Even though a camera converges to single point, there is an invisible plane that acts as a screen on which to draw the objects. The only thing you need to know about the screen is how far away it is from the camera.

Here is a diagram of how an object is rendered to a camera at two different distances.

As you would expect, the height of the object is dependent on the the distance from the camera. BUT since rending occurs on the near culling plane, we must calculate the height of the sprite at that point.

Some basic trig calculations will lead you to the following formula:

f(d, v) = v/(v+d)
* Where f is the size ratio to the original sprite aka size factor
    and v is the distance to the near clipping plane (trial and error value)
    and d is the distance from the near clipping plane to the object

EXAMPLE:

Assuming you have a sprite that is 2.5x1.8 units in size and 10 units away 
   from the camera, and that the near clipping plane is 5 units from the camera.

sizeFactor = 5/(5+10) = 0.3

renderHeight = actualHeight * sizeFactor = 1.8 * 0.3 = 0.54
renderWidth  = actualWidth * sizeFactor = 2.5 * 0.3 = 0.75

I would suggest starting with v=5 and then adjust from there based on how it looks. I may throw a fiddle together that allows you to see the changes in realtime.

TL;DR

The change in height or width should be multiplied by the following factor:

sizeFactor = v/(v+d)

Where v = Some number greater than 0 that never changes (try 1 thru 5)
  and d = the distance from the camera

So an object that is 2.5 units tall would be rendered at 2.5*sizeFactor units tall.

EDIT: When you say move along the z-axis I'm assuming you will want a perspective view (like most 3D games; shooters, etc.) The math to calculate object size based on distance will also depend on location in the frame, similar to peripheral vision. Instead, I would try it with my math which is an orthographic view (think Mario, Angry Birds, Super Smash Bros, etc.). I don't know the look and feel you are trying to achieve, but as long as it seems real then the players will never know!

DEMO!

\$\endgroup\$
5
  • \$\begingroup\$ Yes I am actually aiming for an orthographic view. The game I am "borrowing" my current inspiration from is Rayman Origins. In some sections of the game you can jump on flowers, and then you will bounce in another layer with a different depth. Then the camera zooms in or out corrspondig to that depth. Axamples can be seen in this video, at 4:50 and 5:00. \$\endgroup\$
    – Berry
    Mar 16, 2013 at 9:34
  • \$\begingroup\$ Furthermore, great answer! But since just a confirmation that the rule "twice as close, twice as big" does apply would've been enough, I chose Blue's answer as the best. \$\endgroup\$
    – Berry
    Mar 16, 2013 at 9:51
  • \$\begingroup\$ Thank you, and best of luck with your game! But I do want to clarify for others that "twice as close, twice as big" will work great if everything is very close to the camera. As things get further away, the perceived change in size reduces. For example, look at your thumb up close, then extend your arm and look at it. The size of your thumb appears drastically smaller. After that, look at something far away. Take one step backwards (about the same as your arm length). Notice how the size barely changed? If a game has a long field of view, using a little bit of math will go a long way. \$\endgroup\$
    – Jim Buck
    Mar 18, 2013 at 15:20
  • \$\begingroup\$ EDIT: I made a mistake in my previous comment. "Twice as close, twice as big" is correct when the items remain fairly close to each other with respect to their distance from the camera. \$\endgroup\$
    – Jim Buck
    Mar 18, 2013 at 16:24
  • \$\begingroup\$ Here is a quick demo I put together, use the mouse to move and the scroll wheel to change the depth. \$\endgroup\$
    – Jim Buck
    Mar 18, 2013 at 21:16
1
\$\begingroup\$

You have to define "twice as big". A line will be twice as long, or tall, at half the distance, but simple mathematics tells us that the surface area of a rectangle, for example, is the height multiplied by the width. The result is that any object with both length and height will be four times as big at half the distance. Binoculars with 8x augmentation will show objects other than lines to appear 64 times bigger.

\$\endgroup\$
0
\$\begingroup\$

This wasn't covered and I thought this might be beneficial: It should be noted when you half the distance, doubling the size in both X and Y dimensions will quadruple the total area of the sprite. This is because:

Area = X * Y

After Zooming in:

NewArea = (x*2) * (y*2)

This may give you the impression that the zooming effect is happening quickly or is too intense. You can adjust the factor by changing 2 in the above formula to a float value like 1.5 or 1.33 instead.

Alternatively, what I've done is store camera depth (distance) to your tiles in a byte value along with camera translation (X and Y) then calculate projected tile size thusly:

XTileSize = (255 / CameraZ) * DefaultTileWidth
YTileSize = (255 / CameraZ) * DefaultTileHeight

Note that CameraZ has to be strictly between 1-255, and that restriction may be a benefit or a bane to you in the future.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .