Skies and 3D ness

Discuss programming topics for the various GPL'd game engine sources.
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Re: Skies and 3D ness

Post by taniwha »

Ok, I put some graffiti on marcher's skybox textures (I labeled them such that they'd be easy to identify in-game). Everything seems to be quite ok: the label text is all correct when looking at the relevant face (ie, nothing written backwards or upside down). However, right is left and left is right, but I suspect that might be a viewpoint thing: ie, lf and rt are from the viewpoint of somebody outside the box looking at the front of the box, rather than someone inside the box looking at the front.

This now raises the question of which way (in quake coordinates) should be front? +X? +Y? Or less likely, -X or -Y? As a point of interest, the sun is on the back face for marcher's skybox.
Leave others their otherness.
http://quakeforge.net/
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Skies and 3D ness

Post by mh »

Just plugged this code into both OpenGL and D3D renderers and yes, it works. Pretty neat, and yeah, you were right - no need for flipping/etc. Of course, it does trade off a per-fragment inverse square root and dotproduct at runtime versus load time overhead with the flipping/etc method (which otherwise just requires a regular cubemap lookup with no inverse square root or dot product needed). Flipping/etc will also work with the fixed pipeline which is not a concern of mine but may be for Baker. On balance I think I'll prefer taking the load time overhead in exchange for a little extra runtime performance though, especially as it gives better consistency with my alternate manual cubemapping code for where a mod provides skybox textures that don't conform to the cubemap rules.

A simple rotate of the cubemap matrix by 90 degrees around z is all that's needed to align it correctly (do before any other matrix ops here), and cross-checking with FitzQuake shows everything lines up as expected.
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
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Re: Skies and 3D ness

Post by taniwha »

ok, so QF's boxes are rotated after all? Easily fixed.

As for the inverse-root: I'm not certain that's actually necessary. I don't think I tested without it.
Leave others their otherness.
http://quakeforge.net/
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Skies and 3D ness

Post by mh »

Just tested without either the inverse root or the dot, works fine. That makes sense as this is just a normalization which shouldn't be needed for textureCube. I'm feeling more inclined to adopt this code now.

Just for the record, here's my own current (Quake 2) implementation:

Code: Select all

#define SURF_COMMON_ATTRIBUTES \
	"uniform mat4 localmatrix;\n" \
	"layout(location = 0) in vec4 position;\n" \
	"layout(location = 1) in vec4 diffuse;\n" \
	"layout(location = 2) in vec4 lightmap;\n"

#define skycube_vs \
	SURF_COMMON_ATTRIBUTES \
	"uniform mat4 skymatrix;\n" \
	"\n" \
	"void main ()\n" \
	"{\n" \
	"	gl_Position = localmatrix * position;\n" \
	"	gl_TexCoord[0] = skymatrix * position;\n" \
	"}\n"

#define skycube_fs \
	"uniform samplerCube skydiffuse;\n" \
	"\n" \
	"void main ()\n" \
	"{\n" \
	"	gl_FragColor = textureCube (skydiffuse, gl_TexCoord[0].xzy);\n" \
	"}\n"

GLuint r_skytexture;
char *suf[6] = {"ft", "bk", "rt", "lf", "up", "dn"};

static GLenum sky_target[] =
{
	GL_TEXTURE_CUBE_MAP_POSITIVE_X, // front
	GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // back
	GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // left  (normally -ve Z, see shader)
	GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, // right (normally +ve Z, see shader)
	GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // up
	GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // down
};


void LoadTGA (char *name, byte **pic, int *width, int *height);

void R_SetSky (char *name, float rotate, vec3_t axis)
{
	int i;
	int size = 0;

	strncpy (skyname, name, sizeof (skyname) - 1);
	skyrotate = rotate;
	VectorCopy (axis, skyaxis);

	glDeleteTextures (1, &r_skytexture);
	glGenTextures (1, &r_skytexture);

	GL_BindTexture (GL_TEXTURE0, GL_TEXTURE_CUBE_MAP, 0, r_skytexture);

	// load the images
	for (i = 0; i < 6; i++)
	{
		int width, height;
		byte *data = NULL;
		char pathname[MAX_QPATH];

		Com_sprintf (pathname, sizeof (pathname), "env/%s%s.tga", skyname, suf[i]);
		LoadTGA (pathname, &data, &width, &height);

		if (!size && data && width && height) size = width;

		if (data && width == size && height == size)
			glTexImage2D (sky_target[i], 0, GL_RGBA8, size, size, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
		else glTexImage2D (sky_target[i], 0, GL_RGBA8, size, size, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
	}
}


void R_DrawSkyChain (msurface_t *surf)
{
	int i;
	msurface_t *reversechain = NULL;
	int numindexes = 0;
	glmatrix skymatrix;

	if (!surf) return;

	GL_LoadIdentity (&skymatrix);
	GL_RotateMatrix (&skymatrix, 90, 0, 0, 1);
	GL_RotateMatrix (&skymatrix, r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]);
	GL_TranslateMatrix (&skymatrix, -r_origin[0], -r_origin[1], -r_origin[2]);

	// push the depth range back to far end of the z-buffer
	// rogue has some pretty - unusual - brush placement and needs this
	GL_Enable (DEPTHTEST_BIT | (gl_cull->value ? CULLFACE_BIT : 0));
	glDepthRange (gldepthmax, gldepthmax);

	GL_UseProgram (gl_skycubeprog);

	glUniformMatrix4fv (u_skylocalmatrix, 1, GL_FALSE, r_mvpmatrix.m[0]);
	glUniformMatrix4fv (u_skytexturematrix, 1, GL_FALSE, skymatrix.m[0]);

	GL_BindTexture (GL_TEXTURE0, GL_TEXTURE_CUBE_MAP, r_skysampler, r_skytexture);

	for (; surf; surf = surf->texturechain)
	{
		surf->reversechain = reversechain;
		reversechain = surf;
		numindexes += surf->numindexes;
	}

	R_DrawSurfaceChain (reversechain, numindexes);
	glDepthRange (gldepthmin, gldepthmax);
}
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
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Skies and 3D ness

Post by Spike »

this works for the "ft", "bk", "rt", "lf", "up", "dn" postfix, but there are other postfixes that you might encounter that are not flipped for quake, so you might need a conditional in there. Which is annoying.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Skies and 3D ness

Post by mh »

Fortunately no mod that I'm aware of uses other postfixes so it's most likely a non-issue.

Changing the load order to char *suf[6] = {"ft", "bk", "up", "dn", "rt", "lf"}; lets you get rid of sky_target and just use GL_TEXTURE_CUBE_MAP_POSITIVE_X + i in your loading loop; handy (I'd come across an AMD driver before that choked on cubemaps if they weren't specified in that strict order).
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
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Skies and 3D ness

Post by Baker »

After a lot of messing around, so far I couldn't get cubemaps to work (I was probably super-close). But a sky sphere / sky dome works fine and that was easy enough.

A bit a shame since I really wanted to load these up: http://www.humus.name/index.php?page=Textures (beautiful)

Image

Image

I did a lazy method drawing the skydome first with glDepthMask off so it couldn't interfere with anything (i.e. z fail something). I will say cubemaps add some weirdness to texture management, having to upload 6 textures (positive x, negative x, etc.) to complete a single slot and none of the textures "own" the texture slot.

That being said, I'm not super-fond of the distortion that a skysphere introduces when rendering the texture :( I'm kinda wondering if a cube map doesn't do likewise.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Skies and 3D ness

Post by Spike »

you can generally hide distortion quite well, so long as the ripples are in world space instead of screen space, and the poly count is high enough.
glsl can project the image properly, and will completely remove the need for a sky sphere.
I'd suggest using the texture matricies for fun stuff, that that's vertex-program level rather than fragment-program level, so won't help.
glsl is seriously awesome.

cubemaps are not fantastically different from 3d textures, just with a depth/layercount of 6, and that its specified via the 2d function instead of 3d function.
remember that you need to either explicitly disable mipmapping, or to upload a full set of mipmaps, or your texture will be invalid. Cubemaps will need all 6 faces specified, or it will also be invalid, but I'm sure you realise that.
They can be a real pain to load - most people load each face from a separate file.
You can try a dds file too/instead. Those contain the cubemap faces each separately within the file.
you shouldn't have any distortions with cubemaps. however, its possible that the borders of the cubemap wrap instead of clamp. this can result in ugly borders. More recent hardware can properly map on to the neighbouring face, but this needs to be explicitly enabled.
cubemaps will not help you remove distortion when the map specifies only a legacy 2d sky, but shouldn't have significant distortion themselves.
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Re: Skies and 3D ness

Post by taniwha »

Using nvidia hw, I get no visible distortion (that I've noticed) with cubemaps on any q1 map I've tried (including id's maps). The intel hw in my eeepc is another matter, but it doesn't get the walls right, let alone the sky :/.

Blender exports cubemaps with all 6 faces in the one png. I'm not certain about the details of setting it all up, but if you model a full scene in blender, you can make your own cubemaps :). Blenders cubemaps are 3Nx2N (N is the resolution of each face) with (bk rt ft) along the top and (dn up lt) along the bottom (normal quake suffixes). QF's glsl_bsp.c has code to load such files.

For the skyboxes you posted, they're already nicely setup (separate negx/posz etc files), but if your shader is setup for ft/bk/... skyboxes, you'll need to swap things around a little.

I reckon you want that second skybox for the girl ;).
Leave others their otherness.
http://quakeforge.net/
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Re: Skies and 3D ness

Post by taniwha »

mh: Not that I'm sure I recommend supporting such a feature (I started to feel a little ill while testing... at 0.2 and 0.28 radians/second :mrgreen:), but even QF's rotating skies work properly, and because of them, the rotate-on-z correction is just one extra per-frame quaternion multiply.

Anyway, now you see the (rising?) sun as you leave the cave at the beginning of Marcher (in the glsl renderer: gl will take a bit of work).
Leave others their otherness.
http://quakeforge.net/
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Skies and 3D ness

Post by mh »

The only time I've ever seen distortion in cubemaps was when I wrote my own cubemapping code in a fragment shader and got some things wrong; otherwise they're rock-solid. That's not an approach I'd recommend in the general case (it's more complex and somewhat slower) but it was useful for the occasional case where a mod may supply e.g. a "bottom" texture that is smaller than the rest (based on the - entirely reasonable - logic that since you can't see the bottom most of the time, it can be supplied smaller (if at all)). The other option is to just resample the bottom texture up to the same size as the rest.

The texture matrix is quite cool for cubemaps. You can do things like multilayer skyboxes - a background layer that rotates slowly, a middle layer that rotates faster and a front layer that's static, for example. Mmmmm - clouds. That would need to be well-specified and standardised first, of course.
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
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Skies and 3D ness

Post by qbism »

Baker wrote:A bit a shame since I really wanted to load these up: http://www.humus.name/index.php?page=Textures (beautiful)
Thanks for the link, I was inspired by these. "Unforgiven: One Night at the Museum" Properly named textures at http://qbism.com/chan/res/137.html just realized will have to rename if downloaded, but original name is in title.
Image
mankrip
Posts: 924
Joined: Fri Jul 04, 2008 3:02 am

Re: Skies and 3D ness

Post by mankrip »

This... is... beautiful.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Skies and 3D ness

Post by Baker »

qbism, that is pretty nice looking. In fact, it made me remember something (your pic reminds me of something I found a while back) ... I should have a working cubemaps deal on another computer. I found someone's crazy OpenGL experiments somewhere on github 6-7 months ago and was looking them over. Lucky me +1
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Skies and 3D ness

Post by mh »

More info on the QF cubemap orientation.

Loading the following onto your texture matrix (before rotate and translate) will orient the sky correctly: 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 (this may be row-major).
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
Post Reply