A simple, but effective god ray shader can be implemented using simple ray-marching.
There are a few common approaches, but generally, you can either implement something that for each pixel, walks towards the centre of the lightsource, adding colours as it goes.
The idea is that you run the shader on a surface without a background, so that as you the ray marches across "empty" spots or white spots, you accumulate much more brightness than if you walk over the scene.
Depending on whether you want colour bleeding or not, you can simply just sample the alpha channel (alpha 0 = fully white, alpha 1 = black - no contribution).
Bit of simple pseudo code would look something like this:
Code:
uniform vec2 lightpos; // screenspace position of lightsource
#define STEPS 24
...
// Calculate vector towards light
vec2 v_towards_light = (lightpos - v_vTexcoord)/STEPS ; // Get the unit vector that will reach the centre of our light source in the given number of steps
vec4 accumulated_colour = vec4(0.0,0.0,0.0,0.0);
vec2 sample_coord = v_vtexcoord; // Our current sample coordinate
for(int i=0; i < STEPS ; i++){
// Sample at current location, then step closer to the light
vec4 sample = texture2D(gm_BaseTexture, sample_coord);
accumulated_colour += sample.rgb*(1.0-sample.a); // Weight sample based on inverse alpha -- We want the gaps in the background to be "bright spots"
sample_coord += v_towards_light;
}
gl_FragColor = accumulated_colour*0.5 / float(SAMPLES); // Need to multiply the end result by some factor to reduce brightness. You would need to play around with this. (Also weighted by sample count)
A more advanced version could weight the samples based on how close they are to the light -- you can basically keep on throwing in features like this to adjust the reuslt
Code:
uniform vec2 lightpos; // screenspace position of lightsource
#define STEPS 24
...
// Calculate vector towards light
vec2 v_towards_light = (lightpos - v_vTexcoord)/STEPS ; // Get the unit vector that will reach the centre of our light source in the given number of steps
vec4 accumulated_colour = vec4(0.0f,0.0f,0.0f,0.0f);
vec2 sample_coord = v_vtexcoord; // Our current sample coordinate
float intensity = 0.0f;
for(int i=0; i < STEPS ; i++){
// Increase sample contribution
intensity += 1.0f/float(STEPS);
// Sample at current location, then step closer to the light
vec4 sample = texture2D(gm_BaseTexture, sample_coord);
accumulated_colour += sample.rgb*(1.0f-sample.a);
sample_coord += v_towards_light;
}
gl_FragColor = accumulated_colour*0.5 / float(SAMPLES); // Need to multiply the end result by some factor to reduce brightness. You would nede to play around with this
If we wanted a version with colour bleeding, you could adjust the accumulation process to allow partial colour in:
Code:
uniform vec2 lightpos; // screenspace position of lightsource
#define STEPS 24
...
// Calculate vector towards light
vec2 v_towards_light = (lightpos - v_vTexcoord)/STEPS ; // Get the unit vector that will reach the centre of our light source in the given number of steps
vec4 accumulated_colour = vec4(0.0f,0.0f,0.0f,0.0f);
vec2 sample_coord = v_vtexcoord; // Our current sample coordinate
float intensity = 0.0f;
for(int i=0; i < STEPS ; i++){
// Increase sample contribution
intensity += 1.0f/float(STEPS);
// Sample at current location, then step closer to the light
vec4 sample = texture2D(gm_BaseTexture, sample_coord);
accumulated_colour += sample.rgb*(1.5f-sample.a);
sample_coord += v_towards_light;
}
gl_FragColor = accumulated_colour*0.5 / float(SAMPLES); // Need to multiply the end result by some factor to reduce brightness. You would nede to play around with this
This is the sort of thing where you really have to play around with all of your inputs and your process until you get the desired result. Its a relatively simple concept, but there are lots of small details you can just to change the softness/hardness, colours, brightness, intensity etc; of the result. The only key performance indicator is that the greater the value of SAMPLES, the higher quality the result, but the worse the performance.