Back in the first post where I announced CANINE, all I had was a 2-D grid representing the level that highlighted the parts of the screen that were visible to the player through a theoretical frustum. I have since implemented a three-dimensional world using the same data model. It wasn’t really that hard using OpenGL: the walls can be positioned at real 3-D coordinates, and the graphical processing unit (GPU) will take care of the rest. The main difficulties are figuring out how to store the polygon data and avoiding polygons that won’t even be visible at the player’s current angle. However, this was mostly solved in the 2-D raycaster from my previous post. The only additional polygon-culling I’ve done is glEnable(GL_CULL_FACE), which tells the GPU to ignore polygons drawn in counter-clockwise order (thus only showing polygons that are facing you) and this pseudocode:
if x < player.x: draw_wall (x + 1, y, WEST_WALL)
else if x > player.x draw_wall (x - 1, y, EAST_WALL)
if y < player_y: draw_wall (x, y - 1, NORTH_WALL)
else if y > player_y: draw_wall (x, y + 1, SOUTH_WALL)
This ignores any polygons that would be facing away from you and, thus, hidden by the rest of the wall. I think this actually kind of eliminates the use for glEnable(GL_CULL_FACE), but I don’t think it’s doing any harm to double up here. I’m thinking of having 3-D sprites in the future, in which case glEnable(GL_CULL_FACE) should really help.
(Videos now with Beethoven!)
Just yesterday I added two new cool features to this, both of which reassured me of the superiority of hardware- over software-rendering systems. The first is the addition of textured walls. Under Vandevenne’s software renderer, using only 64×64 textures on a 512×384 display, it runs at about 50 frames-per-second on my Dell Optiplex 745 with Arch Linux. My hardware-accelerated engine, using 256×256 textures at 1024×768 runs at about 70 frames-per-second. Porting back those dimensions to Vandevenne’s engine, his only runs at 10-20 frames-per-second! Pretty impressive, eh?
Of course, Vandevenne’s limitations are only important for developers who actually want those dimensions, but who wants to be limited like that? Also, OpenGL is automatically stretching textures as needed, while that would have to be directly implemented in Vandevenne’s renderer. This means that under my engine, you could have 64×64, 256×256 or even 100×42 textures all in the same level without having to worry about it.
The second thing is that you can look up and down in my engine now. Albeit, that’s kind of pointless when everything in the game such short walls and items are always at the same level as you, it can be pretty cool (especially if skybox’s come into play — (^-^)).
Disclaimer: I don’t mean to insult Lode Vandevenne and his renderer. Without his tutorial, I wouldn’t have understood raycasting so quickly. His renderer shows all the nitty-gritty details of how raycasting works. It’s an amazing way to speed up hardware rendering, and is required in the equivalent software renderer. It also has some interesting implications in enemy logic (can the enemy see me?).