[Solved] Calculate pixels world position in compositors?

Problems building or running the engine, queries about how to use features etc.
Post Reply
User avatar
Xavyiy
OGRE Expert User
OGRE Expert User
Posts: 847
Joined: Tue Apr 12, 2005 2:35 pm
Location: Albacete - Spain

[Solved] Calculate pixels world position in compositors?

Post by Xavyiy » Sat Jul 12, 2008 7:02 pm

Hi all,
it's driving me crazy the fact that I can't calculate the world position of a pixel under compositors:

VertexProgram

Code: Select all

void main_vp_compositor(
	    // IN
		float4 iPosition      : POSITION,
		// OUT
		out float4 oPosition  : POSITION,
		out float3 oPosition_ : TEXCOORD0,
		// UNIFORM
		uniform float4x4 uWorld,
		uniform float4x4 uWorldViewProj)
{
	oPosition = mul(uWorldViewProj, iPosition);
	oPosition_ = mul(uWorld, iPosition);
}
FragmentProgram

Code: Select all

void main_fp_compositor(
    // IN
	float3 iPosition        : TEXCOORD0,
	// OUT 
	out float4 oColor		: COLOR)
{   
  oColor = float4(saturate(iPosition),1);
}
And the output image is always this: (In all camera positions/orientations):
Image

Am I skipping something? Or what's happend? (To be honest I'm not very familiarized with Ogre compositors!)

Thanks!
Last edited by Xavyiy on Sat Jul 12, 2008 11:05 pm, edited 1 time in total.
0 x

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

Post by nullsquared » Sat Jul 12, 2008 7:32 pm

When you use the vertex program, all you're doing is processing the 4 vertices of the full-screen quadrilateral of the compositor. If you want the world positions of the pixels that were previously rendered, you'll either need to set up a 32-bit floating-point RGB surface and render the positions in there, or set up a floating-point R surface to render the depth and then extract the positions from that. You can find an example of extracting the view-space (for world-space you'd multiply by the inverse view matrix) positions from a linear depth buffer in my SSAO demo. It doesn't use compositors, but it uses the same theory of a full-screen quadrilateral.

Now - my demo uses the 4 far frustum corners directly as it passes them as the normal attributes of the 4 vertices. Since you won't want to modify the compositor quadrilateral to do this, you can pass only one frustum corner, instead:
- use Camera::getFrustumCorners(), and pass the FAR-UPPER-RIGHT frustum corner as a uniform to the vertex shader
- find your final clip-space vertex position by multiplying with worldViewPorjection as usual, then normalize this vector, and multiply it with the above corner.
- pass this result as the interpolated "ray" as seen in the SSAO demo

The idea is to get a "ray" from the camera that goes through the pixel in question. Then you simply multiply this by the linear view-space depth of the object. In the SSAO demo, look for ssao.cg and fsquad_vs() as well as the helper functions. Also, look for diffuse.cg and geom_vs() and geom_ps() which stores the linear depth from the camera (as well as some normals, but you don't need those).
0 x

User avatar
Xavyiy
OGRE Expert User
OGRE Expert User
Posts: 847
Joined: Tue Apr 12, 2005 2:35 pm
Location: Albacete - Spain

Post by Xavyiy » Sat Jul 12, 2008 10:11 pm

Thanks nullsquared, at really I only need the Camera-ToPixel normalized vector.

At the end, I'm want to do this:
1) Pass to the vertex program 3 corners of far-plane(TOP-LEFT, TOP-RIGHT, BOTTOM-LEFT) and calculate the current position of the pixel with this code:

Code: Select all

void main_vp_compositor(
	    // IN
		float4 iPosition      : POSITION,
		// OUT
		out float4 oPosition  : POSITION,
		out float3 oPosition_ : TEXCOORD0,
		out float2 oUV        : TEXCOORD1,
		// UNIFORM
		uniform float3   uCorner0, // Top-left
		uniform float3   uCorner1, // Tio-right
		uniform float3   uCorner2, // Bottom-left
		uniform float4x4 uWorldViewProj)
{
	oPosition = mul(uWorldViewProj, iPosition);
	
	iPosition.xy = sign(iPosition.xy);
	oUV = (float2(iPosition.x, -iPosition.y) + 1.0f) * 0.5f;
	
        // Calculate segments
	float3  x01 = uCorner1-uCorner0; 
	float3  x02 = uCorner2-uCorner0; 
	
        // Multiply segments by the current pixel position[0,1] range
	x01 *= oUV.x;
	x02 *= oUV.y;
	
        // Final position = Origin + segment1 + segment2
	oPosition_ = uCorner0+x01+x02;
}
(I've tried with uCorner0+x01+x02;uCorner0+x01-x02;uCorner0-x01+x02;uCorner0-x01-x02;...)

and finally, in the vertex pixel calculate the view vector with:

Code: Select all

void main_fp_compositor(
    // IN
	float3 iPosition        : TEXCOORD0,
	float2 iUV 		        : TEXCOORD1,
	// OUT 
	out float4 oColor		: COLOR,
	// UNIFORM
	uniform float3  uLightDirection,
	uniform float   uIntensity,
	uniform float3  uHGg,
	uniform float3  uCameraPos,
	uniform sampler2D uDepthMap  : register(s0))
{   
    float3 view_vector = normalize(uCameraPos-iPosition);
    
    float4 shafts = tex2D(uDepthMap, iUV);

    float phase =compute_phase( view_vector, uHGg, -uLightDirection);

    oColor = float4((0.15 + uIntensity*shafts.xyz)*phase,1); 
}
But it seems not to work :(, my c++ code to upload corners is: (updated each frame)

Code: Select all

		// FAR_LEFT_TOP
		static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("CompositorGodRays"))->
			getTechnique(0)->getPass(0)->getVertexProgramParameters()->
			    setNamedConstant( "uCorner0", mCamera->getWorldSpaceCorners()[5] );
		// FAR_RIGHT_TOP
		static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("CompositorGodRays"))->
			getTechnique(0)->getPass(0)->getVertexProgramParameters()->
			    setNamedConstant( "uCorner1", mCamera->getWorldSpaceCorners()[4] );
		// FAR_LEFT_BOTTOM
		static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("CompositorGodRays"))->
			getTechnique(0)->getPass(0)->getVertexProgramParameters()->
			    setNamedConstant( "uCorner2", mCamera->getWorldSpaceCorners()[6] );
But it doesn't work, in all camera positions or orientations the result is the same for all pixels..., debug screenshot with oColor.xyz = (view_vector+1)/2;
Image

I don't know what the problem is...:(! But it's driving me really crazy!!

Thanks!
0 x

User avatar
Xavyiy
OGRE Expert User
OGRE Expert User
Posts: 847
Joined: Tue Apr 12, 2005 2:35 pm
Location: Albacete - Spain

Post by Xavyiy » Sat Jul 12, 2008 10:50 pm

Shit.... I think that I know what is happend.., compositors material parameters need to be updated in the compositor listener, because Compositors uses a copy of the original material..!

If I solve it, I will post!

EDIT: Solved!, all the above code works good, the only thing is not forgotten to update parameters in the compositor listener.
0 x

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

Post by nullsquared » Sun Jul 13, 2008 2:01 am

Sounds good :). I think you can simplify it by passing only the top-right far corner, and multiplying it by normalize(oPosition):

Code: Select all

oPosition = mul(worldViewProj, inputPosition);
oRay = float3(normalize(oPosition).xy, 1) * farTopRightCorner;
Either way, go with whatever works best for you.
0 x

Post Reply