Journals need more animated GIFs

Published August 09, 2007
Advertisement


Pixel shaders are fun.

I've implemented support for decoding mip-maps from mip textures (embedded in the BSP) and from WAL files (external).

Now, I know that non-power-of-two textures are naughty. Quake uses a number of them, and when loading textures previously I've just let Direct3D do its thing which has appeared to work well.



However, now that I'm directly populating the entire texture, mip-maps and all, I found that Texture2D.SetData was throwing exceptions when I was attempting to shoe-horn in a non-power-of-two texture. Strange. I hacked together a pair of extensions to the Picture class - GetResized(width, height) which returns a resized picture (nearest-neighbour, naturally) - and GetPowerOfTwo(), which returns a picture scaled up to the next power-of-two size if required.



All textures now load correctly, and I can't help but notice that the strangely distorted textures - which I'd put down to crazy texture coordinates - now render correctly! It turns out that all of the distorted textures were non-power-of-two.

The screenshots above demonstrate that Quake 2 is also handled by the software-rendering simulation. The current effect file for the world is as follows:

uniform extern float4x4 WorldViewProj : WORLDVIEWPROJECTION;uniform extern float Time;uniform extern bool Rippling;uniform extern texture DiffuseTexture;uniform extern texture LightMapTexture;uniform extern texture ColourMap;struct VS_OUTPUT {	float4 Position : POSITION;	float2 DiffuseTextureCoordinate : TEXCOORD0;	float2 LightMapTextureCoordinate : TEXCOORD1;	float3 SourcePosition: TEXCOORD2;};sampler DiffuseTextureSampler = sampler_state {	texture = ;	mipfilter = POINT;};sampler LightMapTextureSampler = sampler_state {	texture = ;	mipfilter = LINEAR;	minfilter = LINEAR;	magfilter = LINEAR;};sampler ColourMapSampler = sampler_state {	texture = ;	addressu = CLAMP;	addressv = CLAMP;};VS_OUTPUT Transform(float4 Position : POSITION0, float2 DiffuseTextureCoordinate : TEXCOORD0, float2 LightMapTextureCoordinate : TEXCOORD1) {	VS_OUTPUT Out = (VS_OUTPUT)0;	// Transform the input vertex position:	Out.Position = mul(Position, WorldViewProj);		// Copy the other values straight into the output for use in the pixel shader.	Out.DiffuseTextureCoordinate = DiffuseTextureCoordinate;	Out.LightMapTextureCoordinate = LightMapTextureCoordinate;	Out.SourcePosition = Position;	return Out;}float4 ApplyTexture(VS_OUTPUT vsout) : COLOR {	// Start with the original diffuse texture coordinate:	float2 DiffuseCoord = vsout.DiffuseTextureCoordinate;	// If the surface is "rippling", wobble the texture coordinate.	if (Rippling) {		float2 RippleOffset = { sin(Time + vsout.SourcePosition.x / 32) / 8, cos(Time + vsout.SourcePosition.z / 32) / 8 };		DiffuseCoord += RippleOffset;	}	// Calculate the colour map look-up coordinate from the diffuse and lightmap textures:	float2 ColourMapIndex = {		tex2D(DiffuseTextureSampler, DiffuseCoord).a,		1 - (float)tex2D(LightMapTextureSampler, vsout.LightMapTextureCoordinate).rgba	};		// Look up and return the value from the colour map.	return tex2D(ColourMapSampler, ColourMapIndex).rgba;}technique TransformAndTexture {	pass P0 {		vertexShader = compile vs_2_0 Transform();		pixelShader  = compile ps_2_0 ApplyTexture();	}}


It would no doubt be faster to have two techniques; one for rippling surfaces and one for still surfaces. It is, however, easier to use the above and switch the rippling on and off when required (rather than group surfaces and switch techniques). Given that the framerate rises from ~135FPS to ~137FPS on my video card if I remove the ripple effect altogether, it doesn't seem worth it.

Sorting out the order in which polygons are drawn looks like it's going to get important, as I need to support alpha-blended surfaces for Quake 2, and there are some nasty areas of Z-fighting cropping up.

Alpha-blending in 8-bit? Software Quake didn't support any sort of alpha blending (hence the need to re-vis levels for use with Quake GL as underneath the opaque waters were marked as invisible), and Quake 2 has a data file that maps 16-bit colour values to 8-bit palette indices. Quake 2 also had a "stipple alpha" mode used a dither pattern to handle the two translucent surface opacities (1/3 and 2/3 ratios).
0 likes 2 comments

Comments

Ravuya
Man, that looks good.

I remember the first time I tried S3 ViRGE Quake back in the day. I think that was the first time I ever saw antialiasing on textures in a computer game, and I was blown away.

Oh, and the GLQuake "translucent water" patches. I remember having holy hell with other people on QuakeWorld who were able to see through the water I was camping in and frag me. Those bastards! Just because I can't afford a decent graphics chipset...
August 09, 2007 10:34 AM
benryves
Quote:Original post by Ravuya
I remember the first time I tried S3 ViRGE Quake back in the day. I think that was the first time I ever saw antialiasing on textures in a computer game, and I was blown away.
I'm still of the opinion that low-resolution textures - such as those offered by Quake or, say, DOOM - look much better with nearest-neighbour filtering. Part of this might be due to Quake storing its textures at "half brightness", and getting the full brightness texture by multiplying by two or adjusting it via the colour map in a once-off operation doesn't look right (clipped colours). Using the colourmap and original texture indices fixes this, at the expense of some inflexibility when it comes to filtering the textures (as you can't end up with non-integral colour indices).

Quote:Oh, and the GLQuake "translucent water" patches. I remember having holy hell with other people on QuakeWorld who were able to see through the water I was camping in and frag me. Those bastards! Just because I can't afford a decent graphics chipset...
Hehe [grin] I guess now that the source is available you could add Quake 2-style software alpha, though that would only be a decade or so too late.
August 09, 2007 11:40 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement