glDepthFunc and GL_LEQUAL for background drawing in an OpenGL ES 2 Android\iOS game.

For the (semi secret)game I am currently working on( I had to implement the background or backdrop of the 3D world.

A simple method to draw the background is having a textured sphere mesh surround the camera.

The issue with this method is that the sphere is not perfect so there are distortions and it doesn’t completely fit the viewing frustum. Which means some geometry that is inside our frustum will be occluded by the sphere.

A different method is to draw a screen space quad at the exact back end of the frustum. This quad will have coordinates in screen space and won’t require transformation.

The back of the plane in screen space coordinates is 1.

You could disable writing into the ZBuffer with glDepthMask(false) and draw the background first. All the geometry that renders afterwards will overwrite the background.

However, what if we want to draw the background last and save on fill rate by using the ZBuffer?

Just drawing the background last should have done that but instead it might not render at all.

We usually clear the depth buffer part of the render buffer into 1.0 which is the highest value for the depth buffer. But our background screen mesh is also rendered into 1!

It turns out the default depth test function in OpenGLES is GL_LESS. Since the ZBuffer is already 1.0 our background screen mesh won’t render.

What we can do is before rendering the screen mesh, we can set the depth test function  into less or equal by calling: glDepthFunc(GL_LEQUAL);

This way our background buffer will not draw at pixels that we have drawn geometry before but will draw on the rest of the “blank” pixels.

Cube Shadow mapping and camp fire.

For quite some time I had this camp fire made of particles inside my demo scene. However, a camp fire without shadows looks a bit unnatural.
I have already implemented shadow mapping but only for a single projection. For the camp fire I need to map the shadows all around the camp fire, like a complete sphere.
There is a solution, it’s called cube texture.
In terms of topology a cube is isomorphic to a sphere, they both have a genus value of 0. This means that a cube can be stretched and deformed into a sphere without tearing the surface.
A torus(like a donut) has a genus 1 and cannot be stretched into a sphere.

DirectX11 and other APIs have intrinsic support for cube textures. In DirectX11 a cube texture is actually an array of 6 2D textures.
With a 2D texture we use a 2D vector to sample a Texel, namely the “UV coordinates”. This was sufficient because the 2D texture is like a bitmap in a sense.
With the cube texture we need a 3D vector to sample a Texel.
However, the length of the vector does not matter. This vector is “pointing” from the center of the cube texture and samples the Texels that it points to, or the Texel on the cube which the ray from the center with the direction of the vector intersects with.

Since we are doing shadow mapping, we need to compare the depth of our current pixel(in the pixel shader) to the depth in the shadow map.
With a single projection shadow mapping we achieved that by converting the world space position of the pixel into the screen space depth using the projection matrix and the view matrix of the light source.

float Depth = gLightProj._33+gLightProj._43/abs(toLight.z); // toLight here is in view space, the light acting as a camera.

In our cube map we have 6 projections, one for each side of the cube. We align the sides of the cube to the axes of the world space. Relying on the axes alignment and on the fact that the cube map is actually a cube and not a nonuniform box, we can calculate the depth value simply by taking the maximum absolute value of  x, y, z. We also don’t need to translate the coordinate into the view space like we did with the single projection, because we assumed that the sides of the cube map are aligned to the world space.

float3 toLight = pin.PosW-gCynLights[0].Position; // Now toLight is in world space float Depth = gLightProj._33+gLightProj._43/(max(abs(toLight.x), max(abs(toLight.y), abs(toLight.z))));

Cube mapping can get pretty expensive. We have 6 textures instead of 1, and we need to render the scene from 6 different projections to fill the cube map.
There are optimizations we can do though. First of all, we can start off by not picking very high-resolution for the cube map.
Another thing is that we don’t have to render the whole scene 6 times, we can just render the objects which are visible to each of the 6 projections. In other words, we can do macro level culling. Macro level culling is done by not sending objects for drawing to the GPU which are not gonna be visible anyway. With a smart separation of the scene into different chunks and objects, we can ideally render every object no more than once or twice.
Another approach is to use the geometry shader to duplicate the level objects for each one of the 6 projections. This will save draw calls and some processing, but it has its own performance issues.
In my demo I used the first method and for the walls and floor of the dungeon I disabled shadow casting all together because the effect of shadows casted from the walls was barely visible.

One last thing, I added a small touch to the camp fire. I randomly changed the camp fire’s light source intensity and position over time. This is a small detail that made the camp fire look much more real and alive.