Thursday, February 28, 2013

IsometricGood Damn it

Okay so I've been having trouble with making the isometric view just right. It's been a combination of learning about graphics and about Ogre3d. Let's describe two things first:

  • Z Buffer
  • Alpha Channel Transparency

Z Buffer. In a graphics engine when it goes through its rendering queue it has to decide what the final pixel it draws on your screen is. As it draws, for each pixel it records a "z value". This z value is based on the distance from your camera. It is usually non-linear; it slices your viewable area (your "viewing frustum") into unequal slices. The closer you are to the camera, the thinner the slices to get better accuracy.

As it decides to render the next pixel, it does a "depth check", and sees whether or not the z-value of the newest pixel is higher. If so, then it replaces the old pixel. If not, then it discards it. If it is of equal value, it might blend them or you might get z-fighting/flimmering (where it draws one or the other pixel).

Alpha Channel Transparency. If you look at a png (or other file types that support this) you'll see that it has colour channels and something called an alpha channel. You'll probably have to dig around to find this in your graphics editor. The alpha channel is a measure of opacity. It's useful for transparent objects. When you tell Ogre3d to do "alpha scene blending" of some kind, it blends the colours of the original existing pixel with that of the new pixel (assuming it passed the depth check).

When I was making my isometric view I made the terrain a staticGeometry. That makes it render super fast. The problem is that it renders super fast because Ogre3d combines the objects together and then renders it. The end result is that the terrain does "blocking" in giant squares, but nothing else does, so it'll just look wrong. I've tried it without the staticGeometry and the blocking works perfectly. Problem? Runs super slowly :/

Now the problem is that I have a lot of entities (my particular test run has about 900), so it runs very slowly. All it is making is 900 quads and applying textures. It's not much. Most of the quads don't need to be updated. In fact in any particular game, only units have to be updated and most of the scenery is static. Structures and piles of resources, which I would add later, would also not need to be updated very often. The main issue is that high number of entities that need to be sent to the video card to be rendered. Unfortunately, there's really only complicated ways to resolve this because I need to preserve the render order. Poop!

But! This is a common issue for many games (especially age-old isometric ones) and thus has solutions. I'm going to take some time to research my options and then move ahead on one.

Okay here is my current solution idea...

Problem? If I use staticGeometry to get quick batched geometry being sent to the video card I get great frame rate (which I rate as 60 FPS v-sync in debug). But staticGeometry groups the quads I make into super quads. Exactly what it is supposed to do but totally flubs my render order that I carefully arranged much like a house of cards. In the utter ruin of this I use Ogre3d render queue groups to get what I want. This is a lot of cheating and silliness but let's go through what I've done.

You can see in the picture I have problems because staticGeometry and render groups mess with my correct overlapping of objects that are taller than the square they occupy. Okay, but let's tackle one problem at a time. Let's deal with the staticGeometry but keep the performance. I can render all the base terrain, then all the grass, then all the bushes and then all the trees and then all the units all in different render queue groups. It takes care of the staticGeometry problem. Terrain overlapping itself doesn't matter. Grass and bush don't expand beyond a square so they can sit in the same render queue group. Trees have to be in a separate render queue group or else they don't overlap properly. Units are rendered last because they are each a separate entity and must be done in a costly square per square rendering.

Okay that solves the static geometry. But now, the unit still blocks the tree because of the render queue grouping. The feet of my humans block the top of trees. What if... we rerender those trees?

Oh noesss! It's still not quite correct. But it is less wrong. Anyway to be absolutely correct, I have to rerender EVERYTHING down the line. Well that seems costly. How to cheat more? I make the bushes smaller and fit exactly in the square. That is, I make as much stuff as possible shorter than a square. That means I rerender everything "downwards" (positive x, negative y) until I hit a square that doesn't have anything that breaches a square.

This renders at 60 FPS v-sync in debug. There is of course much horror and terror going on in my code which will have to be fixed and cleaned up but that is a task for Later Man, the King of Not Optimising Until It Is A Problem.

No comments:

Post a Comment