2
\$\begingroup\$

I want the maps in the game I'm working (in Java) to be draw with perspective just to sugar coat it, but I'm not sure how that can be done. If anyone has an article about the math behind it or something similar, that would be greatly appreciated.

Something looking similar to the plain shown on this image found on Google Images:

2d plain in perspective

(not my image, I take no credit)

EDIT: The game is indented to be in 2D, I can draw the map into BufferedImage and then warp it somehow to make it perspective. Just a thought. The real question is, how would the image of the map be warped to to have the angled effect? (Please note, I am trying to avoid using 3D by warping the plain to simulate an angled view)

\$\endgroup\$
  • \$\begingroup\$ Do you want the camera to move across this map? (Rendering one frame is easier than real-time movement). If you wish to have motion, using 3d may be very wise. If you just want to render a still image, I could easily provide you with a generic algorithm. \$\endgroup\$ – wolfdawn Jan 12 '14 at 20:02
  • \$\begingroup\$ I wish for the player to be in the middle, and walk around by moving the map in the opposite direction. Similar to old 2.5D games. \$\endgroup\$ – 8bitslime Jan 13 '14 at 3:46
2
\$\begingroup\$

I wrote some code to explain how this could be done in software:

    evaluatePixel()
    {
        const float2 ofst    = float2(0.0, 0.0);
        const float2 imgSize = float2(2050.0, 1700.0); // image size
        const float M = 2.2;
        const float MDZ = 1.0 + 2.0 / (M - 1.0);
        const float H = 1.0 + MDZ;

        float2 c2D = float2(2.0, - 2.0) * (outCoord() / imgSize) + float2(- 1.0, 1.0);

        float dz = 1.0 + (1.0 + c2D.y) / (M - c2D.y);

        float2 c3D = float2(c2D.x, c2D.y + 1.0) * float2(dz, dz);
        c3D.x /= 1.7 * MDZ;
        c3D.y = c3D.y / H - 0.5;

        if(outCoord().x < imgSize.x && outCoord().y < imgSize.y){
            dst = sampleLinear(src, (c3D + float2(0.5, 0.5)) * imgSize + ofst);
        } else{
            dst.rgb = float3(0.0, 0.0, 0.0);
            dst.a = 0.0;
        }

    }

This is what it looks like:

Result

And this is what it looked like before the effect:

enter image description here

The image was taken from this page:

http://www.lughertexture.com/tiles-new-hires-textures/modern-and-vintage-tiles-textures/stone-tiles-light-762

Older answer: Look at what they did in this game: http://www.newgrounds.com/portal/view/631599

The trees' leaves are layered in different distances.

If you wish to save time, you should probably use your existing map as a texture for a 2-d plain and position your camera in the desired angle. You could take a screenshot in-game and play around in Blender to figure out the desired angle.

Since you wish to explore this for deductive purposes and for interest, I will point out how it's done.

Imagine the screen (display) plain. You have a matrix (2d array) of pixels on the display. All those pixels originate from tiles in the tile map which is a 2d-array of blocks of pixels. We could generalize this to seeing the tile map as a 2d-array of pixels.

Now, we simply need a function that takes x, y in the display and pulls out the correct x', y' from the pixel array that is the tile map. That is a form of rendering.

The function obviously depends on the placement (height, offset) and angle of the camera.

Imagine the display is a window and the tile map is beyond that window and you only have one eye and you are tracing a line between that eye and the tiles. Where the line hits the display, that is where the color from the tile map goes. I believe this is called ray-tracing.

In simple terms, to get you started, lets say the tile map is laying flat and your eye is a camera that is 1000 units from the monitor and 500 units above the plain. We will also say that the pixels closest to us are in y = 0 and that the center line on the screen is in x = 0.

Ray trace example

Now we have a line and we could use math to figure out where is headed on the tile map. In your case, a simple plain, the mat is also simple. If the eye is looking through the center of the monitor, any pixel above that will not hit the plain if the camera is pointing straight forward. Pixels bellow that point we can calculate like this:

We are assuming each pixel is the size of one unit and that we are d = 1000 (distance) units away from the monitor right now and 500 units above the tile-map plain. If we are looking at a pixel that is 100 units bellow the center, the ratio is 100 / 1000 = 0.1. To reach the tile-map plain it will need to go down another 500 - 100 = 400 units so it will required another 400 / 0.1 = 4000 steps on the y axis. We could adjust the constants to suit the game design and resolution. The same is being done with the x offset. If you wish to give the camera an angle, it is entirely possible with a tiny bit of additional complication.

To do the rendering fast though, you would probably need to rely on an existing library.

\$\endgroup\$
  • \$\begingroup\$ I have messed around, and I have ALOT of time on my hands. (This game is purely a hobby while I continue to study computer science) But the different distances of objects it a very good idea! Thanks! \$\endgroup\$ – 8bitslime Jan 13 '14 at 3:54
  • \$\begingroup\$ Now this is very useful but the main goal I'm trying to achieve is warping the 2d plain that is the tile-map into a simulated camera angle pushing towards the retro 2.5D feel. But I may add a feature to the game engine I'm making side-by-side to the actual game about different z-indexes and the math behind it. \$\endgroup\$ – 8bitslime Jan 15 '14 at 6:08
  • \$\begingroup\$ Added some code showing how it's done \$\endgroup\$ – wolfdawn Jan 18 '14 at 9:20
  • \$\begingroup\$ That is exactly the effect I wanted! I'm still slightly confused on how the code actually works, and how to apply it. Do you think you could comment it for me? I was also looking into a graphics2D object and its shearing ability, would that have the same look? \$\endgroup\$ – 8bitslime Jan 21 '14 at 10:01
  • \$\begingroup\$ This thing is called a pixel shader. Try downloading Pixel Bender. I can share the full source code. What it does basically is use a function that gets (x, y) and figures out what pixel to put there. In this example it does pretty much what I've drawn up there: sends imaginary rays through the screen from where it expects your eyes (green circle) to be into a 2d tile map (orange square) that is positioned behind the screen and then uses those rays to figure the color of every pixel on the screen. \$\endgroup\$ – wolfdawn Jan 21 '14 at 10:19
4
\$\begingroup\$

If you are looking to use any 3D objects (lets say a chessboard with 3d pieces), you could make a series of quads, then manipulate the camera's position and target to get the angle/perspective that you want.

\$\endgroup\$
  • \$\begingroup\$ This. Even if you're not going to use 3D Objects, painting a 2D plane in 3D is going to make perspective much easier. \$\endgroup\$ – Cameron Fredman Jan 12 '14 at 9:11
0
\$\begingroup\$

Diablo2 did this just with 2D, look at some screenshots and you see the foreground(bottom) tiles are bigger then the background(top) tile. I asked a question about this in the past the answer was basically that it is just too much hassle and hacking to get things right. It makes much more sense if we convert the 2D tile to a 3D scene.

You need to look for bill-boarding. Basically you need to make each tile a "3D" flat plane/billboard. Render them together and just setup a perspective camera. This way you have the benefit of both 2D and 3D worlds. This does however require you to dig a bit into 3D graphics and shading like (HLSL).

\$\endgroup\$
  • \$\begingroup\$ That perspective effect was only enabled in Diablo 2 when you were rendering with Direct3D (it was grayed out if you were rendering through Direct2D), so I'd guess they did use the 3D quad + billboarding method. \$\endgroup\$ – Jimmy Jan 12 '14 at 23:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.