Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mode7-like perspective transform in canvas?

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.

like image 222
Stephen Belanger Avatar asked Oct 01 '10 01:10

Stephen Belanger


2 Answers

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.

like image 74
oezi Avatar answered Oct 14 '22 09:10

oezi


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.

like image 38
Great Turtle Avatar answered Oct 14 '22 08:10

Great Turtle