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
nullsquared
Old One
Posts: 3245
Joined: Tue Apr 24, 2007 8:23 pm
Location: NY, NY, USA
x 9

Post by nullsquared »

Jerky wrote:
nullsquared wrote:
nikki wrote:Looks very nice. But I have a really old graphics card (GeForce FX 5600), and get really low FPS on most good looking stuff like this. :(
Does your 5600FX even run this? Because the demo renders to a 128-bit texture (32 bits for each channel)...
Runs on my fx 5200 as well. Only about 0.3 FPS though :(. Looks friggin fantastic though. Nice work!
Really didn't expect it to work there :shock: :lol:

Anyways, I figured why shader model 3 was fubar for most of you - there's a typo in the unified vertex shader definition. It should say "delegate", but I believe it said something stupid like "delete", instead. For those of you who had SM3 not work, mind checking out ssao.material to see if that was indeed the issue?

Godlike
Kobold
Posts: 27
Joined: Thu Jul 10, 2008 2:22 pm

Post by Godlike »

Hi there, I am new here but lurked a long time now and then.

I tried the demo but:

15:19:07: Creating resource group General
15:19:07: Creating resource group Internal
15:19:07: Creating resource group Autodetect
15:19:07: SceneManagerFactory for type 'DefaultSceneManager' registered.
15:19:07: Registering ResourceManager for type Material
15:19:07: Registering ResourceManager for type Mesh
15:19:07: Registering ResourceManager for type Skeleton
15:19:07: MovableObjectFactory for type 'ParticleSystem' registered.
15:19:07: OverlayElementFactory for type Panel registered.
15:19:07: OverlayElementFactory for type BorderPanel registered.
15:19:07: OverlayElementFactory for type TextArea registered.
15:19:07: Registering ResourceManager for type Font
15:19:07: ArchiveFactory for archive type FileSystem registered.
15:19:07: ArchiveFactory for archive type Zip registered.
15:19:07: FreeImage version: 3.9.3
15:19:07: This program uses FreeImage, a free, open source image library supporting all common bitmap formats. See http://freeimage.sourceforge.net for details
15:19:07: Supported formats: bmp,ico,jpg,jif,jpeg,jpe,jng,koa,iff,lbm,mng,pbm,pbm,pcd,pcx,pgm,pgm,png,ppm,ppm,ras,tga,targa,tif,tiff,wap,wbmp,wbm,psd,cut,xbm,xpm,gif,hdr,g3,sgi
15:19:07: DDS codec registering
15:19:07: Registering ResourceManager for type HighLevelGpuProgram
15:19:07: Registering ResourceManager for type Compositor
15:19:07: MovableObjectFactory for type 'Entity' registered.
15:19:07: MovableObjectFactory for type 'Light' registered.
15:19:07: MovableObjectFactory for type 'BillboardSet' registered.
15:19:07: MovableObjectFactory for type 'ManualObject' registered.
15:19:07: MovableObjectFactory for type 'BillboardChain' registered.
15:19:07: MovableObjectFactory for type 'RibbonTrail' registered.
15:19:07: *-*-* OGRE Initialising
15:19:07: *-*-* Version 1.4.6 (Eihort)
15:19:07: Loading library RenderSystem_Direct3D9
15:19:08: Installing plugin: D3D9 RenderSystem
15:19:08: D3D9 : Direct3D9 Rendering Subsystem created.
15:19:08: D3D9: Driver Detection Starts
15:19:08: D3D9: Driver Detection Ends
15:19:08: Plugin successfully installed
15:19:08: Loading library Plugin_CgProgramManager
15:19:08: Installing plugin: Cg Program Manager
15:19:08: Plugin successfully installed
15:19:08: CPU Identifier & Features
15:19:08: -------------------------
15:19:08: * CPU ID: AuthenticAMD: AMD Athlon(tm) 64 Processor 3700+
15:19:08: * SSE: yes
15:19:08: * SSE2: yes
15:19:08: * SSE3: yes
15:19:08: * MMX: yes
15:19:08: * MMXEXT: yes
15:19:08: * 3DNOW: yes
15:19:08: * 3DNOWEXT: yes
15:19:08: * CMOV: yes
15:19:08: * TSC: yes
15:19:08: * FPU: yes
15:19:08: * PRO: yes
15:19:08: * HT: no
15:19:08: -------------------------
15:19:08: D3D9 : Subsystem Initialising
15:19:08: ***************************************
15:19:08: *** D3D9 : Subsystem Initialised OK ***
15:19:08: ***************************************
15:19:08: D3D9RenderSystem::createRenderWindow "Ogre Soft Shadowing", 800x600 windowed miscParams: FSAA=0 vsync=false
15:19:08: D3D9 : Created D3D9 Rendering Window 'Ogre Soft Shadowing' : 800x600, 32bpp
15:19:08: D3D9 : WARNING - disabling VSync in windowed mode can cause timing issues at lower frame rates, turn VSync on if you observe this problem.
15:19:08: Registering ResourceManager for type Texture
15:19:08: Registering ResourceManager for type GpuProgram
15:19:08: RenderSystem capabilities
15:19:08: -------------------------
15:19:08: * Hardware generation of mipmaps: yes
15:19:08: * Texture blending: yes
15:19:08: * Anisotropic texture filtering: yes
15:19:08: * Dot product texture operation: yes
15:19:08: * Cube mapping: yes
15:19:08: * Hardware stencil buffer: yes
15:19:08: - Stencil depth: 8
15:19:08: - Two sided stencil support: yes
15:19:08: - Wrap stencil values: yes
15:19:08: * Hardware vertex / index buffers: yes
15:19:08: * Vertex programs: yes
15:19:08: - Max vertex program version: vs_2_0
15:19:08: * Fragment programs: yes
15:19:08: - Max fragment program version: ps_2_b
15:19:08: * Texture Compression: yes
15:19:08: - DXT: yes
15:19:08: - VTC: no
15:19:08: * Scissor Rectangle: yes
15:19:08: * Hardware Occlusion Query: yes
15:19:08: * User clip planes: yes
15:19:08: * VET_UBYTE4 vertex element type: yes
15:19:08: * Infinite far plane projection: yes
15:19:08: * Hardware render-to-texture: yes
15:19:08: * Floating point textures: yes
15:19:08: * Non-power-of-two textures: yes (limited)
15:19:08: * Volume textures: yes
15:19:08: * Multiple Render Targets: 4
15:19:08: * Point Sprites: yes
15:19:08: * Extended point parameters: yes
15:19:08: * Max Point Size: 256
15:19:08: * Vertex texture fetch: no
15:19:08: ResourceBackgroundQueue - threading disabled
15:19:08: Particle Renderer Type 'billboard' registered
15:19:08: Creating viewport on target 'Ogre Soft Shadowing', rendering from camera 'Mgr::cam', relative dimensions L: 0.00 T: 0.00 W: 1.00 H: 1.00 ZOrder: 0
15:19:08: Creating resource group Media
15:19:08: Added resource location '../../data' of type 'FileSystem' to resource group 'Media'
15:19:08: Initialising resource group Media
15:19:08: Parsing scripts for resource group Media
15:19:08: Parsing script 00ambient.material
15:19:08: Parsing script 00diffuse.material
15:19:08: OGRE EXCEPTION(2:InvalidParametersException): Parameter called invSMSize does not exist. in GpuProgramParameters::_findNamedConstantDefinition at D:\Ogre_CVS\ogrenew\OgreMain\src\OgreGpuProgram.cpp (line 883)
15:19:08: Error at line 33 of 00diffuse.material: Invalid param_named_auto attribute - Parameter called invSMSize does not exist.
15:19:08: Parsing script metal.material
15:19:08: Parsing script ogre.material
15:19:08: Parsing script shadow_caster.material
15:19:08: Parsing script ssao.material
15:19:08: Error at line 39 of ssao.material: Error in program ssao_ps_sm3 parameter compile_aruments is not valid.
15:19:08: Parsing script white.material
15:19:08: Parsing script debug.overlay
15:19:08: Finished parsing scripts for resource group Media
15:19:08: WARNING: Texture instance 'Ogre/ShadowTexture0' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
15:19:08: WARNING: Texture instance 'Ogre/ShadowTexture1' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
15:19:08: WARNING: Texture instance 'Ogre/ShadowTexture2' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
15:19:08: WARNING: Texture instance 'Ogre/ShadowTexture3' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
15:19:08: Creating viewport on target 'rtt/2953696', rendering from camera 'Ogre/ShadowTexture0Cam', relative dimensions L: 0.00 T: 0.00 W: 1.00 H: 1.00 ZOrder: 0
15:19:08: Creating viewport on target 'rtt/2952448', rendering from camera 'Ogre/ShadowTexture1Cam', relative dimensions L: 0.00 T: 0.00 W: 1.00 H: 1.00 ZOrder: 0
15:19:08: Creating viewport on target 'rtt/2953408', rendering from camera 'Ogre/ShadowTexture2Cam', relative dimensions L: 0.00 T: 0.00 W: 1.00 H: 1.00 ZOrder: 0
15:19:08: Creating viewport on target 'rtt/2953472', rendering from camera 'Ogre/ShadowTexture3Cam', relative dimensions L: 0.00 T: 0.00 W: 1.00 H: 1.00 ZOrder: 0
15:19:08: Creating viewport on target 'rtt/3035040', rendering from camera 'geom_cam', relative dimensions L: 0.00 T: 0.00 W: 1.00 H: 1.00 ZOrder: 0
15:19:08: Texture: random.png: Loading 1 faces(PF_A8R8G8B8,256x256x1) with 0 generated mipmaps from Image. Internal format is PF_A8R8G8B8,256x256x1.
15:19:08: OGRE EXCEPTION(3:RenderingAPIException): Cannot create D3D9 pixel shader ssao_ps_sm2 from microcode. in D3D9GpuFragmentProgram::loadFromMicrocode at D:\Ogre_CVS\ogrenew\RenderSystems\Direct3D9\src\OgreD3D9GpuProgram.cpp (line 180)

I have a X800 board which should support perfectly any kind of shader model 2.

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

Post by nullsquared »

I'm afraid it won't work on an X800:

a) seems like the shader failed to compile in a really odd way, probably because the ps_2_b version used too many texture fetches and instructions

b) I'm pretty sure the X800 doesn't have 128-bit floating point texture support, even less rendering to such a texture *

Sorry :|

* which reminds me, I probably should have optimized that a bit, you can use a 48-bit floating point texture instead without any noticeable SSAO quality loss (R16G16B16)

ShadowFire
Gnoblar
Posts: 13
Joined: Tue Jul 29, 2008 2:59 pm

Post by ShadowFire »

Hey null, great work. I was able to get this in a project of mine rather quickly last night. I also noticed some of the stuttering but I think it was when the camera was looking straight down a plane.

I had a question: If I wanted to add normal mapping to this where would be the key areas of interest. I know that one of the debug overlays shows the normal information for the ambient occlusion shader. So I would presumably need to put the object normals into that as well as in the diffuse.cg to handle the specular lighting correctly. Did I hit the right spots?

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

Post by nullsquared »

For the SSAO itself you only want the interpolated vertex normals, no normal mapping (since whatever you have in the normals should be respected in the depth, and normal mapping is not respected in the depth). Simply add your normal mapping to your lighting shader (which, in the demo's case, is the diffuse.cg file).

As for slowness: there is a bit optimization that can be made to go from a 128-bit buffer to a 48-bit buffer:
- change format from R32_RGBA to R16_RGB
- render depth to R, and normal.xy to GB
- to get the normal, use:

Code: Select all

float3 geom = tex2Dlod(gbuffer, float4(uv, 0, 0)).rgb;
float depth = geom.r;
// no normal mapping on SSAO normals means that Z can only be positive
float3 normal = float3(geom.yz, sqrt(1.0 - dot(geom.yz, geom.yz)));
This should be a lot faster on some cards (though on the 8800 series and above it poses no speed issues).

ShadowFire
Gnoblar
Posts: 13
Joined: Tue Jul 29, 2008 2:59 pm

Post by ShadowFire »

Great I'll give that a shot.

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

Post by nullsquared »

Uploaded some new screen shots for the curious (first page)

TSM
Gnoblar
Posts: 17
Joined: Sun Feb 05, 2006 9:31 pm

Post by TSM »

From an artistic view, if you turned down the AO effect by 50+% it would look much more realistic.

For example

http://www.projectoffset.com/blog.php?id=83

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

Post by nullsquared »

TSM wrote:From an artistic view, if you turned down the AO effect by 50+% it would look much more realistic.

For example

http://www.projectoffset.com/blog.php?id=83
I was pretty much just emphasizing the AO, obviously you'd want to tweak it for an actual scene. Anyways:

Off:
Image
On:
Image

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Man nully you are my hero...

I think I have found a way for people to use the compositor framework with your shaders. It seems like the only thing your 'fullscreen quad' framework does special is the projection of a texel into view space (you use the camera corners to calculate this).

I think there is more than one way to skin this cat. I have been calculating the texel view space position for my deferred shaders via the following...
//fragment shader
//from material - param_named_auto invProj inverse_projection_matrix
uniform float4x4 invProj,

...

//calculate projection vector
float3 projVec = float3(inPos[0], inPos[1], 1) *
float3(invProj[0][0], invProj[1][1], invProj[2][3]);

//calculate texel position (view space)
float3 texelPos = projVec*depth;
That should be all we need to cut the sseffect dependency eh? Not that there is anything wrong with it, I kinda like it actually, but im already using compositors heavily, so I want to keep things tidy. Unless you can think of anything your framework CAN do that the compositor framework cant?

I will try and test this later and report back my results.

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

Post by nullsquared »

Zeal wrote:Man nully you are my hero...

I think I have found a way for people to use the compositor framework with your shaders. It seems like the only thing your 'fullscreen quad' framework does special is the projection of a texel into view space (you use the camera corners to calculate this).

I think there is more than one way to skin this cat. I have been calculating the texel view space position for my deferred shaders via the following...
The way you posted actually won't work with the type of depth that is stored (linear distance to the camera). What you can do to reproduce the far frustum corners without modifying the full screen quadrilateral is to pass the far-upper-right corner via a shader parameter, and then multiply this by the final clip-space position in the vertex shader to get the signs correct (the corners are symmetric for the most part):

Code: Select all

VOut fsquad_vs(in float4 p : POSITION, uniform float4 farUpperRight, ...)
{
    ...
    OUT.ray = sign(p) * farUpperRight;
}
This eliminates the usage of normals to pass the frustum corners, and should be easy to do with a compositor.
That should be all we need to cut the sseffect dependency eh? Not that there is anything wrong with it, I kinda like it actually, but im already using compositors heavily, so I want to keep things tidy. Unless you can think of anything your framework CAN do that the compositor framework cant?
It's just that I use sseffect in my own engine very extensively to selectively generate screen-space effects into any texture I want, while compositors pretty much force you to do calculations over a given viewport. For example (using my new engine, wasn't ready when I did the SSAO demo):

Code: Select all

sseffectManager effects;
effects += sseffectPtr(new gbuffer(*renderer)), "gbuffer";
effects += sseffectPtr(new ssao(*renderer)), "ssao";
effects += sseffectPtr(new composite(*renderer)), "composite";

main loop
{
    clearFramebuffer();

    effects(); // does all rendering in a deferred "effects" manner

    swapBuffers();
}

// if you want to disable an effect
effects["ssao"]->active(false);
I will try and test this later and report back my results.
Awesome :D

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

The way you posted actually won't work
You sure? I store my depth as...

Code: Select all

	outPos = mul( worldViewProj, inPos );
	//depth
	outDepth = outPos.w;
The inverse projection code I posted above seems to work fine for my deferred shaders. At least it LOOKS like its correctly transforming them to view space...

And I have no idea how to calculate the 'far upper right' position (view space?) of the quad, or I would try that. Plus passing a custom param to a compositor quad is kind of a pain in the ass...

One other thing you do in your shader, you pass a matrix to transform a view space texel back to texture space. I wonder, (assuming the above inverse projection works), wouldnt I simply have to multiply by the 'regular' projection matrix? Of course I would then have to convert to texture coords, but that is pretty easy...

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

Post by nullsquared »

Zeal wrote:
The way you posted actually won't work
You sure? I store my depth as...

Code: Select all

	outPos = mul( worldViewProj, inPos );
	//depth
	outDepth = outPos.w;
The inverse projection code I posted above seems to work fine for my deferred shaders. At least it LOOKS like its correctly transforming them to view space...
Yes, but SSAO works with linear view-space depth:

Code: Select all

depth = length(viewSpacePosition.xyz);
And I have no idea how to calculate the 'far upper right' position (view space?) of the quad, or I would try that. Plus passing a custom param to a compositor quad is kind of a pain in the ass...
Camera::getFrustumCorners(), check the docs for which index was the far upper right.
One other thing you do in your shader, you pass a matrix to transform a view space texel back to texture space. I wonder, (assuming the above inverse projection works), wouldnt I simply have to multiply by the 'regular' projection matrix? Of course I would then have to convert to texture coords, but that is pretty easy...
It's PROJECTIONCLIPSPACE2D_TO_IMAGESPACE2D or something like that from OgreAutoParamDataSource.cpp multiply by the projection matrix. Just pass the project matrix, it'll be fine, but you'll need to convert from [-1..1] to [0..1].

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Ok well im getting there. I have everything 'working' (using the projection matrix and converting to [0-1]), I see the ambient occlusion but its clearly wrong (only fades in very close to the camera, among other errors). You must be right about my depth and/or the way I am converting my texel to view space.

You say the technique works with 'linear view space depth', does that mean we cant use our standard depth values generated for deferred shading? I still dont quite understand what the difference is between converting a texel to viewspace for my lighting calculations (which again, seems to work fine), and converting a texel to viewspace for ssao.

*just for fun I tried normalizing the texel view space position.. so close I can taste it now...

Image

The effect is still wrong though, you have to move the camera in REALLY close before things start to darken, and then they darken too much too fast..

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

Post by nullsquared »

Zeal wrote: You say the technique works with 'linear view space depth', does that mean we cant use our standard depth values generated for deferred shading?
You can still use the same depth values, as long as your deferred shading uses the same values.

SSAO needs linear view-space length-based depth. Not post-projection Z (which is what you're using). You can use the same method the SSAO uses with this depth (frustum far corners multiplied by the depth, with either of the two normalized) to do your deferred shading (and it's actually a lot faster, a single multiply).

That's really why I said to not base your deferred shading off of the demo, it does some really odd, funky things that really limit the potential.

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Haha damn that deferred shading demo!

Ok so how should I be storing my depth then? Can you post your depth calculation (and how you convert it to texel space in when deferred shading)?

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

Post by nullsquared »

Zeal wrote:Haha damn that deferred shading demo!

Ok so how should I be storing my depth then? Can you post your depth calculation (and how you convert it to texel space in when deferred shading)?
Heh, just look at the SSAO demo (ssao.cg and diffuse.cg), I do the exact same view-space computation for my deferred shading ;)

Code: Select all

outDepth = length(IN.viewSpacePosition.xyz);

Code: Select all

float3 viewSpacePosition = inDepth * farFrustumCorner / farCameraDistance;
// (or you can just normalize(farFrustumCorner), since it has the farCameraDistance length

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Ahh didnt see it tucked away at the bottom of the diffuse cg.

Ok I have switched my depth output to a length(viewspacePosition). Oddly enough all my lighting shaders still work fine, they didnt skip a beat (I was outputing projection space z before).

I also figured out its not that hard to set a param for a compositor material (last time I swear I had to setup a compositor listener, but this time I was able to set a param easily).

Problem is, I have no idea how to calculate this 'frustum corner' (since its based on a camera that only the compositor uses). Anyone know of a way I can find it out?

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

Post by nullsquared »

No, you need your own usage camera, not the compositor's camera.

Code: Select all

const Ogre::Vector3 *CORNERS = camera->getWorldSpaceCorners();

Ogre::Vector3 toView = camera->getViewMatrix(true);

// multiply by the view matrix since we don't want the world space corners, but the view-space corner
Ogre::Vector3 farTopRight = toView * CORNERS[4];
http://www.ogre3d.org/docs/api/html/cla ... 1Cameraa65

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Heh but the whole idea is I would like to just use the compositor framework. It is really easy to render a quad...

Code: Select all

compositor SSAO
{
	technique
	{		
		//generate ssaoTex
		target_output
        {
            input none
            pass render_quad
            {
                material Core/SSAO
            }
        }
	}  
}
I will check out the compositor class... If anyone has any idea on how to access this information, please lemme know.

If I cant figure it out by tonight I guess ill just use your method.

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

Post by nullsquared »

Zeal wrote: If I cant figure it out by tonight I guess ill just use your method.
No, compositors are good. Just grab the material the compositor is using (it's a copy of the original), get the vertex program parameters, and setNamedConstant() with the above code I posted.

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Problem is the above code you posted assumes the compositor doesnt use a special camera for all its quad renders. I just tried passing the ray based on the code you posted (using the players camera corners/view matrix) and got some funky results, so I think the compositor HAS to be using its own camera (with custom view, fov, ect..).

Ill check out the compositor class one more time, but I have a feeling I wont be able to use a compositor for this effect.

*but really with all the crap ogre can automatically pass to shaders, none of this will do what we need?

http://www.ogre3d.org/docs/manual/manual_23.html#SEC106

*wait a minute. The compositor framework doesnt even use a camera...

Code: Select all

Renderable *CompositorManager::_getTexturedRectangle2D()
{
	if(!mRectangle)
	{
		/// 2D rectangle, to use for render_quad passes
		mRectangle = new Rectangle2D(true);
	}
	RenderSystem* rs = Root::getSingleton().getRenderSystem();
	Viewport* vp = rs->_getViewport();
	Real hOffset = rs->getHorizontalTexelOffset() / (0.5 * vp->getActualWidth());
	Real vOffset = rs->getVerticalTexelOffset() / (0.5 * vp->getActualHeight());
	mRectangle->setCorners(-1 + hOffset, 1 - vOffset, 1 + hOffset, -1 - vOffset);
	return mRectangle;
}
So all the info we need is based on the viewport on which the compositor is attached to? Can we calculate your projection 'ray' with this information?

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

Post by nullsquared »

I don't see what you're talking about here. The compositor's way of rendering has nothing to do with the main camera corners.

If you're getting incorrect results, then output the view-space position as the SSAO, so we can get to debuggging.

User avatar
Zeal
Ogre Magi
Posts: 1260
Joined: Mon Aug 07, 2006 6:16 am
Location: Colorado Springs, CO USA

Post by Zeal »

Ok wait youre right, the compositors camera/viewport wont help us reconstruct a position thats based on the main camera. Ok, so I do the following setup...

Code: Select all

	//create the ssao render target
	mSSAOTex = Ogre::TextureManager::getSingleton().createManual( "SSAOTex",
		Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 
		res.x, res.y, 0, Ogre::PF_R8G8B8A8, Ogre::TU_RENDERTARGET );

	mSSAORT = mSSAOTex->getBuffer()->getRenderTarget();
	v = mSSAORT->addViewport( mGraphicsCore.camera );
	v->setClearEveryFrame(true);
	v->setOverlaysEnabled(false);

	//add a compositor to render a simple quad
	Ogre::CompositorManager::getSingleton().addCompositor( v, "SSAO" );
...configure the 'corner' param...

Code: Select all

	const Ogre::Vector3 *CORNERS = mGraphicsCore.camera->getWorldSpaceCorners(); 
	Ogre::Matrix4 toView = mGraphicsCore.camera->getViewMatrix(true); 
	// multiply by the view matrix since we don't want the world space corners, but the view-space corner 
	Ogre::Vector3 farTopRight = toView * CORNERS[4]; 

	Ogre::MaterialPtr mat= (Ogre::MaterialPtr)Ogre::MaterialManager::getSingleton()
		.getByName("Core/SSAO"); 
	mSSAOParams = mat->getTechnique(0)->getPass(0)
		->getVertexProgramParameters();
	mSSAOParams->setNamedConstant("farUpperRight",
		Ogre::Vector4(farTopRight.x,farTopRight.y,farTopRight.z,1)); 
...using the following vertex shader...

Code: Select all

void vpSSAO (

	//in
	uniform float4x4 worldViewProj,
	uniform float4 farUpperRight,
	in float4 inPos : POSITION,

	//out
	out float4 outPos : POSITION,
	out float2 outUV0 : TEXCOORD0,
	out float4 outPos2 : TEXCOORD1,
	out float3 outRay : TEXCOORD2
	
) {

	outPos = mul( worldViewProj, inPos );
	outPos2 = outPos;

	//the input positions are adjusted by texel offsets, so clean up inaccuracies
	inPos.xy = sign( inPos.xy );
	
	outUV0 = ( float2( inPos.x, -inPos.y ) + 1.0f ) * 0.5f;
	
	outRay = sign(inPos) * farUpperRight; 
     
}
...and the fragment shader (copied almost exactly, except I am using the proj matrix to reconstruct the neighbor uv positions)...

Code: Select all

float4 fpSSAO (

	//in
	uniform sampler2D depthMap : register(s0),
	uniform sampler2D randMap : register(s1),
	
	uniform float4x4 proj,

	float2 inUV0 : TEXCOORD0,
	float4 inPos : TEXCOORD1,
	float3 inRay : TEXCOORD2
	
) : COLOR0 {

	//return float4(inRay,1);

    const float3 RAND_SAMPLES[128] = {
        float3(-0.027131, -0.246559, 0.530992),
        float3(0.210791, -0.976012, 0.357158),
        float3(0.0462355, -0.106906, 0.671804),
        float3(-0.806879, 0.610157, -0.245094),
        float3(0.117038, 0.691458, -0.163793),
        float3(-0.754204, -0.859249, 0.118931),
        float3(-0.907285, -0.24601, 0.0990326),
        float3(-0.153844, -0.0475784, -0.492111),
        float3(0.467757, -0.0378735, -0.401471),
        float3(-0.393292, 0.00106815, -0.951292),
        float3(-0.248573, -0.507859, -0.433943),
        float3(-0.0719932, 0.67626, -0.825373),
        float3(-0.285318, 0.1948, 0.835505),
        float3(0.525193, 0.0574664, 0.346782),
        float3(-0.251198, 0.946715, -0.500229),
        float3(-0.675222, 0.62212, -0.263466),
        float3(0.404584, 0.275735, 0.308756),
        float3(0.452986, 0.742607, 0.350566),
        float3(-0.834834, -0.402081, -0.705924),
        float3(-0.649709, 0.363628, 0.928953),
        float3(-0.0367138, -0.968261, -0.775384),
        float3(-0.287881, 0.269204, -0.113926),
        float3(0.131077, 0.229408, 0.0739463),
        float3(-0.79754, -0.412885, 0.852046),
        float3(-0.38731, -0.770135, 0.984191),
        float3(-0.00729392, 0.886288, -0.752007),
        float3(-0.363811, -0.750237, -0.520249),
        float3(0.361858, -0.352947, -0.945433),
        float3(0.869442, 0.830988, -0.827387),
        float3(-0.864193, 0.280496, 0.746574),
        float3(-0.36021, -0.88757, 0.157933),
        float3(-0.131687, -0.515244, -0.471969),
        float3(0.313211, -0.565233, -0.0259713),
        float3(0.639332, 0.80932, -0.242286),
        float3(-0.331156, -0.729423, 0.646657),
        float3(0.415204, -0.901975, -0.952269),
        float3(0.312052, 0.85406, 0.199255),
        float3(0.32316, -0.746574, 0.215613),
        float3(0.0924406, -0.895627, 0.343303),
        float3(0.19602, -0.251259, -0.700064),
        float3(0.392376, -0.245277, -0.885067),
        float3(-0.406659, 0.776849, -0.517197),
        float3(-0.74102, -0.741142, -0.758538),
        float3(0.443831, -0.903806, 0.230934),
        float3(0.940794, -0.699576, -0.739128),
        float3(-0.259621, -0.219153, 0.538011),
        float3(0.684744, 0.829218, 0.125217),
        float3(-0.40141, 0.444563, -0.943297),
        float3(-0.0746178, -0.262062, 0.442366),
        float3(0.710196, -0.659536, 0.416974),
        float3(-0.520188, 0.830988, -0.0925626),
        float3(0.0415357, 0.289712, 0.37022),
        float3(0.324503, 0.861934, 0.0868862),
        float3(0.785943, -0.089938, 0.845332),
        float3(0.20127, -0.606494, -0.199194),
        float3(0.333048, -0.644154, -0.216651),
        float3(0.949461, 0.295999, 0.150792),
        float3(0.616688, 0.986511, -0.000335704),
        float3(-0.682119, -0.886898, -0.992309),
        float3(0.892209, -0.69335, 0.542467),
        float3(0.349712, 0.527512, -0.235023),
        float3(0.032075, 0.41612, -0.664174),
        float3(0.477035, 0.00393689, -0.382305),
        float3(0.0550859, 0.320353, -0.447066),
        float3(0.487411, 0.633839, -0.194678),
        float3(-0.921323, -0.965514, 0.420515),
        float3(-0.241066, 0.484054, -0.601062),
        float3(0.449507, -0.284402, 0.252602),
        float3(-0.131016, -0.362163, 0.577685),
        float3(-0.28251, -0.674734, -0.295755),
        float3(-0.892392, -0.165929, 0.172277),
        float3(0.623768, 0.815485, 0.768975),
        float3(0.821223, -0.570788, 0.802301),
        float3(-0.381817, -0.214087, 0.174047),
        float3(-0.875973, 0.566454, 0.454451),
        float3(-0.133457, 0.237037, 0.800653),
        float3(0.599414, 0.190222, -0.912168),
        float3(0.489303, -0.311563, -0.178808),
        float3(-0.589099, 0.141636, 0.0583819),
        float3(-0.843867, 0.79461, -0.342692),
        float3(-0.984863, 0.262551, 0.0802332),
        float3(0.380474, -0.0780358, -0.135594),
        float3(-0.344707, 0.469955, -0.661977),
        float3(0.175634, 0.203589, 0.898984),
        float3(0.270974, -0.606922, 0.475021),
        float3(0.395184, 0.604663, 0.663076),
        float3(-0.362651, 0.635914, 0.765496),
        float3(-0.667837, 0.772759, 0.00863674),
        float3(-0.310465, -0.703604, -0.919187),
        float3(-0.748833, -0.847224, 0.26017),
        float3(-0.648061, -0.717215, -0.472884),
        float3(0.717887, 0.271767, 0.539537),
        float3(-0.974975, 0.470748, 0.120884),
        float3(0.125706, -0.505539, -0.508408),
        float3(-0.56859, 0.0946989, 0.827387),
        float3(0.949156, -0.837214, -0.829524),
        float3(-0.956053, -0.794488, -0.0399487),
        float3(-0.776238, 0.115268, 0.598804),
        float3(-0.943724, 0.814142, 0.586352),
        float3(-0.177099, 0.382244, -0.889035),
        float3(-0.937193, -0.281961, 0.445662),
        float3(0.506455, -0.376629, -0.716422),
        float3(-0.457869, -0.768364, -0.779717),
        float3(-0.273598, 0.861202, 0.289468),
        float3(0.130772, -0.64391, -0.951353),
        float3(0.0165716, -0.478133, -0.858577),
        float3(0.789483, 0.586291, -0.809198),
        float3(-0.261452, 0.971191, -0.234107),
        float3(-0.456221, -0.194983, 0.993652),
        float3(0.240089, 0.875423, 0.410871),
        float3(0.784356, -0.186743, 0.0116886),
        float3(-0.63976, -0.916135, 0.803461),
        float3(-0.621387, 0.235755, -0.436323),
        float3(-0.060213, 0.558946, -0.0224311),
        float3(-0.662465, -0.923093, -0.600208),
        float3(-0.189306, -0.569079, 0.0380566),
        float3(0.734001, -0.668203, -0.230506),
        float3(-0.101169, -0.223792, 0.569323),
        float3(0.249367, 0.0263985, 0.258522),
        float3(-0.171667, 0.452498, -0.816401),
        float3(0.365764, 0.13303, -0.431257),
        float3(0.0129093, 0.53502, 0.0798669),
        float3(-0.912534, -0.788751, 0.18009),
        float3(-0.0874355, -0.178747, 0.709342),
        float3(-0.595264, 0.632984, -0.176061),
        float3(0.166417, 0.766961, 0.959349),
        float3(0.766167, 0.0951872, -0.844478),
        float3(-0.0554521, -0.670034, -0.0729087)
    };

    const float RADIUS = 0.12;//0.08;
    const int NUM_SAMPLES = 12;

    // random normal lookup from a texture
    #ifdef SM3
    float3 randN = tex2Dlod(randMap, float4(inUV0 * 24, 0, 0)).xyz;
    #else
    float3 randN = tex2D(randMap, inUV0 * 24).xyz;
    #endif
    randN = expand(randN);

    // our "current" depth/position and normals
    #ifdef SM3
    float4 geom = tex2Dlod(depthMap, float4(inUV0.xy, 0, 0));
    #else
    float4 geom = tex2D(depthMap, inUV0.xy);
    #endif
    // view-space position
    float4 D = computeViewPos(inRay, geom.w);
    // view-space normals
    float3 N = geom.xyz;
    
    //return D;

    // accumulated occlusion factor
    float occ = 0;
    for (int i = 0; i < NUM_SAMPLES; ++i) {
        // reflected direction to move in for the sphere
        // (based on random samples and a random texture sample)
        float3 RN = reflect(RAND_SAMPLES[i], randN);

        // bias the random direction away from the normal
        // this tends to minimize self occlusion
        const float DIR_BIAS = 1.5;
        RN += N * DIR_BIAS;

        // new (view-space) position in a sphere of RADIUS
        float3 vp = D.xyz + RN * RADIUS;

        // move this new position back into texture space
        
        //!!! changed this to use projection matrix...
        //float4 nuv = mul(pMat, float4(vp, 1));
        //nuv.xy /= nuv.w;
        
        float4 nuv = mul(proj, float4(vp, 1));
        nuv.xy = ( nuv.xy + 1.0f ) / 2.0f;
		nuv.y = 1-nuv.y;

        // look up the new depth
        #ifdef SM3
        float depth = tex2Dlod(depthMap, float4(nuv.xy, 0, 0)).w;
        #else
        float depth = tex2D(depthMap, nuv.xy).w;
        #endif

        // get the (scaled) Z difference
        const float ZSCALE = 50;
        float ZD = ZSCALE * max(D.w - depth, 0);

        // quadratic falloff is both accurate
        // and it avoids the halo effect (mostly)
        const float MAX_DIFF = 2;
        const float NO_OCC = 4;
        occ += (ZD < ZSCALE * MAX_DIFF ? occlusion(ZD) : NO_OCC);
    } occ = occ / NUM_SAMPLES;
    occ = lerp(0.3, 1, occ);

    return float4(occ.xxx, 1);
}
These are the results I get, first I visualized the 'ray' that well be using to reconstruct the view space positions, does this look right?

Image

Then when I multiply this ray by the depth (which I am now storing in linear view space) I get this...

Image

And finally the ooc result (which is clearly wrong)...

Image

Any ideas?

Thanks again for all your help with this!

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

Post by nullsquared »

Yup, the ray is wrong. It should be yellow/red/black/green (not necessarily in that specific order).

Try this, instead:

Code: Select all

outRay = float3(sign(outPos.xy), 1) * farUpperRight;
// also, try without the sign()
(btw, you'll need to still divide by .w on the projected texture coordinates before you move them to image-space)

Post Reply