I just finished my Isometric drawing class that can draw 2D cubic tilemaps (its not a single plane with objects on top, its a lot of cubes piled, planes divided on what I call floors (no, Im not cloning minecraft)).

I can draw in diamond shape and in the staggered shape, as described in most algorithms out there..Whats holding me up now is something I didnt find in any isometric article/topic out there, how do I draw characters/objects on it in a optimal way?

What Im doing now, as one can imagine, is traversing my grid/map ( its a 3d array) and drawing the tiles in a order so alpha blending works correctly.

Well, things are a lot easier when you just have a plane with objects on top of it, but since my grid is 3D, I cant see any other way than having to draw all my objects at the same time Im drawing the map, with screws the cuteness of the code..

I cant imagine a good way to do this, things that I can imagine is:

#1# give a list of objects(sprites and its positions) to the iso drawer, each loop iteration on the map drawing algo checks the position of all objects against the current tile on the grid....This is the most inefficient thing I ever imagined (for each tile on the map, check all the objects..)

#2# each time a object moves, insert it ON THE GRID, this is so ugly..screws everything, the isodrawer now will change a lot since now its not more a map drawer, its the entire game drawer (except the HUD)(well, this is true for #1# too)...Second problem with this approach is that objects can move freely, not per tile movement, so an object can occupy 2 tiles (be between 2 tiles), dont know how Id handle it.

#3# Forget the " iso drawer "map drawing algo" ", transform it onto a " "depth list" composer ", the list consist on [2D position, uv, Z(depth)] of all tiles on the map, then insert ..somehow..the objects on that list, then draw the list...I cant say for sure if this is feasible, youd have all tiles Z values, than you can compute all objects Z values, now totally independent, (the trick here would compute the Z of the objects considering its position on the map (i.e. object at floor 2, row 4, col 1 : Z = ? ) and the tiles Z too(giving top floors tiles higher Zs, etc.).......

Im using XNA spritebatch for doing this, I think (not sure, I just started using xna) that it can draw sorted by Z order for you, so I wouldnt need to sort the list.

Any links, tips or ideas are welcomed ;D

"why dont you do it 3D?" 3D is good for ultra realistic graphics, for simpler stuff it looks terrible, because 2D art is owsome and cant be compared with 3D, they are two different fields, not the evolution of the other, because I prefer it, because Im fan of isometric 2D for long, because programming iso stuff is tricky and is forcing my mind a lot.....IMO

I fear you misunderstand exactly what "3D" is. 3D doesn't have to look terrible, good, ultra-realistic, or anything else. 3D is merely a set of mathematical transformations. An abstraction, if you will. You can accomplish in 3D exactly the visual appearance you have already established with your 2D, by using an orthographic transformation and your 2D graphics view-projected onto properly-shaped primitives. But it will have the added bonus of a Z-buffer which will greatly aid your efforts of populating the map with dynamic objects. It will certainly be at least an order of magnitude easier than hacking together some kind of god-awful convoluted draw algorithm, as you seem to be working on. On a platform with the proper hardware support, I can think of absolutely zero valid reasons to be doing something like this the "old school" way. This is coming from someone who has written many isometric games and prototypes, who loves the isometric look and feel more than any other game.

It's all about utilizing the tools that modern technology provides to overcome some of the hurdles that people have been struggling with for years. Feel free to search the extensive back-history of the old Isometric Games forum here at gamedev.net. You will find countless posts on this very issue. What you won't find is a solution that is simple and elegant.... unless you go 3D.

Well, by 3D I really meant 3D cubes, but if you talking about "billboards", 3d quads with a texture, than we are talking about the same thing..I dont see how it changes anything..??
I plan to migrate all that stuff to my sprite engine that Im working on on dx11, with is exactly a ortho projection and quads, see?..With I believe must be the same thing xna sprites are...

I'm not talking about billboards, except maybe for the mobs. The world geometry should be cubes (or, rather, your shortened cubes). That way, the depth buffer will have the depth that it needs to clip your mobs after the world is drawn. Just take your 2D landscape sprites and project them onto shortened cubes, ramps, etc... Since the view never changes, your cube primitives only need to consist of the three visible faces.

Translating pixel art to textures so you can map to ortho projected cubes is that easy? and will look the same?
The steps to do it, as Im guessing:
Use nearest/point filtering when strecthing the original 2d image (on photoshop i.e.) to produce the texture map, and then sample it with point sampling onto a ortho projected cube..
I just cant believe it will look exactly like the original pixel art o_o is that what you saying?

Because if you just saying it will look good and 2D, its still not enough reason to consider it, the great deal with 2d iso games, is the 2d iso art..

Even if it do will look just like..

One problem already is to make that translation, you have to do it manually for all tiles, or you build a tool to do it for you, with will have to account for all possible shapes you have in your tilseset.

Forgetting the tiles and do the textures straight ahead is also a complete different matter, I mean, how would you draw a grass texture for a cube, so it can look a nice 2D grass after projected, and not just a texture on a 3D cube? Youd have to draw the texture accounting for how much it will be stretched on Y, not feasible either..Youd need a different artist, not a good 2D pixel artist.

Then that tool to make the conversion automatically seems the better solution, but building it seems as tricky as all the isometric old school stuff..

I dont think theres a direct translation from 2D to 3D as you make it look, unless Im dont get what you mean yet, I remain with I said in the first post: 2D and 3D are two completely different art fields..

The question isn't about different art. Like I said, you can continue to use the same exact art you have. You were on the right track when you suggested to use nearest filtering and project it onto an ortho cube. That is exactly right. And yes, you can set up your mathematical abstraction so that the 3D version will look identical to the 2D. Here is a tile I made just now:

I made a couple versions of it (lighter and darker). Then I took that tile and (1) hand-arranged several copies as if I were a 2D renderer, stacking blocks back to front and positioning the sprites just so to line up. Then (2) took the tile, mapped it onto a cube in Blender, set up an orthographic projection and a material with no texture filtering, then built a stack of blocks identical to the first. Can you tell me which one is the 2D version and which one is the 3D version?

I sure can't tell, and neither can the Gimp. Doing a subtraction operation between the two as layers results in a perfectly black bitmap. The two versions are pixel-perfect identical. However, the advantage of the 3D rendering (which is on the right, in case you were wondering) is this little goodie right here:

See that little beastie? That's the depth map of the 3D version. If this were in-game, that depth buffer would be used to clip incoming fragments. You can very easily draw your entire map, then go back and draw all your mobs, and the z-buffering will ensure that pixels clip correctly. It's so easy, I honest to God wonder why in this day and age anyone would ever bother with trying to rehash all the old techniques.

If you don't want to use the hardware for whatever reason, that's fine. You can implement your own z-buffer, build a simple 3D abstraction for your map layer, and do the depth testing yourself. It's relatively simple (though it is easier to just let the hardware handle it for you; that's what it's designed for). But revisiting 20+ years of old 2D techniques, hoping that things will turn out better this time, really isn't a solution. Nor is it even an interesting problem anymore. It's a very much solved problem, and all those sprite sorting and stacking tricks just get in the way of progress toward completing your game.

I don't mean to sound like some kind of crusty old know-it-all, but I have been doing isometric games now for almost 20 years. I've run the gamut of sprite sorting techniques, block tagging, you name it. Nothing beats the elegance of using the hardware correctly, in my opinion. To reinforce it, here are two images I've had kicking around for almost a decade now. They are from an old game I was working on, Golem. The first image was taken before I did a rewrite of the backend code to 3D. It was still using the original 2D code. The second image was from after the rewrite. You can see that visually, there is little difference. The game still looks the same. The differences were in the elimination of all the weird little edge cases that made the original 2D engine such a pain in the ass to work with. The code was made vastly simpler as well.

I was able to reuse all assets, I didn't have to make any artistic changes whatsoever. The game still looked 2D. The only difference was that the character could now walk through certain doorways or cross tile boundaries in certain ways, and not have to worry about being overdrawn in odd fashion by some other piece of the landscape.

Thats freaking nice..Im not trying to forcing myself onto old school stuff either, its just that accepting you can do the same on 3D never seemed possible to me.

When mapping the tiles to the cubes on blender, you didnt even need to stretch the tile/texture? you can just map directly?

One thing that holded me up on that is the tile spacing, when dealing with pixel art, you account the amount of pixels from one tile to another, and how much pixels you overlap(or not), with also means you can have different shaped iso tiles (mine have 2 horizontal px on the top and bottom corners, 2 px horizontal on the left right ones, on the top and bottom you must overlap by one pixel, on the left and right you overlap by too, I already saw many tilesets with different proportions but same perspective(like no overlapping at all, 3 px at top and bottom, etc.)) I never imagined this fitting on 3D stuff without losing the 2D appeal.

Can I assume irregular tiles like fancy curved slopes, like on this famous tileset:Will also work fine? o_o look all the irregular, not straight cube stuff on these tiles.

Yeah, you can map all of those to cubes. It really is just like mapping them to billboards, only you use cubes instead so they have depth. Mapping it to cubes will give it the shape of a cube, though, so in the case of some of those ramps and such you can deform the cube somewhat, maybe even subdivide it one or two times, to give it a shape that more closely approximates the sprite it is meant to represent. The key word is approximate; you don't need to get crazy.

As far as mapping the sprite onto the geometry, there is no stretching or tiling. Here is how I do it in Goblinson Crusoe and all my other ventures.

1) Start with a cube in Blender.

2) Since only three faces (top, front-left, front-right) are visible, I delete the non-visible faces.

3) Set up an orthographic camera that is rotated 30 degrees on the X axis, 45 degrees on Z. This gives a viewpoint that mathematically implements the 2:1 tile ratio size of most "standard" isometric games. Hit Numpad-0 to go to camera view so I'm looking at the cube from the perspective it will be viewed in game.

4) Tab into Edit mode on the cube, press 'u' for UV unwrap, and select Project to View (bounds). What this does is assigns UV coordinates based on the current camera view. In effect, it flattens the cube as it is being viewed into a UV map. The result is something like this:

4) Export the cube geometry (or write down the verts and UVs and just enter them manually into a geometry array in your program, if you don't want to much with model loading.

5) Draw the cube with the tile set as the texture, with Nearest filtering.

You can see that the UVs are projected exactly as the cube is viewed. The only slightly tricky part here is using trigonometry to calculate how much to scale the unit-sized cube vertically to fit the desired tile size. This is something you can either calculate mathematically or by trial and error. You want to scale it so that the UVs line up with your tile exactly as so. Then you want to scale the cube itself, which will be drawn by your engine, so that it will fit the tile size in the orthographic projection.

You do have to think about the 3D math that underlies the abstraction, but as you gain a deeper understanding of 3D it becomes no problem. By setting up your projection carefully, you can draw the cube geometry such that it will cover exactly the same screen space as the 2D version, pixel for pixel.

There is one small caveat: you do want to avoid using too much floating point in your abstraction. I typically set my orthographic projection up on a 1:1 basis; that is, 1 pixel in screen space equals one unit in 3D space, and always clamp translations to integers. The reason for this is that floating point math can get a little bit "leaky", and you might sometimes get rasterization artifacts when you are trying to get pixel-perfect rendering of your sprite. You can also pad your sprites, duplicating pixels all the way around the shape, so that if the occasional off by one funky raster does take place, it won't be noticeable. However, if you are careful with your math, that shouldn't really be a problem.

Im having artifacts on XNA already when zooming (scaling) the camera/view matrix, not a 3D exclusive issue ;DMy WIP sprite engine on Dx11 is pixel perfect already, but I have a scale unscale thing going on so I can work with physics with a px not being a metter, so basically I have a to_Metter on sprite sizes, and a to_PX on my projection matrix (the inverse of the to_Metter).. I probably can just plug cubes instead of quads and it will work, and workout the camera position.

But never done anything in 3D with XNA yet (started messing with XNA last week)

How do you turn off all filtering on blender? I turned mipmaps off on the system tab, but it stills have some filtering going on (left model, right texture):

From programming to modeling questions ;D

"Maybe if I get a few minutes at work, I'll pop together a demo."._. * humiliation *

The key to eliminating filtering, whether it's in Blender or in a game, is to ensure that there is exactly 1:1 correspondence between the pixels being drawn and the region of the buffer they are being drawn to. Any change in scale or stretching will result in filtering of some sort, and you will have to plan accordingly. You can use nearest filtering, but there will still be filtering. This is actually the biggest hurdle when trying to do a pixel-perfect translation from 2D to 3D. Although, of course, you also have to worry about filtering if you do traditional 2D with scaling, so there's that.

In Blender, you can reduce filtering by going to the Texture->Image Sampling panel, turning off Mip Maps and interpolation, and cranking down the filter size as low as it will go. But you also have to ensure that your object is scaled relative to the viewpoint correctly, so that there is a 1:1 pixel mapping. Also, I notice that in your posted image, on the right, there is a bit of sloppiness in your tile. To be pixel-perfect, or as near to it as can be achieved, you need to ensure that your tiles are correct. A 2:1 tile ratio has cell lines that are exactly 2 pixels horizontally for every 1 pixel vertically; in your tile, there are a couple spots on the cell boundary that don't follow the pattern precisely, and this can have implications when drawing. That is a minor nitpick, though.

Getting the math right for pixel-perfect is the trickiest part of the process. You also have to ensure the quality of the asset creation process. I have found that, for best results, a 2:1 isometric tile hold approximately to this template:

That is zoomed, of course. You can see that all the edge lines hold to the 2:1 line ratio. In the image, the dark zones indicate areas where padding may be placed, in order to mitigate what filtering may take place. Extra padding around the outside may be necessary if the sprite is to be scaled. The padding between the top and the walls should match the top, and not the walls, since those rows of padding will be visible on tiles of the same level placed adjacent to one another, without tiles on top of them.

The main areas where you need to do some calculating are:

1) The orthographic projection matrix, and how it relates to the drawing size of the tile cubes. My personal method is to visualize each tile, as in the template above, as being some number of units in size. Each 2-pixel wide block in the cell lines denotes a unit, so a tile that is 64 pixels wide would denote a 16x16 unit cell. So if I draw my cubes as 16x16xH (height varies, depending), and use integer math for coordinates and locations, then I can ensure that tiles will be drawn on whole-pixel locations, and filtering is reduced. This requires special consideration in calculating the projection matrix.

My method, then, of calculating the orthographic matrix is to divide the screen horizontal resolution by the width, in pixels, of a tile. (64, in the case of the above magnified template). Then I multiply this value by the world size of a tile (16, in my system) and multiply that result by 1.41421356237 (The square root of 2). The reason for this is that, given a camera rotated 45 degrees around the vertical axis, you are viewing a tile not edge-wise, but diagonally. The distance between the corners of a square whose sides are 1x1 is, of course, the square root of 2.

With that calculated value, I multiply by the aspect ratio to get the orthographic height of the viewport, then use those values to set the ortho matrix. To illustrate, here is a bit of code to do just that in OpenGL:

That is working code from the demo that sets the projection matrix. The member tile_pixel_width_ of that class is set during initialization, to the width (in pixels) of a tile. 64, with the above template. The member tile_world_size_ is set by dividing the tile pixel width by 4, for a 16x16xH unit tile in the case of the above template.

2) Tile height. If you set up a 30 degree camera (the angle needed for a 2:1 projection) and view a cube, you will notice that the cube vertical faces are fore-shortened, due to the angle of the viewpoint. There needs to be careful consideration for the correspondence between the tile sprite and the cube primitive that is drawn. The height of the cube primitive needs to be scaled correctly to correspond with that foreshortening. This can take a little bit of trigonometry, but once you wrap your head around it it's not too complicated. In the case of my template tile above, the tile is a total of 64x48 pixels. (The rest is padding to bring it to 64x64.) That means 32 of the pixels are taken by the top of the tile, leaving 16 for the vertical faces. A bit of trig gives me the totally arbitrarily funky value of ~0.40824829f as the height to scale the unit-sized cube to in order to match the tile template.

With that in place, the rest is pretty simple. I put together a small demo in C++, using the latest RC of SFML 2.0. (I don't use XNA or C#.) But the code should be relatively explanatory. It's a quick, one-off demo meant to show the concepts, rather than a comprehensive prototype, but it works.

Here are the tiles used for the demo. (They should be in the root directory of the executable.)

dirttile.png

grasstile.png

leftramptile.png

rightramptile.png

The demo sets up a tiny sample map, then enters a loop in which the camera scrolls around endlessly in a circle. Nothing fancy. The tile geometry units are hard-coded, but in a real game I'd use loadable geometry in case I needed a weird tile of some sort. Here is a shot of the demo in action:

If you zoom in, you can see that the pixels are pretty close to pixel-perfect (or, at least they were on the source image; I really can't vouch for imgur's service after they're uploaded). Filtering artifacts might occur (very occasionally) but if you pad your sprites correctly, even on the rare times they happen, they are not that noticeable.

I didn't have time at work to hack in mob sprites, but depth testing IS working correctly, and the sprites would be correctly clipped. (You can tell depth buffering is working, as the tiles are drawn from front (top, nearest corner) to back (bottom, far corner), and yet the back tiles are correctly clipped by the front tiles.

Thank you very much JTippetts, this example is awesome.I want to make a similar isometric engine, but I am not on the same level as you guys. Can you clarify stuff a bit for me?

Tile and funky valueLooking at the tiles you used, it looks like the tile primitive is 0.5 of the width. And the funky value is 0.5 in perspective of 30° angle. Am I on the right path here? I tried to reproduce your calculation, but I haven't managed to do so yet, can you describe the formula?

World UnitAs I understood, your world is rasterized in world units, one tile consists of 16*16 units. You wrote that an actor traversing the tile needs 16 steps. So a mob in your engine would keep track of the mobs unit he is currently in, right?

ZoomingIf you would implement zooming, it looks like you would need to reinit OpenGL to a different resolution.This seems a bit cumbersome, is there an other solution?

1) The "funky value" for the foreshortening of the unit cube was calculated as (0.5/cos(30)) / (sqrt(2)). I don't really have time to do a diagram, but maybe a description will do. The vertical walls in the tile sprite are 0.5 times as tall on-screen as the top of the tile. The sprite is being viewed at an angle of 30 degrees. Doing a little trig, you can see that if the tile top is considered 1 unit in size on-screen (it's not, but for the purposes of the math it is) then the foreshortening factor to use to make a unit-size cube half that size in screen space would be 0.5 / cos(30). Now, since the tile top is actually being viewed diagonally, it's size is actually sqrt(2), so we need to divide (0.5 / cos(30)) / sqrt(2) to get the final foreshortening factor. Scale a tile-sized cube by this factor vertically, and it should match the sprite tile pattern.

(This kind of weird math is the most difficult part of tranforming 2D to 3D isometric. You just need to get a sheet of paper and draw some diagrams of exactly what is happening, as far as the interaction of a camera at 30 degrees / 45 degrees is concerned. Once you wrap your head around it, the rest is easy peasy.)

2) Not necessarily. I just have my mobs keep track of their world coordinate. There are 16 world units per tile. So a tile world 10x10 tiles in size in X and Z would be 160x160 units in size. To find the tile any given mob is in, you just divide his world coordinate by 16. Now, I usually do use a spatial grid structure to track mobs, but that is typically for visibility determination.

3) No, all you have to do is scale the ortho_width and ortho_height values when constructing your projection matrix by 1/zoomfactor. So if you want a zoom of 2, just scale by 0.5. To make it easy, you could just alter the applyCamera function:

You still will need to sort the alpha blended sprites right? I mean, sprites behind a tile will need to be clipped(partially) by the front tile, but the blending need to occur to the tiles behind the sprites..Isnt true?Doesnt that mean that the entire map will need to be sorted anyway? At least if you want a "pilled cubes" kind of isometric game.

One problem Im trying to figure out (in 2D) is when the height of a object is greater then an entire floor, I mean, if you draw the first floor (the one with a 2 floor height object on it) and than you draw the second floor, the second floor objects will clip the tall object even if behind it. I though I have solved it by drawing all the floors of each tile ( instead of traversing floor/row/col, Im traversing row/col/floor, check the image on the op, theres 2 floor tall objects), this really solved for the map itself (static) but for moving objects it does not work, since the object will be clipped by tiles on front rows(on the same floor), its "feet" will be cliped by the "losang" right bellow it, on the front row, before it jumps to the next row (you know, when its transiting between tiles). One may think a solution is to not have objects taller than a floor, but them..your character can not jump? inadmissible!

Neither I can understand what I described, heres a pic:The tall cube is being cliped by the tile on the floor above, cause the top floors are drawed later.Here I solve the first problem, by drawing all floors of a tile first..the object is on the second floor, but its clipped by the one on the floor bellow, cause the front rows are drawed later now..

Resuming, the problem is solving transitions, if you solve transitions on width, you ruin on height, if you solve on height (y), you ruin on width.

I cant visualize if this problem will be solved on 3D, you still need alpha blending and sorting right?

How engines solve problem like this (kinda off topic):Lets say the sprite is a smoke particle, how you do the blending of the smoke with the heightfield behind it, without having the smoke showing on front of the height field part on front of it?

You only need to sort if you actually do alpha blending, with partial transparency. If you just do alpha testing, where a pixel is either fully opaque or fully transparent, you do not need to sort. Typically, I do not see pixel art Iso games use partial transparency. The above demo uses full transparency and draws front to back to take advantage of early depth rejection to reduce overdrawn.

For sprites like smoke that must use partial transparency you can sort those sprites alone and draw them in a pass after the world is drawn. Depth testing will reject any pixels that do not pass the depth test.