Screen Space Global Illumination / Radiosity - 2d filter

THESE IMAGES ARE OUTDATED, OFFICIAL THREAD HERE

I have been working on this nice Global illumination filter wich is based on a VPL-ish approach for a couple of days and it was all going quite smoothly. I even got some nice rsults to show for it!
No SSGI:



With SSGI:

As you can see it gives off a pretty neat effect but… i was looking at it and i noticed that nothing was getting any bounced light from the coloured walls, wich seemed a bit odd at first.
I tested some things out in my code and it turns out that the filter is only gathering information from the 4 pixels in the exact corners of the rendered image, wich strikes me as VERY FUCKING ODD.
I am trying to fix this but i haven’t had any results so far. I will post in this thread as soon as i figure out and fix what’s wrong but, in the meantime you can try and fix the filter yourself, here’s the code:

uniform sampler2D bgl_RenderedTexture;uniform sampler2D bgl_DepthTexture;
uniform float bgl_RenderedTextureWidth;
uniform float bgl_RenderedTextureHeight;
float width = bgl_RenderedTextureWidth;
float height = bgl_RenderedTextureHeight;
vec2 texCoord = gl_TexCoord[0].st;
vec4 direct = vec4(texture2D(bgl_RenderedTexture,texCoord));
vec4 bounced = vec4(0,0,0,1);
vec4 sample = vec4(0,0,0,1);
/* martin start */
vec2 canCoord = gl_TexCoord[0].st;
float aspectratio = 0.75;
float znear = 0.1; //camera clipping start
float zfar = 50.0; //camera clipping end
float getDepth(vec2 coord){
    float zdepth = texture2D(bgl_DepthTexture,coord).y;
    return -zfar * znear / (zdepth * (zfar - znear) - zfar);
}
vec3 getViewPosition(vec2 coord, vec2 cancoord){
    vec3 pos;
    pos =  vec3((cancoord.s*2.0-1.0),(cancoord.t*2.0-1.0)/aspectratio ,1.0);
    return (pos*getDepth(coord));
}
vec3 getViewNormal(vec2 coord, vec2 cancoord){
    vec3 p1 = getViewPosition(coord+vec2(1.0/width,0.0), cancoord+vec2(1.0/width,0.0)).xyz;
    vec3 p2 = getViewPosition(coord+vec2(0.0,1.0/height), cancoord+vec2(0.0,1.0/height)).xyz;
    vec3 dx = p1-getViewPosition(coord,cancoord);
    vec3 dy = p2-getViewPosition(coord,cancoord); 
    return normalize(cross( dx , dy ));
}
/* martin end */
void main(void){
    vec3 viewPos = getViewPosition(texCoord,canCoord);
    vec3 viewNormal = getViewNormal(texCoord,canCoord);
    vec3 lightDir = vec3(0,0,0);
    vec3 viewPos2 = vec3(0,0,0);
    float amount = 0;
    vec2 screenCoord = vec2(0,0);
    while(screenCoord.y < height){
        while(screenCoord.x < width){
            if(screenCoord.x != texCoord.x && screenCoord.y != texCoord.y){
                viewPos2 = getViewPosition(screenCoord,canCoord);
                lightDir = viewPos - viewPos2;
                amount = dot(lightDir,viewNormal)/(length(lightDir)*length(viewNormal));
                sample = texture2D(bgl_RenderedTexture,screenCoord) * amount;
                bounced += sample;
            }
            screenCoord.x += width/30;
        }
        screenCoord.y += height / 40;
    }
    bounced = bounced / (30*40/8);
    gl_FragColor = direct + bounced;
}

PD: some of these things are based on Martin Upitis’ deffered shading filter

UPDATE:
I just figured out why samples were getting bunched up in the corners. it tuns out that the image coordinates range goes from 0 to 1 and not from 0 to the width of the rendered image in pixels.
Now light is no longer getting sampled exclusively from the corners but it seems like i messed something else up because even though i got samples to speread across the image in 10% intervals lighting is only being sampled from the pixels in the bottom most row of the rendered image. Also it seems like i messed up how i am calculating the light falloff by angle cause things are looking very off.

no image but here is the updated code:

uniform sampler2D bgl_RenderedTexture;uniform sampler2D bgl_DepthTexture;
uniform float bgl_RenderedTextureWidth;
uniform float bgl_RenderedTextureHeight;


float width = bgl_RenderedTextureWidth;
float height = bgl_RenderedTextureHeight;


vec2 texCoord = gl_TexCoord[0].st;
vec2 canCoord = gl_TexCoord[0].st;


float aspectratio = 0.75;


float znear = 0.1; //camera clipping start
float zfar = 50.0; //camera clipping end


float getDepth(vec2 coord){
	float zdepth = texture2D(bgl_DepthTexture,coord).y;
	return -zfar * znear / (zdepth * (zfar - znear) - zfar);
}


vec3 getViewPosition(vec2 coord, vec2 cancoord){
	vec3 pos;
	pos =  vec3((cancoord.s*2.0-1.0),(cancoord.t*2.0-1.0)/aspectratio ,1.0);
	return (pos*getDepth(coord));
}


vec3 getViewNormal(vec2 coord, vec2 cancoord){
	vec3 p1 = getViewPosition(coord+vec2(1.0/width,0.0), cancoord+vec2(1.0/width,0.0)).xyz;
	vec3 p2 = getViewPosition(coord+vec2(0.0,1.0/height), cancoord+vec2(0.0,1.0/height)).xyz;
	vec3 dx = p1-getViewPosition(coord,cancoord);
	vec3 dy = p2-getViewPosition(coord,cancoord); 
	return normalize(cross( dx , dy ));
}


vec4 lightSample(vec2 coord,vec2 canCoord){
    vec3 viewNormal = getViewNormal(canCoord, canCoord);
    vec3 lightDir =  getViewPosition(canCoord, canCoord) - getViewPosition(coord, canCoord);
    float amount = dot(lightDir,viewNormal) * (1/length(lightDir));
    vec4 sample = texture2D(bgl_RenderedTexture, coord) * amount;
    return sample;
}


void main(void){
    
    vec4 direct = texture2D(bgl_RenderedTexture,texCoord);
    vec4 indirect = vec4(0.0,0.0,0.0,1.0);
    
	vec3 viewPos = getViewPosition(texCoord,canCoord);
	vec3 viewNormal = getViewNormal(texCoord,canCoord);


    vec2 screenCoord = vec2(0.0,0.0);
    
    while(screenCoord.y <= 1.0){
        while(screenCoord.x <= 1.0){
                indirect = indirect + lightSample(screenCoord, texCoord);
            screenCoord.x += 0.1;
        }
        screenCoord.y += 0.1;
    }
    
    vec2 dummyb = vec2(0.2,0.4);
    vec3 dummy = viewPos - getViewPosition(dummyb, canCoord);
    
    gl_FragColor = vec4(dummy.xyz,0);
}

UPDATE 2: I managed to fix the angle falloff. It was a matter of replacing the parameters that i was passing to a function inside of light

before:
vec3 lightDir = getViewPosition(canCoord, canCoord) - getViewPosition(coord, canCoord);

after:

vec3 lightDir =  getViewPosition(canCoord, canCoord) - getViewPosition(coord, coord);

Because the function was made by Martin Upitis i didn’t know how to use it and since he was always passing it two different variables (wich i didn’t notice that they always had equal value) as parameters in his code i didn’t realize that i was supposed to pass the same variable as both parameters to get apropiate results (first variable is the is x and y and the second variable corrects for z perspective and should be the same than the first one to refer to a specific position on the screen)

Here is an image that shows the angle falloff perfectly:
[ATTACH=CONFIG]464546[/ATTACH]

And here it is again but only the indirect pass:
[ATTACH=CONFIG]464547[/ATTACH]
Now all that’s left is figuring out why i can’t iterate through rows and then this filter will be ready for shipping.

UPDATE 3: Earlier i said that the algorithm not iterating through the y values did not have anything to do with the nested loops order and that was the case back then. But it seems like i did something and now it just refuses to loop through the outter loop.

UPDATE 4: Nevermind update 3, i just figured out what was preventing it from iterating. I won’t say what it was because it would be too embarrasing so figure it out by yourself if you wanna have a good laugh.

I thought it was working fine (and it was, for the most part) but now, for some reason now the bounced pass is getting substracted instead of added. but this only happens in very specific circumstances that i have not been able to identify.

Here is a nice image:



Some tweaking is still needed because it doesn’t look right

Here is an image of the bug:



In this case it was not very noticeable and it looks kinda nice, actually. But it gets much worse, i just didn’t think of taking a screenshot when it happened but it was pretty bad (the back wall was completely purple and the spheres had weird shading on them)…

As a bonus, here is another nice image:


I really like this image in particular, it really higlights how the filter works.

Very nice! Can’t wait to try this with a few scenes I have in mind.

Sounds good! I’ll post the updated filter in a bit.

I’ll try to upload a 1024*768 screenshot later but rn i am not at my main pc so idk if an intel graphics machine will be able to handle the shader at over HD resolution.

UPDATE 5: Fully functioning and glitchless

After fixing a few stupid bugw i think this is completely finished and ready to go into the wild.

Here are a couple of images at highest resolution i could get (because apparently printscreen doesn’t work on the fullscreen bge player), the first one is what you will get if you just use the filter as it is on this page, to get results like on the second image you can just uncomment the commented line on lightSample()(also i darkened the walls for the second image):



I would put a blend file up for download but i am too lazy, instead i will link to this video that explains how to add 2d filters to your game.

Here is the filter itself:

//Screen-Space Global Illumination post process filter by Sebastian Mestre// this section of code was written by Martin Upitis


uniform sampler2D bgl_RenderedTexture;
uniform sampler2D bgl_DepthTexture;
uniform float bgl_RenderedTextureWidth;
uniform float bgl_RenderedTextureHeight;


float width = bgl_RenderedTextureWidth;
float height = bgl_RenderedTextureHeight;


vec2 canCoord = gl_TexCoord[0].st;


// width/height , in this case it is set up for 600*800
float aspectratio = 0.75; 


//these two MUST match your camera settings
float znear = 0.1; //camera clipping start
float zfar = 50.0; //camera clipping end


float getDepth(vec2 coord){
    float zdepth = texture2D(bgl_DepthTexture,coord).y;
    return -zfar * znear / (zdepth * (zfar - znear) - zfar);
}


vec3 getViewPosition(vec2 coord, vec2 cancoord){
    vec3 pos;
    pos =  vec3((cancoord.s*2.0-1.0),(cancoord.t*2.0-1.0)/aspectratio ,1.0);
    return (pos*getDepth(coord));
}


vec3 getViewNormal(vec2 coord, vec2 cancoord){
    vec3 p1 = getViewPosition(coord+vec2(1.0/width,0.0), cancoord+vec2(1.0/width,0.0)).xyz;
    vec3 p2 = getViewPosition(coord+vec2(0.0,1.0/height), cancoord+vec2(0.0,1.0/height)).xyz;
    vec3 dx = p1-getViewPosition(coord,cancoord);
    vec3 dy = p2-getViewPosition(coord,cancoord); 
    return normalize(cross( dx , dy ));
}


//this is the end of the code written by Martin Upitis
//anything from here on was made by Sebastian Mestre


vec4 lightSample(vec2 coord,vec2 canCoord){
    vec3 viewNormal = getViewNormal(canCoord, canCoord);
    vec3 lightDir =  normalize(getViewPosition(coord, coord) - getViewPosition(canCoord, canCoord));
    float amount = abs(dot(lightDir, viewNormal));
    vec4 color = texture2D(bgl_RenderedTexture, coord);
    vec4 sample = color * amount;
    //use this one to make the bounced lights more powerful
    //vec4 sample = color * amount * amount * 4 ;
    return sample;
}


void main(void){
    //pixels between samples
    //float hstep = 0.05;
    //float vstep = 0.1;
    
    vec4 direct = texture2D(bgl_RenderedTexture,canCoord);
    vec4 indirect = vec4(0.0,0.0,0.0,1.0);
    
    vec3 viewPos = getViewPosition(canCoord,canCoord);
    vec3 viewNormal = getViewNormal(canCoord,canCoord);


    //this should be vec2(hstep,vstep) but blender crashes if i do this using variables
    vec2 screenCoord = vec2(0.1,0.1); 
    
    //all of these should be using hstep and vstep instead of hard coded numbers but it doesnt work for me, maybe you can fix it
    while(screenCoord.y <= 0.9){
        screenCoord.x = 0.1;
        while(screenCoord.x <= 0.9){
            indirect += lightSample(screenCoord,canCoord);
            screenCoord.x += 0.05;
        }
        screenCoord.y += 0.1;
    }
    
    //last term should be close to 1/(amount of samples)
    gl_FragColor = direct + indirect * 0.01; 
}

I tested it in upbge, it gives some nice brightness and low fps. :cool:
Image-> http://pasteall.org/pic/index.php?id=110291

Cool! You might want to try the latest version of the filter, available here. I would post more elaborate screenshots but i don’t have access to my main pc atm (not at home cuz of holidays)… But it’d be nice if someone could help me by taking and sending me some screenshots of an actual scene.