15

I'm making a canvas-based game engine and am wondering if anyone has any good info on how to achieve an overhead view perspective. What I'm looking for is somewhere halfway between the traditional birds eye view and the old SNES mode7 view. Just a slight angle to give the illusion of 3D.

I'm trying to figure out what is going to be the best way to deal with the perspective skewing. I'm not doing rotations so 3D matrix stuff would be going overboard, but I need to be able to deal with rendering the map layers at a consistent angle and it'd be nice if the angle was adjustable. I also need to deal with the depth warp. Basically, the bottom row of pixels should be 1:1 pixel width and height, then for each row it'd get, for example, 5% smaller or something like that. What I'd like is to be able to supply a large canvas as a texture and then supply a camera angle between 0 and 90 where 0 is perfectly horizontal and 90 is birds eye view.

Anyone have any related tutorials or sample code? I've searched online a bit, but everything I've found seems to either be unsuitable for use in this particular application or overly complex, doing all sorts of crazy 3D skewing and rotation stuff. All I want is to take the normal tiled grid and lean it back a bit, no rotations or complicated stuff like that.

Here's an example of what I want; Here's an example. http://img801.imageshack.us/img801/2176/perspectivesample.jpg

The bottom pixel row is 1:1 pixel ratio, and each row above that progressively gets shorter horizontally and vertically. The source texture of the top center region is normally about half the height of the bottom center region, but it has been shrunk vertically and horizontally to fit the perspective.

What I'm thinking might work best is to render the current viewport state to another canvas in flat, birds eye view, with approximately 50% extra space on the top and sides, then slice an upside triangular region from that and draw that to the actual visible canvas.

Only problem is, I suck at math when it comes to calculating angles and such.

Stephen Belanger
  • 6,251
  • 11
  • 45
  • 49
  • 1
    Do you have a graphical example somewhere online? Just want to get a more definite idea of what you want. Thanks – Castrohenge Oct 01 '10 at 12:54
  • I added a picture, to represent what I want. The map is actually a 32x32 grid pattern, but tilted backwards to add perspective. – Stephen Belanger Oct 01 '10 at 16:51
  • 3
    This is interesting: http://acko.net/blog/projective-texturing-with-canvas – Josh Lee Oct 01 '10 at 17:35
  • Don't have anything a little easier to understand? Like I said, I don't need all this complex extra stuff, I just want something relatively simple. Surely I don't need several hundred to a thousand lines of code to do something this basic. – Stephen Belanger Oct 01 '10 at 23:23
  • 1
    Let me get this straight. You want to rotate a 3D view around the X axis, and you want to do it using a 2D API without using "all sorts of crazy 3D skewing and rotation stuff"? How can that work? – Stefan Monov Oct 03 '10 at 07:23
  • 1
    No. I don't want any rotations. I only want to lean a rectangular texture back to make it look like it has perspective by making the top row of pixels narrower than the bottom row. That on it's own isn't too overly difficult to figure out, but it also needs to be able to handle textures that aren't perfectly centered by making the angle on one side different than the other side. That's what I need help with...I suck at vector match. >.> – Stephen Belanger Oct 03 '10 at 20:13
  • shouldn't this be easy with the right transformation matrix, context.setTransform(....)? – oberhamsi Jan 26 '13 at 20:45
  • Did you ever got the mode-7 look out of a canvas working? – eri0o Feb 04 '15 at 03:48

2 Answers2

7

if i understand you right, you just want a simple trapeze transformation. if so, maybe this or this link helps you out. for images that aren't centered it would just be an additional rhomboid tranformation, wich is easily possible with canvas, as far as i know.

oezi
  • 51,017
  • 10
  • 98
  • 115
4

What you're talking about is something that can be done simply with any 3D api. However since you've decided to try to stick to 2D canvas, you have to do everything in the 2D world which means working with rectangles, rotation, scaling, skewing, etc. Also know as affine transformations as mentioned the other answer.

What you want to do is possible, but since you want to use 2D you have to think in terms of 2D functions.

  1. Generate your initial image.
  2. Add a slice from the bottom of the original image to the bottom of the canvas, very slightly positioned to the left so the center of the image matches up with the center of the current canvas.
  3. Very slightly increase the scale of the entire image
  4. Repeat until you get to the top of the image.

The Pseudo code would look like this...

imgA = document.getElementById('source');

// grab image slices from bottom to top of image
for (var ix=height-slice_height;ix>=0;ix-=slice_height)
{

    // move a section of the source image to the target canvas
    ctx.drawImage(imgA, 0,ix,width,slice_height, 
         0-half_slice_width_increase,width,slice_height);
    // stretch the whole canvas
    ctx.scale(scale_ratio, 1);
}

This will take lots of tweaking, but that is the general solution.

  • scale_ratio will be a number slightly larger, but very close to 1.
  • ctx is the standard canvas 2D context
  • half_slice_width_increase is the 1/2 the amount the canvas will grow when scaled by the scale ratio. This keeps the scaled image centered.

To look correct you would want to transform the background tiles first before you add the icon overlays.

Great Turtle
  • 3,315
  • 7
  • 32
  • 36
  • As I've said in the comments, I need it to be able to handle images that aren't perfectly centered. It's easy enough for me to figure out what you have posted, it's compensating for images that aren't centered that I'm having trouble with. – Stephen Belanger Oct 05 '10 at 17:01
  • I wasn't clear I guess, but the initial image would be generated on a canvas object in flat 2D. That's the source. Then you take slices of the finished 2D image and tilt it by adding a line to the bottom, doing very slight increase and repeating as you go up. Afterwards add sprites on the tilted map. I'll try to make a working demo if I have time this weekend. – Great Turtle Oct 07 '10 at 12:39