Skybox depthrange/farclip trick

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Skybox depthrange/farclip trick

Post by mh »

This one's easy; if you're drawing a skybox you normally need to worry about the far clipping plane, and that it's sufficiently large to accommodate the skybox dimensions.

But the thing is that you don't. It's actually completely unnecessary.

This one is based on the FitzQuake 0.85 code, but it's easily adaptable to any engine.

First of all, find this code block:

Code: Select all

void Sky_EmitSkyBoxVertex (float s, float t, int axis)
{
	vec3_t		v, b;
	int			j, k;
	float		w, h;

	b[0] = s * gl_farclip.value / sqrt(3.0);
	b[1] = t * gl_farclip.value / sqrt(3.0);
	b[2] = gl_farclip.value / sqrt(3.0);
Change it to:

Code: Select all

void Sky_EmitSkyBoxVertex (float s, float t, int axis)
{
	vec3_t		v, b;
	int			j, k;
	float		w, h;

	b[0] = s * 10.0f;
	b[1] = t * 10.0f;
	b[2] = 10.0f;
Now find this code block:

Code: Select all

void Sky_SetBoxVert (float s, float t, int axis, vec3_t v)
{
	vec3_t		b;
	int			j, k;

	b[0] = s * gl_farclip.value / sqrt(3.0);
	b[1] = t * gl_farclip.value / sqrt(3.0);
	b[2] = gl_farclip.value / sqrt(3.0);
And change it to:

Code: Select all

void Sky_SetBoxVert (float s, float t, int axis, vec3_t v)
{
	vec3_t		b;
	int			j, k;

	b[0] = s * 10.0f;
	b[1] = t * 10.0f;
	b[2] = 10.0f;
OK, what we're doing here is drawing the sky as a 10x10 cube instead of positioning it at the far clipping plane. Madness? Nope, because all we need to do in order to push it to the back of the depth buffer is find this code:

Code: Select all

	if (!r_fastsky.value && !(Fog_GetDensity() > 0 && r_skyfog.value >= 1))
	{
		glDepthFunc(GL_GEQUAL);
		glDepthMask(0);

		if (skybox_name[0])
			Sky_DrawSkyBox ();
		else
			Sky_DrawSkyLayers();

		glDepthMask(1);
		glDepthFunc(GL_LEQUAL);
	}
And change it to:

Code: Select all

	if (!r_fastsky.value && !(Fog_GetDensity() > 0 && r_skyfog.value >= 1))
	{
		glDepthRange (1, 1);
		glDepthFunc(GL_GEQUAL);
		glDepthMask(0);

		if (skybox_name[0])
			Sky_DrawSkyBox ();
		else
			Sky_DrawSkyLayers();

		glDepthMask(1);
		glDepthFunc(GL_LEQUAL);
		glDepthRange (0, 1);
	}
Hey-presto. Sky is now automatically positioned at the back of the scene, and you don't need to worry about your far clipping plane, positioning things correctly, or any of that. It will just automatically be correct with any scene geometry.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
metlslime
Posts: 316
Joined: Tue Feb 05, 2008 11:03 pm

Post by metlslime »

I just looked at this, and WTF -- why am i doing three sqrt() calls PER VERTEX!!!!!!!1
Tomaz
Posts: 67
Joined: Fri Nov 05, 2004 8:21 pm

Post by Tomaz »

Why not just use glDisable( GL_DEPTH_TEST ); ?

According to specs ( http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml ) it should turn off both "read" and "write" operations with the depth buffer.
metlslime
Posts: 316
Joined: Tue Feb 05, 2008 11:03 pm

Post by metlslime »

Tomaz wrote:Why not just use glDisable( GL_DEPTH_TEST ); ?

According to specs ( http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml ) it should turn off both "read" and "write" operations with the depth buffer.
Theoretically that would work, though it would annoy me to see a big skybox floating there when i noclip outside the level.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

an alternative is GL_ARB_depth_clamp / GL_NV_depth_clamp.

another alternative is as follows:
draw the skybox as the very first thing you draw, with depth testing inactive, and you get a similar result.
for bonus points, you can easily have a fastsky that clears the sky via glClear too.
which is basically what q3 does.

you likely also need to write the proper depth (glcolormask(0,0,0,0) to write just depth without colours) if you want to avoid artifacts on certain q1 maps. but that applies to any skybox/skysphere algorithm that I've seen. Many don't bother, and result in players appearing behind the sky on dm3, for example.

also, the code mh gives will conflict with gl_ztrick (you shouldn't really want to use ztrick on recent hardware, but still this should be mentioned).
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Post by qbism »

Spike wrote:players appearing behind the sky on dm3
This is a paradox which exposes the truth. Really the sky should not be visible from this viewpoint, it would be obstructed by the structure containing the exposed players.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

The obvious more correct way is to use a cubemap. That'll avoid all such artefacts, only draw the skybox on actual sky brushes, eliminate any fillrate concerns, and completely remove the need for any kind of depth hacking. It does need a bit of jiggery-pokery with box face image orientations at load time though.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Tomaz
Posts: 67
Joined: Fri Nov 05, 2004 8:21 pm

Post by Tomaz »

metlslime wrote:
Tomaz wrote:Why not just use glDisable( GL_DEPTH_TEST ); ?

According to specs ( http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml ) it should turn off both "read" and "write" operations with the depth buffer.
Theoretically that would work, though it would annoy me to see a big skybox floating there when i noclip outside the level.
See a floating skybox where?

Obviously when doing a "no-depth" sky you render it before everything else, and have it translated to where your camera is ( view_org in Quake? been so long since last time I touched Quake code ), only downside to this that I can see is fillrate, I do something similar when rendering the regular quake sky in CleanQuake, using a sphere for the sky, rendering it first as a no-depth sky, obviously it only renders it if the Update code found a skybrush that would originally be marked to be rendered.
Post Reply