views:

160

answers:

3

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.

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.

A: 

Canvas only supports affine transforms. Tilting the view using only a canvas element would require warping the pixels, probably through transformation matrices, which would be quite far from "simple".

However, you might be able to combine 2D canvas rendering with CSS 3D transforms to achieve what you want in an easier way. Browser support for this feature is still lacking, though.

Frédéric Hamidi
I know it requires pixel manipulation, but it shouldn't require something as complex as 3D tranforms. I only need to make the top pixel row narrower than the bottom and adjust the angle of the left and right sides to compensate for textures that aren't perfectly centered.
Stephen Belanger
+1  A: 

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
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
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
+1  A: 

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