View Full Version : orthographic isometric with 2D billboard sprites drawn on tiles.

09-21-2013, 05:46 AM
Hi all! So we're converting out isometric engine to use proper orthographic projection, as well as turning walls and floors into actual poly's instead of iso tiles. The problem I have is now I'm using an isometric viewport in the projection / view, and since we still do have 2D sprites that we wish to place in the scene as billboard 1 to 1 unscaled images, I'm finding it impossible to figure out how to translate this or even if it's possible to do at all.

Here is the ortho / lookat:


float scale = 80.0f;
glOrtho(-w/scale, w/scale, h/scale, -h/scale, 0.000001f, 1000);
gluLookAt(30.0f, 30.0f, 25.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f);

This works great, and allows us to easily plop down walls and floors in iso perspective. It also matches the angle and proportions of the old fake iso tiles perfectly.

However, since we have a whole ton of sprites for stuff like refrigerators and tables etc that are not polys but drawn in matching fake iso perspective and thus need to be drawn as camera facing at 1 to 1, and also since we'll still be drawing characters in 2D, I can't for the life of me figure out how to draw the sprites at a guaranteed 1 to 1, without of course resetting all the matrices to screen space (which would defeat the point, since a big factor in doing this was to completely get rid of all the manual java iso -> screen conversions and use the zbuffer to allow us to batch and texture sort everything, instead of the strict painfully slow and inefficient iso draw order we've had to abide by in the past )

Take this for example:


(a 52 x 80 refrigerator texture drawn by the artist in isometric perspective)

In the olden days I would just (-width / 2) and -height it to centre bottom align it it in the world (well, more specifically, to align it to the centre of the iso diamond that can be assumed to be at the bottom of the sprite), and of course drawing it 1 to 1 was trivial, but this is no longer possible since I'm on a completely different coordinate system. All I want to do is be able to generate a rectangle within the coordinate system, bottom centre at the exact x, y, z coordinates I pass, to draw this at perfect 1 to 1 in the correct place on a tile given an x, y, z coordinate of that tile, without having to completely switch to flat 2D perspective and therefore have to calculate its position in the world manually in relation to the camera etc.

So I tried to manually make some kinda billboard poly that extends across the diag of an iso tile, scaled to match the texture's size if it was drawn directly with a standard pixel aligned 2d orthographic viewport, but I have absolutely no context to work out the width and height of it exactly. I've sat here for about 3 hours messing with it and my head is going to explode, so if anyone can point me at the answer I would much appreciate it. Perhaps it's obvious but I'm seeing red so not sure I can see the wood for the trees. (I suck at 3D math :( )

float someWidth = XXXX;
float someHeight = XXXX;
float half = someWidth / 2.0f;
render(tex, x-half, y+half, z, x-half, y+half, z-someHeight, x+half, y-half, z-someHeight, x+half, y-half, z);

The fact that these sprites could be different sizes on the texture pages means I can't even magic number it and just make an end of it, I've thought I'd cracked it about 10 times so far but then I switch to another sprite and it goes haywire, and whatever I do they are never 1 to 1 which at this resolution of sprite is ugly beyond words. At this point I'm half prepared to live with blurry sprites if they would at the very least be proportionally correct and equivalent sizes to each other.

Any help would be greatly appreciated!



09-21-2013, 07:08 PM
float scale = 80.0f;
glOrtho(-w/scale, w/scale, h/scale, -h/scale, 0.000001f, 1000);

Those near/far values look like they were chosen for a perspective projection. With an orthographic projection, it's valid for the near value to be zero or even negative. Also, the conversion between Z and depth is linear, not reciprocal like with a perspective projecttion.

w/h are the actual viewport size, right? I.e. the glViewport() call is glViewport(0,0,w,h) with those w/h?

gluLookAt(30.0f, 30.0f, 25.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f);

With those numbers, the model-view matrix is:

[ 0.6092077 -0.6092077 0. 0. ]
[ 0.30927835 0.30927835 -0.74226804 0. ]
[ 0.6092077 0.6092077 0.50767308 -49.24428901]
[ 0. 0. 0. 1. ]

The composition of the projection matrix and viewport transformation is

[ 40. 0. 0. 320. ]
[ 0. -40. 0. 240. ]
[ 0. 0. -0.002 -1. ]
[ 0. 0. 0. 1. ]

(this is based on w=640, h=480 as placeholders, which show in the right hand column as the position of the viewport's centre in pixel coordinates; they don't affect the scale, as the values in the viewport and projection transformations cancel out).

The overall composition of viewport, projection and model-view transformations is:

[ 24.36830796 -24.36830796 0. 320. ]
[-12.37113402 -12.37113402 29.69072165 240. ]
[ -0.00121842 -0.00121842 -0.00101535 -0.90151142]
[ 0. 0. 0. 1. ]

Thus, the tile grid's X axis is (24.36830796, -12.37113402), its Y axis is (-24.36830796, -12.37113402), and its Z axis is (0.0, 29.69072165). The horizontal (wide) diagonal is (-48.73661593, 0) and the vertical diagonal is (0, -24.74226804). The aspect ratio (h/w) is 0.507673.

You might want to consider tweaking the model-view matrix so that those values come out to be integers (with 0.5 for the aspect ratio). E.g. replacing 0.30927835 with 0.3 and 0.6092077 with 0.6 would produce tiles which are 48x24.