Building An Isometric Game Using Horde3D (Part 2)
Constructing Geometry Using Anti-Aliased Sprites
As a jumping off point for trying to use pre-existing anti-aliased rendered sprites, I want to create a few geometry primitives using some pre-rendered assets. For the first tests, I'll set up a set with a basic floor tile, a floor decal for decoration, a left wall, a right wall, a roof, and a basic wall decal for decoration. This will give me a good set to test with and, hopefully, help me to see where I'm going to have issues.
To begin, I'll just go ahead and grab the assets I made for the SFML isometric post.
Then I'll fire up Blender and map those sprites to some geometry. The way I do this for a 3D-based game is to create the geometry to match the shape and orientation of the sprite. I do need to construct the wall geometry to be of the proper height, in pixels, on the screen. This means taking into account the fore-shortening introduced by the camera angle.
With a 2:1 tile-ratio dimetric projection, the camera angle above the horizon is 30 degrees, the angle around the Z axis is 45. Now, going with the above assets which are 64 pixels wide, this means that the total cell on-screen size is 128 pixels wide. Ignoring the 30 degree azimuth angle for a moment, we can calculate the length of the cube edges using the Pythagorean theorem, a^2+b^2=c^2. The hypotenuse is 128 pixels long, and the cube sides are the same length, so 2*a^2=128^2. Solving for a we get a=sqrt((128*128)/2) or a~90.5. So if the cube edges are approximately 90.5 in pixel units, then we now take into account the foreshortening of the vertical axis by the 30 degree azimuth angle, by multiplying the edge length by cos(30), to get approximately 78.384. Thus, taking the 64 pixel width of the isometric wall sprites, a unit cube on-screen will be approximately 78.384 pixels tall. We can prove this by firing up Blender and rendering a unit cube from the dimetric viewpoint to an image of the appropriate size:
If you open that image in an image editor and put the cursor at the apex of the near corner of the cube, you will see that it is approximately 78 pixels above the bottom of the image, so our math works. Now, the wall assets I created for the SFML isometric post are 256 pixels tall, and 64 pixels wide. The vertical axis represented is 224 pixels. Dividing 224 by 78.384 we get 2.8577. This is the amount we need to scale the unit cube by, vertically, in order to obtain geometry that matches the 64x256 size of the assets.
This stuff can get confusing, I know. One of these days I might try to write a more comprehensive guide, but for now I'm not too concerned about it. If we go back to Blender and apply the vertical scale to the unit cube, then re-adjust the output image dimensions to 128x256 (showing both the right wall and the left wall) and render, we'll get something like this:
You can see that this is the right size to get the full left and right walls. Now, since at this stage we are just trying to build geometry for the wall planes, we can go ahead and delete the "back" vertices of the cube:
This removes extraneous geometry and leaves us with just the wall planes. Now, we need to separate the planes into separate objects. We do this by entering edit mode, selecting the 4 vertices that form a wall plane, and hitting p to separate the selected pieces. This leaves us with 2 wall planes. The only thing left to do now is UV map them. Select a wall plane, enter edit mode and select all vertices, switch view to Camera view, press u to Unwrap, and select Project From View (Bounds). This will map the UVs from the camera view, and the result is something like this:
Do the same with the other wall piece. From here, it's a simple matter of applying materials to the wall pieces and exporting them to Collada for conversion, then loading them into the game framework to see the results. Here is a test run with the left wall piece:
The image is scaled down so you can't really see it, but there are filtering artifacts due to small math imprecisions. I'm still using the default shaders. I'll be replacing them with more appropriate ones that will disable filtering to avoid those artifacts soon.
The floors, roofs, and floor/roof decal geometry setups are similar, though much easier to do. For those, I simply use a 1x1 plane oriented on X/Z.
Next up, I'm going to figure out a drawing order and re-write the basic shaders I'll be using.