SSAO [Screen Space Ambient Occlusion] Demo + Source

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Ok that seemed to work, I now see what appears to be the correct ray. I should have known the last colors were wrong. This makes sense, black is -1x,-1y (bottom left corner) and yellow is +1x,+1y (upper right corner).

Image

The effect is still off, but I think I have identified the problem. I added the divide by w to the uv calculations (good eye), but it still seems wrong, check out the following test (which should calculate the uv coord for the primary texel)...

Code: Select all

    // view-space position
    //this seems to be accurate now
    float4 D = computeViewPos(inRay, geom.w);
    // view-space normals
    float3 N = geom.xyz;
    
		//but this is all wrong...
		float4 nuv = mul(proj, float4(D.xyz,1));
        nuv.xy = ( (nuv.xy / nuv.w) + 1.0f ) / 2.0f;
		nuv.y = 1-nuv.y;
		
		return tex2D(depthMap, nuv.xy);
results in -

Image

...which is just 5 different kinds of messed up.

Can you see anything wrong with the way im taking a view space position, and calculating a uv from it?

*onlything I can think of its that the projection matrix gets changed during a compositor render. Should I try manually passing in the main cameras projection matrix? Right now I am just doing a auto param in the material...

Code: Select all

param_named_auto proj projection_matrix
...which I suppose may or may not be right?
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Hm. Can I see the exact code you use to store the depth? Also, try manually passing the camera's projection matrix, just to be safe (when the compositor quad renders, the projection matrix might get messed up or something).

This is how I pass my projection matrix so all you need to do is divide by .w, nothing else:

Code: Select all

static const Ogre::Matrix4 CLIP_SPACE_TO_IMAGE_SPACE(
        0.5,    0,    0,  0.5,
        0,   -0.5,    0,  0.5,
        0,      0,    1,    0,
        0,      0,    0,    1);
if (params->_findNamedConstantDefinition("pMat"))
     params->setNamedConstant(
        "pMat",
        CLIP_SPACE_TO_IMAGE_SPACE * // automatic scale/bias
        _renderer.camera()->getProjectionMatrixWithRSDepth());
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Gah one step forward one step back. It looks like the projection matrix WAS wrong, so I manually set it based on the main camera...

Code: Select all

	mSSAOParams->setNamedConstant("proj",
		mGraphicsCore.camera->getProjectionMatrixWithRSDepth() );
Now the uv calculations seem accurate, and the final effect seems right at a distance, but when you pull in close there are new errors...

Image

Here is how I am generatign my depth...

Code: Select all

	//from vertex shader
	outPosView = mul( worldView, inPos );


	...

	//from fragment shader
	outColor1.a = length(inPosView.xyz);
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Hm.

:|

Well, time for hardcore debugging. Which would be a lot easier in IRC (#ogre3d @ freenode).

Output the view-space position to verify it, and the normals after that. What units are you using for the world? Inches? Centimeters? Meters?
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Using 1unit = 1 meter.

I am now using your matrix and code for calculating the uvs. It seems to work exactly the same.

However I still get the error shown in the last screen shot. Its strange, at some distances it looks like everything is working, then when you pull in its like the effect is getting clipped by the near or far plane...

Gah I am about ready to just say screw the compositor and use your code...
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Zeal wrote: Gah I am about ready to just say screw the compositor and use your code...
This is why I found Ogre's compositors extremely flaky - they're useful for scripts and post-processing, but if you need a simple "render a full screen quad with said shader" then there's loads of things that need to be done.

Hold on, let me open source my new sseffect code. It's more robust.
morfiel
Gnoblar
Posts: 17
Joined: Tue Feb 14, 2006 11:15 pm
Contact:

Full ScreenQuad in OpenGL

Post by morfiel »

nullsquared wrote:
aguru wrote:I was wondering how far exactly opengl support has come with this thing. Did you get this beauty to work with a non d3d renderer, null?
TBH, no, I haven't. The biggest problem seems to be the fact that I just can't get OpenGL to render my screen-space quad, no matter what I do... and I can't quite figure out why. If anyone gets OpenGL to render the full screen quad correctly (regardless of the actual SSAO), it'd be nice to hear.
Hi Nullsquared,
I try to get your stuff working for some days now and I think I found the OpenGL-problem with your quad-renderer. Its quite simple: GL uses a different winding order than D3D, so you have to draw the Quad the other way around as long as backface culling is enabled. Try the following code and it should work with GL:

Code: Select all

    quad->begin("Chuck Norris", Ogre::RenderOperation::OT_TRIANGLE_LIST); {
        //! store frustum corner in normal attribute
        //! and go anti clockwise

        // top-left
        quad->position(Ogre::Vector3(-1, 1, 0));
        quad->textureCoord(Ogre::Vector2(0, 1));
        quad->normal(CORNERS[5]);

        // bottom-left
        quad->position(Ogre::Vector3(-1, -1, 0));
        quad->textureCoord(Ogre::Vector2(0, 0));
        quad->normal(CORNERS[6]);

        // bottom-right
        quad->position(Ogre::Vector3(1, -1, 0));
        quad->textureCoord(Ogre::Vector2(1, 0));
        quad->normal(CORNERS[7]);

        // top-right
        quad->position(Ogre::Vector3(1, 1, 0));
        quad->textureCoord(Ogre::Vector2(1, 1));
        quad->normal(CORNERS[4]);

        // we put the vertices in clockwise,
        // so just start at 3 and go to 0
        quad->quad(3, 2, 1, 0);
    } quad->end();

User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Interesting find!

@ Zeal: Here's the new sseffect code: http://www.ogre3d.org/wiki/index.php/Sc ... ce_Effects
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Haha! You know what I think it was all along? The background for my depth texture was set to 0, so the ssao effect assumed it was a 'super close object', which caused any object set infront of the black backdrop to have those nasty shadow artifacts.

I put a 'backdrop object' in the scene to capture background depth, and I think its working...

Image

I am still trying to get used to some of the 'natural' artifacts of ssao. I mean I know that as a screen space effect, the shadows are going to move slightly as you move the camera... but I think we are in business!

How do you manually set the 'background' depth in your depth texture? Cause leaving at 0 causes real problems with ssao!

*and one other question. Whats the word on normal maps? I was told we cant use them (which means we have to render a SECOND normal map in addition to our gbuffer? ouch). Just for fun I turned normal mapping on, and it LOOKED ok. The only noticeable artifact I saw was what looked like a bright specular highlight in the middle of the screen, hard to describe...

*the normals seem inverted too..

*here is my cube with a normal map...

Image

Notice the 'white spot' I circled in red. I dont think this has anything to do with the normal map, as you can see this same artifact in your demo too (look straight at a flat wall up close, and move the camera). It seems to only happen when the camera is perpendicular to a large flat polygon. Is this a known issue with ssao?
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

You can store normal maps and compute the (lower-quality) normal from the depth. Did I include a computeViewNorm() function in the demo? It takes a view-space position and gives you a view-space normal, *usually* good enough for SSAO. So now your gbuffer can store normal maps without affecting the SSAO.

For the background, it's simply a colour that you send to RenderSystem::clearFrameBuffer(). Check my wiki article.
User avatar
xadhoom
Minaton
Posts: 973
Joined: Fri Dec 28, 2007 4:35 pm
Location: Germany
x 1

Post by xadhoom »

nullsquared wrote:Interesting find!

@ Zeal: Here's the new sseffect code: http://www.ogre3d.org/wiki/index.php/Sc ... ce_Effects
Hi Null!

Do you think your SSE class could/should be deployed as a patch to the trunk?
Maybe as a modification of Compositors or as you already implemented as
modul besides the compositor. If a Compositor currently is not able to just
perform a shader to the screen (on a quad) this seems to be a very good
enhancement!
BTW: You already showed that this seems to be a very good enhancement. ;-)

EDIT:
Please correct me if I wrote something wrong here:
http://www.ogre3d.org/phpBB2/viewtopic. ... &start=975

Thanks
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

xadhoom wrote: Do you think your SSE class could/should be deployed as a patch to the trunk?
Maybe as a modification of Compositors or as you already implemented as
modul besides the compositor. If a Compositor currently is not able to just
perform a shader to the screen (on a quad) this seems to be a very good
enhancement!
BTW: You already showed that this seems to be a very good enhancement. ;-)
Well, no, Ogre's compositors are just fine. And they're a great solution for scripted post processing that Just Works with Ogre.

My deal was that I wanted to very simply instantiate an effect, tell it what kind of texture to use and what pass to use (no full-on materials, just a given pass with maybe some shaders), and then just call update() to have the effect computed. This is not exactly a post-processing solution (though it can be used that way, by using an intermediate sseffect for rendering the separate parts of the chain to).

With compositors, I believe much the same can be done. But for the life of me I could not figure out where compositors actually come in and do all the dirty work. Viewport::update() and SceneManager::_renderScene() were very obvious and are very easy to make use of manually, unfortunately, I did not find compositors to be of the same use.

And then there's material usage - I wanted to grab my effect's material/pass, edit some shader parameters, and let it go render again (which is actually done in subclasses of sseffects, to make it more encapsulated):

Code: Select all

sseffectsManager effects;
effects += sseffectPtr(new ssao(renderer)), "ssao";
effects["ssao"]->create("ssao_texture", renderer->width(), renderer->height(), Ogre::PF_R8G8B8);

Ogre::Pass *pass = effects["ssao"]->getPass();
pass->getFragmentProgramParameters()->setNamedConstant("radius", 0.05");
With compositors, there's no single-liner. Either you use listeners, or you somehow fetch the copied material instance, and so on.
morfiel
Gnoblar
Posts: 17
Joined: Tue Feb 14, 2006 11:15 pm
Contact:

help using OpenGL / outdoor scene

Post by morfiel »

Ok, I am currently facing some problems getting this nice stuff to work.

I applied the geometry shader to my geometry (not the sky yet, so please ignore that) and the result looks good to me:

Image

Note that I did not apply a special sky shader for the geometry pass yet, but it shouldnt matter. I pass the ray to the ssao pass and it looks good:

Image

When I output the depth-parth value of the geometry map it becomes clear that it is very high due to scene scaling, but when I scale it down by a factor of 256. it looks reasonable as well:

Image

But then the final results (with the /256 scale) looks somewhat weired:

Image

Without the scale I just get a white image out of the ps. Any suggestions of what might be wrong?

Have a nice day and thanks in advance,
Tim
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

What size units are you using for the world?

Don't scale the depth itself, but fix the ZSCALE variable in the SSAO shader to be an accurate scale (the original ZSCALE was with meters, so if you're using inches, for example, you'll need to scale it up). Also, play with the RADIUS variable, that's in meters, as well.

Also - plain white might be correct occlusion. All I see is some terrain, and since SSAO is very local, you'll need to add some objects to actually see any occlusion.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

@morfiel

Your 'ray' texture looks wrong to me. Unless your uvs are reversed, black should be in the bottom right, and yellow should be in the top right. Remember black will send a ray -1,-1, and yellow +1,+1.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Zeal wrote:@morfiel

Your 'ray' texture looks wrong to me. Unless your uvs are reversed, black should be in the bottom right, and yellow should be in the top right. Remember black will send a ray -1,-1, and yellow +1,+1.
Oh, right, your X axis on the ray is flipped.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

I am noticing some artifacts, can you confirm if these are 'normal'?

Image

..in this first screen you can see a sphere infront of a cube. The bottom right cornder of the sphere seems 'off'. I think perhaps it is actually just a abrupt falloff (since the distance between the sphere edge and the ground becomes greater and greater). Is there anyway to soften this?

Image

In this second screenshot I have zoomed out so you can get an idea of the scene (here you can also see this abrupt fallof on the side of the cubes). But zoom in and there seems to be a new artifact...

Image

As you can see, when zoomed in close, you would expect a straight vertical line of shadowing, but instead you get this strange curve. Perhaps it has something to do with the depth (I am storing all my depth as 'length(worldSpacePos)', just like you suggest). I would be curious to see if you can reproduce this error in your application (just setup two cubes infront of each other and play around with the camer angle).

Also one other thing I noticed (which you can reproduce in the demo), if you move in close to the ogre head (a side angle seems to work best), and rotate the camera slowly, you can sometimes see pretty drastic 'pops' in the shadow. I know when new depth comes into the screen it will effect neighboring pixels, but this seems like one corner is effecting the shadowing half way across the screen. You may need to play around with the camera angle, but eventually you should see what I mean.

*for the 'shadow popping' here is a example (it may seem subtle in screenshot form, but its quite noticeable in practice).

Image

Focus on his ear, move the camera a HAIR to the right, and the shadowing of his ear changes quite a bit...

Image

The 'pop' seems to happen when the tip of his ear comes into view. I just dont see how that could effect the shadowing of points so far away...
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

For the sharp "falloff":

Code: Select all

const float MAX_DIFF = 2;
        const float NO_OCC = 4;
        occ += (ZD < ZSCALE * MAX_DIFF ? occlusion(ZD) : NO_OCC);
Remove that check there and simply do:

Code: Select all

occ += occlusion(ZD);
Technically, you'll always get halos with SSAO as it is now. The above check was added to remove the halos against far objects, but in my opinion it looks worse with the check than without the check, and simply living some some (rather slight if well-tweaked) halos.

As for the other artifacts - worldSpacePos? Did you mean viewSpacePos? Not world space ;). Also, are you taking the length in the vertex shader or in the pixel shader? Make sure you're doing it in the pixel shader (pass the 3-component position down from the vs to the ps and do the length() there).

And the ear "popping". Honestly, never noticed it. SSAO is not meant to be slow "clear" the whole time, it's supposed to be a subtle ambient coefficient, where there's other light affecting the scene besides ambient light.

See this GIF:
Image
Note that the SSAO is very slight, and that's with ambient-only lighting (with the removed depth check as I mentioned). Once you start adding normal lights then the SSAO artifacts are all forgetten, but yet it contributes to the final visuals.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Code: Select all

Remove that check there and simply do: 
Code: 

occ += occlusion(ZD);  
Cool that got rid of the hard falloff AND that 'curve' error. Of course now objects can 'cast shadows' on each other from a mile away though... I wonder if there is a way to tweak that conditional line so it just 'sucks less' heh.
worldSpacePos? Did you mean viewSpacePos?
Doh, yes, I meant viewspace. And I am doing the length() in the fragment shader.

As for the shadow poping, I notice it REALLY bad on the athena model. You should look into it. When I look at the athena model head on, and rotate left and right, I get HORRIBLE shadows when her spear goes in/out of view. Even WITH the conditional falloff line enabled!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Zeal wrote:

Code: Select all

Remove that check there and simply do: 
Code: 

occ += occlusion(ZD);  
Cool that got rid of the hard falloff AND that 'curve' error. Of course now objects can 'cast shadows' on each other from a mile away though... I wonder if there is a way to tweak that conditional line so it just 'sucks less' heh.
Lots of tweaking to do.
worldSpacePos? Did you mean viewSpacePos?
Doh, yes, I meant viewspace. And I am doing the length() in the fragment shader.

As for the shadow poping, I notice it REALLY bad on the athena model. You should look into it. When I look at the athena model head on, and rotate left and right, I get HORRIBLE shadows when her spear goes in/out of view. Even WITH the conditional falloff line enabled!
Again, all tweaking. SSAO is all just a big hack - an approximation of ambient occlusion, which in itself is just an approximation for global illumination and what-not. The point is not to get it to look perfect, but to get it to subtly enhance the scene.
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

The point is not to get it to look perfect, but to get it to subtly enhance the scene.
Oh I agree, I am just nitpicking for the sake of nitpicking. I have very acceptable results now (except for that 'shadow poping', but its nothing I cant live with for the time being).

It deserves saying again - damn fine work nully!
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

For the popping, TBH with you I haven't noticed it myself, and don't know what could be causing it. I used to test my SSAO a lot with the athena model, and I didn't notice any popping :|

Something to check, are you clamping the depth texture? That is, tex_address_mode clamp?
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Clamping is on. Im telling yas im not crazy! Use your demo, and replace the ogrehead mesh with the athene.mesh.

Before pop...

Image

After rotating the camera just ONE pixel...

Image

Thats a pretty big difference when just one collum of new pixels come into view.

*here is the pop side by side, zoomed in so you can see it better...

Image

You can also get a nasty 'shimmer' effect if you look at her head on, and rotate left and right. Its like her spear is sending a shadow up and down her body.

*note that you will only see this pop if you are zoomed in close, and only at certain angles.
User avatar
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 11

Post by nullsquared »

Must be because of the new depths coming into the screen :|
User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

It can be pretty distracting imo. Were you able to reproduce the 'spear shimmer' effect?

I wonder if there is a way to weight values on the edge of the screen so they dont have such a impact. Their weight would gradually increase as they move towards the center of the screen. That way hard edges that come into view wont cause such abrupt changes.
Post Reply