Jump to content
  • Advertisement
Sign in to follow this  

SSGI round 2

This topic is 3349 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone! Quite some time ago i posted here a SSAO shader with color bleeding that got some attention but unfortunately many people had problems with it, because it was slow, hard to understand and was impractical for games. That shader used 3 buffers: depth, color, normals, and had trig functions and normalizations everywhere (that by the way were not needed :P). I´ve been working on a simpler shader that can be used in games. The color bleeding is not very accurate but it looks ok to me. I have nicknamed it Gauss SSGI. I hope you find it useful. You can use it any way you like. :) INFO: Screenshots: Fragment Shader:
uniform sampler2D som;  // Depth texture  
uniform sampler2D rand; // Random texture 
uniform sampler2D color; // Color texture 
uniform vec2 camerarange = vec2(1.0, 1024.0);
   float pw = 1.0/800.0*0.5; 
   float ph = 1.0/600.0*0.5;  

   float readDepth(in vec2 coord)  
     if (coord.x<0||coord.y<0) return 1.0;
      float nearZ = camerarange.x;  
      float farZ =camerarange.y;  
      float posZ = texture2D(som, coord).x;   
      return (2.0 * nearZ) / (nearZ + farZ - posZ * (farZ - nearZ));  

   vec3 readColor(in vec2 coord)  
     return texture2D(color, coord).xyz;  

   float compareDepths(in float depth1, in float depth2)  
     float gauss = 0.0; 
     float diff = (depth1 - depth2)*100.0; //depth difference (0-100)
     float gdisplace = 0.2; //gauss bell center
     float garea = 3.0; //gauss bell width

     //reduce left bell width to avoid self-shadowing
     if (diff<gdisplace) garea = 0.2; 

     gauss = pow(2.7182,-2*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));

     return max(0.2,gauss);  

   vec3 calAO(float depth,float dw, float dh, inout float ao)  
     float temp = 0;
     vec3 bleed = vec3(0.0,0.0,0.0);
     float coordw = gl_TexCoord[0].x + dw/depth;
     float coordh = gl_TexCoord[0].y + dh/depth;

     if (coordw  < 1.0 && coordw  > 0.0 && coordh < 1.0 && coordh  > 0.0){

     	vec2 coord = vec2(coordw , coordh);
     	temp = compareDepths(depth, readDepth(coord)); 
        bleed = readColor(coord); 
     ao += temp;
     return temp*bleed;  
   void main(void)  
     //randomization texture:
     vec2 fres = vec2(20,20);
     vec3 random = texture2D(rand, gl_TexCoord[0].st*fres.xy);
     random = random*2.0-vec3(1.0);

     //initialize stuff:
     float depth = readDepth(gl_TexCoord[0]);
     vec3 gi = vec3(0.0,0.0,0.0);  
     float ao = 0.0;

     for(int i=0; i<8; ++i) 
       //calculate color bleeding and ao:
       gi += calAO(depth,  pw, ph,ao);  
       gi += calAO(depth,  pw, -ph,ao);  
       gi += calAO(depth,  -pw, ph,ao);  
       gi += calAO(depth,  -pw, -ph,ao); 
       //sample jittering:
       pw += random.x*0.0005;
       ph += random.y*0.0005;

       //increase sampling area:
       pw *= 1.4;  
       ph *= 1.4;    

     //final values, some adjusting:
     vec3 finalAO = vec3(1.0-(ao/32.0));
     vec3 finalGI = (gi/32)*0.6;

     gl_FragColor = vec4(readColor(gl_TexCoord[0])*finalAO+finalGI,1.0);  

Vertex Shader: standard stuff, no ssao code in there. Pros: -It´s faster than other methods because it doesn´t use a normals buffer. -It does not suffer from the "flat syndrome". -Does not need blurring if a good randomization texture is used. -It´s simple to understand. Cons: -It is slower than traditional SSAO. -It suffers from halos (it has a parameter that helps reducing them). EXPLANATION: The "new" stuff is in the depth comparison function. There i take the depth difference and i plug it in two different gauss functions. The first one has a more pronounced shape to avoid self-occlusion issues and the second one is softer. These two functions map the depths directly to an occlusion value. Then i just multiply that value with a blurred version of the color buffer to get the color bleeding. The SSAO term together with the color bleeding fake some sort of "local" GI. You will also need a random-colors texture to randomize the sampling, tomorrow i will post the one i´m using since it gives pretty good results. [Edited by - ArKano22 on October 16, 2009 10:01:57 AM]

Share this post

Link to post
Share on other sites
Thanks!here´s a comparison between using it and not.

Nvidia 8800 GT (Core2 Quad)
Sponza Atrium with 3 phong lights and 4 low poly models (no SSGI): 60 fps
Same scene with SSGI (24 samples): 50-54 fps
Same scene with SSGI (32 samples): 45-49 fps

There are some things you could probably do to increase performace, for example replacing the randomization texture with a function to save a few texture fetches.
I still have to test it against another SSAO techniques but it has to be slower because of the 3 buffers needed instead of 1 or 2.

btw here´s the texture i use for random sampling:

EDIT: I forgot to mention that the input depth buffer doesn´t have to be linear. If you do use a linearized buffer, remove the math in readDepth() and leave only
"return texture2D(som, coord).x;".

Share this post

Link to post
Share on other sites
Good work! It looks pretty good and seems pretty fast. :)

I coded a little test for it in my code and this is what I came up with:



There seems to be a big problem with both the SSAO and the GI in my code. Not sure what it is yet but I'll try to figure it out! :D


[Edited by - toasterthegamer on October 16, 2009 4:05:46 PM]

Share this post

Link to post
Share on other sites
Hi Toaster

It looks like your sampling radius is very small. You should check a small bit of code at the beginning that defines the sampling "step size":

float pw = 1.0/800.0*0.5;
float ph = 1.0/600.0*0.5;

the 800 and 600 should be the width and height of your resolution. Also make sure that your depth buffer is not linear if you´re using the same code i posted :).

Share this post

Link to post
Share on other sites
Yeah my res is 800, 600 so I didn't change that at all. I'm using a normal depth buffer for the depth its just:

mul(In.Position, WorldSpaceMatrix).z;

I changed your depth code so it only outputs the .z but I still think its my depth to be honest but maybe something weird got messed up when I converted the GLSL to HLSL. Here's the code if you want to take a look at it:


Not much is different from the original code. I know its not very optimized in some parts like the multiple variable calls is probably slowing it down. I just want to get it working first and then I can optimize it.


Share this post

Link to post
Share on other sites
In those two lines i mentioned earlier, try to change the 0.5 to something like 4.5 and see if that makes a difference. I still think it´s the radius since i get results like yours when i reduce it.

Share this post

Link to post
Share on other sites
I pasted Toaster's HLSL conversion code into my game and it works.

Here are some screenshots of your "Gauss SSGI" dropped into my game [ this map/level is for training so it's pretty simple ] ...I'm impressed with the results, especially considering it doesn't use the normal from the surface, there is some halo effects, etc. But overall, I think it looks good.

I will keep tweaking it, and report back, these screens are just a few mins of work dropping it into my pipeline to see how it'd look. This obviously isn't the best example of the color bleeding since it's a pretty dull colored terrain scene...

Ignore framerates I have many things going on the background, as well as in-game, it has full Havok physics, and is doing every aspect of the game [ I just only output the SSGI element to the screen, I can reuse the depth value I generate for my DOF effect ] . It runs at 60+ 800x600 when I disable the color bleeding sampling [ since its hardly visible it seems on this dull colored terrain scene ].

Screens w/color bleeding enabled

[edit] here is a screen w/color bleeding disabled -

Keep up the good work!

- Dan

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!