Page 1 of 1

Skybox depthrange/farclip trick

Posted: Sat May 28, 2011 11:50 pm
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.

Posted: Wed Jul 13, 2011 10:03 pm
by metlslime
I just looked at this, and WTF -- why am i doing three sqrt() calls PER VERTEX!!!!!!!1

Posted: Wed Jul 13, 2011 11:22 pm
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.

Posted: Thu Jul 14, 2011 1:11 am
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.

Posted: Thu Jul 14, 2011 2:10 am
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).

Posted: Thu Jul 14, 2011 3:43 am
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.

Posted: Thu Jul 14, 2011 8:58 am
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.

Posted: Thu Jul 14, 2011 10:02 am
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.