• entries
162
262
• views
167098

138 views

Since someone asked about it, I thought I'd post up the details of the reflection shader from earlier (the ice scene).

Heres the actual GLSL fragment shader source:
uniform sampler2D reflectMap; // Scene is held in this textureconst int numSamples = 16;const float divisor = 1.0 / float(numSamples);vec2 samples[numSamples];void main(){	// Our generated poisson disc sample offsets	samples[0] = vec2(0.007937789, 0.73124397);	samples[1] = vec2(-0.10177308, -0.6509396);	samples[2] = vec2(-0.9906806, -0.63400936);	samples[3] = vec2(-0.5583586, -0.3614012);	samples[4] = vec2(0.7163085, 0.22836149);	samples[5] = vec2(-0.65210974, 0.37117887);	samples[6] = vec2(-0.12714535, 0.112056136);	samples[7] = vec2(0.48898065, -0.66669613);	samples[8] = vec2(-0.9744036, 0.9155904);	samples[9] = vec2(0.9274436, -0.9896486);	samples[10] = vec2(0.9782181, 0.90990245);	samples[11] = vec2(0.96427417, -0.25506377);	samples[12] = vec2(-0.5021933, -0.9712455);	samples[13] = vec2(0.3091557, -0.17652994);	samples[14] = vec2(0.4665941, 0.96454906);	samples[15] = vec2(-0.461774, 0.9360856);		// Blur weight comes from vertex colour	float weight = gl_Color.r;	// Blur spread amount	float spread = min(weight*2.0, 0.5);	spread *= 0.010;	// -- Distortion --		// Grab the base texture coord	vec2 baseCoord = gl_TexCoord[0].xy;		// Distort the texture coord based on a couple of sine waves	float offsetX = sin( weight * 80.0 );	offsetX *= 0.0015;		float offsetY = sin( baseCoord.x * 16.0 );	offsetY *= 0.009;		baseCoord += vec2(offsetX, offsetY);			// -- Blur --		// We'll accumulate the weighted samples here	vec4 cumulative = vec4(0, 0, 0, 0);		// Sample the texture at each sample point and accumulate	for (int i=0; i	{		cumulative += texture2D(reflectMap, baseCoord + (samples * spread) ) * divisor;	}			// -- Greyscale and output --		// Generate a greyscale colour of the final blur	float grey = cumulative.x*0.3 + cumulative.y *0.3 + cumulative.z*0.3;	float inv = 1.0 - weight;		vec4 greyCol = vec4(grey, grey, grey, 1.0);		// Final frag colour is the weighted avarage of the blur and the greyscale version	gl_FragColor = (cumulative * inv) + (greyCol * weight);}

Theres basically three sections to the shader - the sine wave distortion, the blur, and the greyscale fade in. The distortion is pretty hacky, but it breaks it up from being a perfect reflection.

The blur uses the growable poission disc method, where the disc is bigger based on the blur weight. The weight comes in via the vertex colour's red channel. It gets a bit artifact-y on big blurs, but the whole reflection has a separate texture blended over the top afterwards which hides a lot. The other problem my blur originally had was my sample points were generated in a square rather than a circle.

The greyscale is a simple avarage of the rgb value from the blur. A good improvement would be to use proper weights rather than a fixed third for each, but I havn't got around to looking them up yet. The same weight which controls the blur is used for the greyscale fade in.

This probably isn't totally optimal - I'm sure theres a better way to setup the array of sample points, but I can't figure out how to do that in GLSL. It might be a good idea to remove the two sin() calls too, either by putting it in a texture or subdividing into lots of polys and doing it per-vertex. I'm also biasing the weight in the shader where I'd be better of doing that per-vertex too. On slower systems a version with less samples for the blur would help a lot.

Still, even without those possible optimisations it runs pretty damn fast, and gives nice results too. [grin]

Thanks a bunch for that info ;-).

Thanks a bunch for that info ;-).

There's a page on the colour weightings (and other greyscale methods) used by GIMP here.

I haven't done any shader work so maybe this is obvious, but is there a reason you multiply by "divisor" within the for loop instead of doing it once afterwards? If this does work, does it have any noticable effect on the shader's speed?

Hey dude, just found your blog, awesome work dude.

neato :)

i'm working on a space-type game, and explosions are the last bit i need to produce.. would you be able to post the fragment code from your ripple distortion? i've just recently come to terms with the sine function, and my mind still doesn't wrap around it quick enough to figure out a distortion effect yet.

is a youtube link to a video on my project if you're interested.

## Create an account

Register a new account