Posted: 22nd September 2018

Author: Ric

Tagged: Tutorials

Creating an isometric rig in Blender

(Updated November 2021 for Blender version 2.8 and later)

The most time consuming aspect of creating isometric games is the artwork because almost every single sprite needs to be drawn at 4 different angles, or 8 if the sprite is of a character. Additionally, if the sprite needs animating, such as a character walk, that animation might comprise of say, 10 frames at each of those angles. For a basic character that needs to walk in all directions, that's 80 frames to draw before we even consider running, standing, jumping, and so on. To do all of this by hand as raster art would be a nightmare.

Our solution is to create all of our sprites as 3D models in Blender, a free 3D modelling software for Windows, Mac and Linux, and then render these models out to 2D sprites by rotating the model in front of an orthographic camera.

Blender can render animations out to individual frames so for something like a walking animation it's just a case of animating within Blender, then rendering, rotating, rendering, rotating, rendering, and so on. The resulting sprites can be merged together into single spritesheets later on to use as in-game animations.

For sprites that don't need animating, such as walls, we create the rotation itself as an 8 frame animation so that a render of every angle can be obtained with a single click. This approach makes it really quick to produce isometric game art, ensures the artwork looks exactly right at each angle because you're not actually painstakingly drawing 8 alternate views of the same item, and means that for every 2D graphic in your isometric game, you've got a 3D model ready to use if you ever want to turn that game into a 3D sequel.

If this sounds like the perfect solution to you, here's how to set up an isometric rig in Blender. Alternatively, skip to the end of this post and download a copy of our pre-built rig. The scope of this tutorial isn't to teach Blender, trigonometry, pythagoras, or orthagraphics but the calculations used are shown here for reference in case you need to create a slightly different rig and produce renders of a different size to ours.

 

Creating the base

  1. First, open Blender and click anywhere in the scene to close the overlaying splash screen. Blender should have created a camera, a light, and a cube already.

  2. From the column of icons on the right, select "Render Properties" which looks like a TV screen and switch the render engine to "Cycles". The default Eevee engine doesn't support everything we need for this, and Cycles gives better render results anyway.

  3. Select the cube and hit delete but leave the camera and light - we'll be using those.

  4. From the options in the top left, click "Add" -> "Mesh" -> "Plane" to add a flat plane to the scene. This will become an invisible base that we attach everything else to for rotation, so from the "Object Properties" icon which looks like a square in that column of icons on the right, rename the plane to "Base".

  5. Scroll down a little and unfold the "Visibility" tab. We don't want the base to be visible in renders but we do want shadows cast towards it to be rendered, so tick "Shadow Catcher" in the masks list.

  6. If you hit "Render Image" now from the Render menu at the top, you'll notice the base isn't rendered as it's now only rendering shadows and there aren't yet any being cast towards it. While we're here, By default Cycles renders an opaque background which you'll likely want to replace with transparency too. Select "Render Properties" from the column of icons, then "Film", and tick "Transparent". A render now shouold just show a chequered background indicative of transparency.

  7. A note on anti-aliasing. If you're rendering isometric tiles that need to slot together in a game world, or you just really like pixel art, you'll want to keep the hard pixel edges. To do this, first change the "Pixel Filter" option of the "Film" tab to "Box" which is Blenders' most basic rendering algorithm and doesn't merge surrounding pixel colours in for smoother edges. Next, from the "Sampling" tab change the number of passes in the "Render" field to 1. This tells Blender to only sample each pixel once, preventing the algorithm from being able to determine things like the transparency of a pixel. Both of these settings combined effectively disable anti-aliaising but if you attempt to render a complex graphic with only 1 pass, you might find visual defects because the ray-tracing algorithms are erroneously deciding that there's nothing to render at a particular pixel. Our recommendation is to use these settings for only the diamond part of a tile, and separately render the rest of the tile with 128 passes so that the two renders can be merged into a single graphic later on. If you download the provided rig file at the end of this blog post, note that this is currently set to 128 passes for the better renders.

Setting up an isometric camera

  1. Select the camera and then the "Object Data Properties" icon which looks like a camcorder. For isometric graphics we want to switch to an orthographic lens, so select "Orthographic" as the camera type.

  2. Hit "0" from the number pad to view the scene from the cameras perspective. For proper isometric renders we need to adjust the cameras viewport so that the plane touches the left, right, and bottom edges the frame, and so that it looks like a perfect diamond where the height is exactly half the width.

  3. For the perfect diamond, click the "Object Properties" icon and set the rotation to 60 degrees along the x, 0 degrees along the y, and 45 degrees along the z. Ignore the position for now, we'll come back to that shortly.

  4. Next we need to decide on a canvas size to render out to. For our own graphics we decided 256px wide would be adequate, and 512px tall would be a reasonable amount of vertical space to draw tall sprites within. Click the "Output Properties" icon which looks like a printer, and enter a resolution of 256 x, 512 y. Or adjust for your own needs.

  5. Back to the "Object Properties" to get the edges of the diamond in the right place, the first step is to force the camera to point exactly at the middle of the scene. For the horizontal, set the camera location to 10 x, -10 y. This combined with the 45 degree z angle puts the middle of the scene perfectly in the middle of the camera frame.

  6. For the vertical position we need a bit of trigonometry and pythagoras. The camera is positioned 10 x -10 which gives us two sides of a right angled triangle, so we can calculate the hypotenuse to give us the distance it is away from the centre. √((10 * 10) + (-10 * -10)) = √200 = 14.1421356237. Next we can use this and the known 60 degree camera rotation to imagine a new right angled triangle and calculate its opposite side, i.e. the height the camera needs to be at to point down the hypotenuse towards the scene centre. (14.1421356237 / sin(60)) * sin(30) = 8.16496580926. Use this for the camera z location.

  7. The diamond should now be exactly centered in the camera view, but we need to adjust the camera zoom to put the corners exactly on the left and right sides of the frame. Back over to the "Object Data Properties" to adjust the "Orthographic scale". The width of the diamond is √((1 * 1) + (1 * 1)) = √2 = 1.41421356237 and its height is always half that, so to render a 256x512px sprite the orthographic scale needs to be 1.41421356237 * ((512 / 256) * 2) = 5.65685424948. Enter this as the "Orthographic scale", or adjust for your render resolution. At this point if you disabled the "Shadow Catcher" visibility mask of the diamond again, and produced a render, you might notice a 1 pixel gap before the edge of the frame. This is normal behaviour just because the plane is only one face. If you create a cube and position it in the centre of the screen the render should be perfectly edge to edge.

  8. Finally we need the base of the diamond to touch the bottom frame of the camera view. For this, still on the "Object Data Properties" icon, (re-select the camera from the collection list in the top right if need be, or hit "0" again to exit the cameras viewport so that you can see it again for selection), adjust the "y shift". (1.41421356237 / ((512 / 256) * 2)) + (5.65685424948 / 256) = 0.3756504775. Enter this, or adjust for your own resolution, and we're there - an invisible isometric diamond aligned perfectly within the canvas, that can be used to position models over for rendering out to 256x512px sprites, or whatever size you adjusted to.

Rotations

We need to set up a rotation animation so that all 8 isometric views of a sprite can be rendered out in one click.

  1. At the bottom of the screen there's an animation timeline. On the right of this, change the "End" frame to 8 and then from the menu to the left, hit "View" -> "Frame All" to reset the timeline view. Then with frame 1 highlighted and the Base plane selected, switch to the "Object Properties" again, hover over the z rotation property and hit the letter "i" on your keyboard. The rotation properties should turn yellow and a yellow diamond will appear on frame 1 of the timeline at the bottom, indicative that this is the rotation the object will be rendered at on this animation frame. Switch to frame 2 by clicking its number in the timeline, change the z rotation to 45 and hit "i" again. Repeat for the remaining frames, increasing the rotation by 45 each time until all 8 frames are set.

  2. Back to the "Output Properties" icon, scroll down to the "Output" tab and pick a folder to render animations out to. Renders will produce a separate file for each frame and by default will overwrite any renders already at that location, so it's best to pick somewhere that's specifically only used for Blender rendering.

  3. Now to render a model out at all 8 angles just means setting the models parent object to be our Base plane and hitting "Render" -> "Render Animation". 8 images will be created within the chosen output folder, each as a 45 degree rotation of your model at an isometric projection. Or to render a single frame, just select that frame from the timeline and hit "Render" -> "Render Image".

Lighting

To finish off, we want to make sure all of the resulting sprites are rendered with the same lighting so it's a good idea to set that up now within the rig. Your optimal settings are somewhat dependant on what you're making, but as a general rule of thumb with isometrics we find it's a good idea to aim for very bright with a really small shadow that doesn't extend beyond a single tile. Most importantly, lighting needs to be an even spread so that tiles can fit together without weird gradient effects. A downward pointing light for a perfectly centered shadow below the sprite tends to work best, even if the sprite is ambiently lit from an angle. Suspension of disbelief kicks in when playing games and shadows not following the logical rays of a sun light in isometric renders just doesn't matter.

  1. Before trying to set the lights, you'll want a model to render so that we can actually see the results. Click "Add" -> "Mesh" -> "Monkey" to add a reasonably complex mesh to the scene, then from "Object Properties" change its position to 0 x, 0 y, 0.6 z, and its scale to 0.6 x, 0.6 y, 0.6 z. Select frame 1 from the timeline again and while still within the "Object Properties" panel, scroll down to the "Relations" tab and set the parent to be the Base plane. The mesh now fits within the isometric tile and will rotate with the animation frames.

  2. Select the existing light and from the "Object Data Properties" icon change it to a Sun type and untick the "Cast Shadow" option. This will be for our ambient brightness. You might also want to rename to "Sun" so that we can differentiate easily from other lights.

  3. The position of Sun lights doesn't matter to the render process as only the rotation data is used, but it's easier to imagine the lighting that they cast if they're positioned near to the scene objects, so from the "Object Properties" icon change the position to 4 x, -4 y, 4 z, and set the rotation to 0 x, 45 y, -40 z. Note that we're not pointing the light at a perfect 45 degrees towards the object because then both faces of a cube would be lit the same shade.

  4. At this point you may want to play with the strength from the "Object Data Properties" icon. Just 1 is probably enough but play around and just pull a render with every adjustment to see the result. Remember that this is a complex shape so you may also want to return to "Render Properties" and increase the sampling passes in the "Render" field for better results. 128 is good for complex shapes, while 1 is necessary for tileable diamonds.

  5. Some sprites, such as characters, need a ground shadow that doesn't extend beyond the size of the tile. Unfortunately Cycles makes this a little complicated because unlike other render engines, lights cannot be set to cast shadows only. Cycles aims for real-world physics simulation and in the real world, a shadow is the absence of light so although we don't want to render any more light than that of our Sun, we are still going to need to emit some to create our ground shadow so for this we'll use some layers trickery. In Blender your scene can comprise multiple layers and objects can be grouped into collections which can then be switched on or off per-layer. Rendering will iterate each of your layers to produce a series of images which we can then later combine so the idea here is to create two layers, one for the model which is only lit by the sun, and one for the shadow which doesn't affect the model. Then we'll merge the two renders into a single image.

  6. Click "Add" -> "Light" -> "Spot", position it at 0 x, 0 y, 20 z from the "Object Properties", and then from the "Data Object Properties" icon set the power to 1000, the radius to 0.1, and the "Spot Size" to 3. You may want to play with these figures later on to adjust the shadow intensity for your own needs. At this point you may want to also rename the light to "Shadow caster" to differentiate it from our Sun.

  7. Next, if you look in the scene collection at the top right, you'll notice all of our objects are currently within a single collection. Collections are groups of objects and each collection in your scene can be made visible, or invisible, to particular layers so currently we just have the one layer and all of our objects are within the one collection which is visible to that layer. We need to shuffle things around a bit now, to move our shadow caster light onto its own layer and then hide it from the main object layer.

  8. First, in the very top right you'll see a field witht the current value of "View Layer". This is the default name of the default layer we've been using. Rename this to "Model layer" and then click the "Add View Layer" icon to the right, choose "New", and rename this to "Shadow layer".

  9. From the scene collection directly below this field, the second icon on the left should be "Display mode". Make sure this is set to "View Layer". This just defines how the scene objects are presented in the list below but this view makes the next step a little easier.

  10. Right-click "Scene Collection" and hit "New Collection". Then drag your Shadow caster down into this new collection by holding down on the orange "Spot" item.

  11. Right-click "Scene Collection" again, and hit "New Collection" to add a third collection. This time drag both your Camera and Base down into it. At this point your original collection should contain the sun and your model, Collection 2 should contain your shadow caster, and collection 3 should contain the base and your camera.

  12. With "Shadow layer" still the selected layer, indicated by its name in the top right of the screen, untick the checkbox against Collection 1 because we don't want the ambient light or model to be included in shadow generation. Then select "View Layer Properties" from the icons column and scroll down the the "Light" tab. Tick "Shadow" in this list.

  13. Next select the "Model layer" from the icon to the left of the layer name field at the top right, and this time untick Collection 2 because we don't want the spot light to affect our model. If you pull a render now, the renderer will first work on the Model layer and ignore the shadow light because it's in collection 2 which is invisible to this layer, and then work on the shadow layer and ignore the monkey because it's in collection 1 which is invisible to this layer. Currently you'll only see the result of the first render becase we haven't yet merged the two compositions into a single image so you'll just see your monkey with only ambient lighting.

  14. We still need to give the shadow caster something to work on. At the moment it's casting light towards the base but there's nothing in the way to create a shadow of. For this you have two options, depending on how realistic you want the shadow to be:

    Option 1: For our own needs we just wanted a basic circular shadow beneath all of our sprites and this can be acheived by just creating a small sphere within collection 2, invisible to the camera. To do this, select "Shadow layer" from the top right again to work on collection 2, and then "Add" -> "Mesh" -> "UV Sphere". Drag the new sphere into Collection 2 and from the "Object Properties" icon set the scale to 0.1 x, 0.1 y, 0.1 z and the position to 0 x, 0 y, 15 z. Scroll down to the "Visibility" tab and untick "Camera" under the "Ray Visibility" sub-tab. This prevents the sphere from rendering even if you move it into view because the camera is effectively ignoring it, but it'll still be in the way of the shadow caster light and thus still render a shadow to the Base plane which the camera doesn't ignore. You may also want to rename to "Shadow generator".

    Option 2: If you want your shadow to mimic the shape of your model, you'll need to replicate the model into Collection 2 and set this replica to be invisible to the camera. The downside here is that you'll need to do this each time you use your rendering rig since it's the object that you'll be swapping out each time but the resulting shadow will be a more realistic shape. To do this, select "Shadow layer" from the top right again to work on collection 2, and temporarily re-tick collection 1 so that you can access its objects. Right-click the monkey object, by default named "Suzanne", to "Copy" and then right-click "Collection 2" and "Paste". Remember to now untick "Collection 1" again to disable it within this layer. The copied object should already be at the correct position and scale so just select it and from the "Object Properties" scroll down to the "Visibility" tab and untick "Camera" under the "Ray Visibility" sub-tab. This prevents the replica from rendering but it'll still be in the way of the shadow caster light and thus still render a shadow to the Base plane. You may also want to rename to "Shadow generator". If you download the provided rig file at the end of this blog post, note that it's option 1 above which is used in this file.

  15. Finally we need to tell Cycles how to compose an image from our two layers. If you pull a render now, you'll see the renderer spit out a result for each layer but the shadow only appears momentarily because although it's processed, it isn't currently used in the final image. Select "Compositing" from the main menu at the top, and tick the "Use Nodes" checkbox. The default should show a render preview of our Model layer attached to a composite node. Basically this means that the resulting render is only using "Model layer", as expected, but we want it to compose of both.

  16. Click "Add" -> "Input" -> "Render Layers" to add another render node, clicking anywhere in the view to attach. From the field at the very bottom of this node switch it to "Shadow layer" and the preview should switch to our generated shadow. Then "Add" -> "Color" -> "Alpha Over" and drag connector lines from the "Image" output dots of each of your "Render Layer" nodes to the "Image" input dots of this new node. You can now drag a connector from the "Image" output dot of this to the original Composite nodes "Image" input dot. What we're doing here is combining the results of both layer renders into a single image and telling the renderer to generate this instead of just the one layer render. To see what's happening, "Add" -> "Output" -> "Viewer" to create a preview render and drag another connector from the output "Image" dot of the "Alpha Over" node to the "Viewer" node's input "Image". The background of the Compositing view should now show what the Alpha Over node is generating from those two layer renders, and thus what the Composite node is receiving. If the shadow is rendering in front of the monkey, just swap the inputs over that feed the "Alpha Over" node.

  17. Return to the "Layout" view from the main menu and "Render" -> "Render Image" to see the result. At this point you may want to revisit the lighting steps to adjust intensities to get your shadow or object brightness just right. If you went for option 2 in the shadow generation, experiment with the scale and/or z position of your replica object too. A scale of 0.1 x, 0.1 y, and 0.1 z for example will create a tidier looking shadow that doesn't block out the whole tile and again, suspension of disbelief will kick in when used in a game so losing the realistic cone effect here just doesn't matter.

If you like our set-up but don't want to go through the whole process yourself, download our complete isometric rig for Blender. You should at least read through the above though to understand how this rig works before trying to use it.

Blog posts written by former QWeb employees are not necessarily an accurate indication of the current opinions of QWeb Ltd and the information provided in tutorials might be biased or subjective, or might become out of date.

Discuss this post

James
19/10/2021 22:28

This is an excellent technique, thank you for sharing. I'm a Blender beginner and the current version is very different. I could not do certain steps you described. I could open your pre-made rig but it doesn't appear to cast any shadows, and it also shows the base. At any rate, I was wondering if you could update the article and the pre-made rig to the latest version, seeing how different it is? Thank you!

Ric
20/10/2021 14:23

Hi James,

Blender has indeed changed a lot since I wrote this post. It looks like the problem is that the material of the plane created just to catch shadows now has a mandatory base colour which is being included in the render, and shadows-only doesn't seem to be an option any more. Shadow catching in the Cycles rendering engine was always problematic and I'm wondering if Cycles is now the only engine in newer builds.

I'll try to figure out a solution and update this post asap.

Ric
24/10/2021 10:32

Alright - now that I've had time to look at this properly again, it seems the internal Blender renderer was indeed removed in Blender 2.8 but it's not Cycles that's replaced it - instead, a new Eevee engine seems to be the default and has some limitations. Most notably for this rig, creating spot lights that cast shadows but don't actually emit light doesn't appear to be possible, and creating planes that catch shadows but don't render a surface material also doesn't seem to be possible.

A little Googling suggests that shadow catching is now possible in Cycles though, which wasn't the case when I built this rig, so I'm going to recompile my Blender install with Cycles support, (Gentoo Linux user here), and see if this can be reworked for that.

In the meantime, if you pull a pre 2.8 version of Blender you should be able to follow the above or use the provided rig properly.

James
24/10/2021 18:18

Ric, thank you so much for sparing time looking into this. I've made big headway learning about Blender and the new version in particular. I found Cycles to give me better results than Eevee in general, and in particular when following your tutorial, although pretty much everything is in a different spot now.

As you said, there is no way to set up a light that ONLY casts a shadow. It will always illuminate the object. There are techniques out there using composition and render layers that make this possible, but IMO this is way too heavy and manual because every object has to be duplicated into another scene. Now multiply this by 100 assets and there is no way I can do that.

I ended up using 2 sun lights, one for the top of the object (that casts a shadow onto a shadow catcher plane), one for the front (no shadow), and an ambient light to lift up the shaded areas. Now that was another can of worms, because you can't stop the background object from casting shadows, so it was contaminating the plane with faint shadows up to its edge. So I ended up forming a light box with area lights arranged in a cube and placed it around my scene, then turned off shadow casting from this object.

Mind you I've only started using Blender for the first time of my life this week, so it might not be the best way to do this. I would be curious to hear your own take on this.

Again thank you for this article, and especially for breaking down the mathematical formulas, something no other 3D to iso article has done (there are at least 3 other articles on the web about this).

James
25/10/2021 06:15

Well, I'm still having light issues when rendering tiles (which need to be perfectly even across). Whatever light source I use, the lighting of the tile isn't even. There is a brighter area at the center of the tiles. This is with specularity turned off. I have no idea why.

Ric
25/10/2021 20:02

I'm no designer myself - a developer by trade really and our actual designers aren't experienced in Blender - but it does sound to me like your approach is a tad convoluted. On the one hand there's always more than one way to achieve these things and no working method is ever wrong, but the simpler you can get it, the easier it'll be to work with moving forwards.

My Blender install is recompiled with Cycles support now and I did get chance earlier today to have a quick fiddle. It seems Cycles now has a shadow catcher mask option which actually works well - just select the base in my original rig and from the object properties panel, scroll down to the visibility tab and tick "Shadow catcher". That seems to be enough to get the ground shadow working, (just remember to first switch to Cycles from the render options panel), but as you've already discovered, spot lights can't be set to cast shadows without emitting light in Cycles.

I do actually have a vague memory of making a Cycles version of my original rig at some point, using layers so that basically the spot light and shadow rendered to one layer and the object and sun light rendered to another layer, and then the renderer merged the two into a single image. I don't remember how well this worked but I might be able to dig that old rig back out of our archives, or recreate it again as long as layers still work the same in current Blender versions. This might be what Blender is now calling "Collections" in the scene list actually.

Again, I'll have another proper look asap and post back.

Ric
31/10/2021 18:56

Pleased to confirm I've gotten a working rig now, using Cycles and Blender 2.93. I've taken a layers approach with Composite nodes but in a way that's not too different to my original method and each step is explained in the same detail as I had before. I've written everything down and will be updating this post tomorrow if not this evening. I'll provide a replacement download too for the rig itself, of course.

Ric
01/11/2021 19:32

Post now updated, and the rig file replaced. Let me know how you get on.

James
02/11/2021 18:56

This is awesome Ric, thank you so much for updating the post!! You're a good man. Cheers!

James
02/11/2021 18:58

Oh and it's working well for me with a few deviations here and there, which I gleaned from learning Blender over the past couple of weeks!

Ric
02/11/2021 19:36

No problem. It wasn't an entirely selfless effort if I'm honest - we'll need this rig again at some point too so would have needed to revise it anyway. Glad it can be useful to others in the meantime.

Leave a comment

Your email address is used to notify you of new comments to this thread, and also to pull your Gravatar image. Your name, email address, and message are stored as encrypted text and you won't be added to any mailing list and your details won't be shared with any third party.

This site is protected by reCAPTCHA and the Google Privacy Policy & Terms of Service apply.