Alright
, here goes:
We have a
standard 3d world from standard geometry (untextured here for contrast), rendered in the "classical" sense. By that, I mean that the projection matrix is a
symmetric perspective projection frustum transformation. And it looks like this at a FOV of 75 degrees rendered at more or less Full HD:
Now, as you can see, the above screenshots shows terrain only. The idea was to marry this full 3d terrain with an old-school sprite based look, that means all objects on the terrain should not be made out of actual geometry but consist only of pre-rendered or drawn images, like in the good old days
. The thing about these classic games is, that they ever only had sprites of an object at exactly one particular vertical angle:
* in games like
Doom or
Wolfenstein, all sprites were drawn to accommodate a player looking at them from the same elevation as the object the sprite is representing
* in games like
Myth: The Fallen Lords or the early Total War games, all sprites were drawn to accommodate a player looking at them from a sort of 50 degrees angle above the object the sprite is representing
While Doom's raycasting engine was involved enough to "simulate" elevation differences, the game's actual vertically in the level design had to be limited in order to not betray the effect (and at various points in even the original levels, the illusion broke down hard due to elevation differences). In the RTS-games mentioned above, both camera movement and degrees of possible rotation had to be controlled and restricted a lot for the very same reason.
Again, the idea was to achieve a similar old-school look but avoid these restrictions, with our nice, modern gigabytes of RAM. As such, I have spritesheets that not only show the object at different rotations but also seen from different angles! Below an examplary image, to illustrate what I mean by that (this is not a real nor a complete spritesheet and it is not pixel accurate either):
This means, I had to come up with a way to combine the actual 3D geometry and the pseudo-3D like the programmers of old. In contrast to Doom's utterly fake ray-caster however, we have modern OpenGL and after doing some investigation into possible techniques, I arrived at using
spherical billboards and switching textures based on the angle. The reason: I obviously need a "canvas" to render the texture onto and that canvas should always be perpendicular to the camera's
look-at angle. Instead of trying to reconcile two utterly different notions of what space and perspective is, I thought rendering it all in the standard way and just "rotating the rectangular sprite-objects to face me" should solve the problem quite easily and early attempts looked promising. However, in practice, the effect breaks down. Consider the following:
Here is a nice line of tree sprites, never mind the transparency-problems. I have chosen trees in this example because their trunk's will illustrate the problem quite nicely later. Our camera is level towards this group, that means the billboard-effect in question is currently not a spherical but a cylindrical one, as there is no vertical rotation to speak of.
If we move and rotate the camera around the group, everything looks fine. In the example below, I rotated counter-clockwise (see the mountain in the background). The billboards continue to face the camera and the texture-switch has exchanged the sprite-texture for a horizontal and vertical viewing angle of about 0 degrees with another simulating the horizontal viewing angle of about 45 degrees, but a still level vertical one.
Going back to the original position, we now move the camera upwards. Again, the textures are exchanged, the spherical billboard continues to face us but the effect breaks down hard
.
The relevant sprite sheet for a vertical angle of about 45 degrees looks like this:
We can see that all the trunks are perfectly vertical and nothing there is angled. Now, there are
two possibilites here:
1.) I simply have a bug in the billboarding shader!While this is always possible, visual investigation seems to indicate otherwise. Doing the same trick as in the OP above, namely just coloring discarded transparent pixels as red, once can see the rectangles and they appear to behave correctly:
I had to space out the trees of the example, to make this image visually digestable
but otherwise, everything is the same. It is important to mentioned that I am currently using what I call a stepped spherical billboard, that means I am not facing the camera exactly. Instead, the billboard can only rotate in the exact number of sprite angles for that axis. Since the tree as sprites for 8 possible horizontal angles, that means the billboard is either rotated 0 degrees, 45, 90, and so forth. This can be nicely observed in the picture.
2.) We are facing the opposite of an optical illusion!Weirdly enough, the picture with the non-red trees looks terrible while the one with the red-background trees looks fine, at least to me. This is seemingly due to the fact that our brain latches on to the now visualized rectangle, deems that to be okay enough and no tree looks terribly bend or angled anymore to me. So basically, everything looks terrible to our tiny lizard brain until does stops doing so.
I thought about this entire problem for a while now and I think that everything we can observe here is actually doing the exact job that I programmed it to do, especially the perspective projection matrix. But obviously, it really sucks
and looks terrible. Combining 2d and 3d in a way that looks both good and interesting can be really hard, a statement supported by the various blog posts on the internet regarding this topic.
I am looking for input here on how to improve the look of this and look forward to discussing if my entire approach is wrong, which might very well be the case.