How to setup paraboloid's view matrix in dual paraboloid shadow map?

Started by
12 comments, last by Jofo 12 years, 2 months ago
I am trying to implement the dual paraboloid base on this site http://gamedevelop.e...dow-mapping.htm

I am using a point light located at the origin, so how do we setup the paraboloid's view matrix for the front and back map?

Instead of using d0(0, 0, -1) and d1(0, 0, 1) to set value for direction variable in shader source code like

pos.z *= direction //for front and back map

I use it to setup the view matrix like

LighPostion + d0 (for front map)
LighPostion + d1 (for back map)



D3DXVECTOR3 temp = D3DXVECTOR3( 0.0f, 0.0, fDirection ); //fDirection = -1 for the back map, 1 for the front map
D3DXVECTOR3 lightTargetW = vLightPos + temp;
D3DXVECTOR3 lightUpW(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&mDPView, &vLightPos, &lightTargetW, &lightUpW);



I did that to setup the LookAt point being used for paraboloid's view matrix. Then before rendering the scene, I create shadow maps for front and back paraboloid by modifying view matrix for each map. But how can I modify it when I render the scene?
Advertisement
If I understood you correctly: You can't change the position until the process. You can place the light and the matrix arbitrary,
but you have to render the scene according to your light position and shadow maps.
What you have done so far looks right.
Zero01, thank for replying but I do not think I am clear about your answer, so what about the final view matrix for the second pass, rendering the scene base on shadow map textures. Let's me give you all information about my situation

First, I have a floor located at from -10 to 10 on xz plane, -8 at y axis.
Second, I have a sphere located at (-2, -5, -2) and the point light is at the origin

Like I said above, I modified the view matrix in the first pass, creating shadow maps ( LightPosition + d0 / d1 ). And in the second pass, I do not know how to set up the view matrix, so I tried to set LookAt point is (0, -1, 0). Then everything is black :(

This is the shader source code in the second pass:




DP_OutputVS RenderShadowMapVS( DP_InputVS In ) {
DP_OutputVS output;

output.pos = mul( float4(In.pos, 1), g_mWVP );
output.posWorld = mul( float4(In.pos, 1), g_mWorld).xyz;
output.normal = mul( float4(In.normal, 0), g_mWorld ).xyz;
output.light = g_vLightPos - output.posWorld;

return output;
}

float4 RenderShadowMapPS( DP_OutputVS In ) : COLOR {
float3 color;

float4 vPosDP = mul( float4(In.posWorld, 1), g_mDPView );
float fLength = length( vPosDP.xyz );
vPosDP /= fLength;

float fSceneDepth = ( fLength - g_fNear ) / ( g_fFar - g_fNear );
float fDPDepthBack;
float fDPDepthFront;
float fDPDepth;

if ( vPosDP.z >= 0.0f ) {
//Project to front map
float2 vTexFront;
float posX_Front = vPosDP.x / ( 1.0f + vPosDP.z );
float posY_Front = vPosDP.y / ( 1.0f + vPosDP.z );
vTexFront.x = posX_Front * 0.5f + 0.5f;
vTexFront.y = 1.0 - ( posY_Front * 0.5f + 0.5f );
fDPDepth = tex2D( DPFrontSampler, vTexFront );
} else {
//Project to back map
float2 vTexBack;
float posX_Back = vPosDP.x / ( 1.0f - vPosDP.z );
float posY_Back = vPosDP.y / ( 1.0f - vPosDP.z );
vTexBack.x = posX_Back * 0.5f + 0.5f;
vTexBack.y = 1.0 - ( posY_Back * 0.5f + 0.5f );
fDPDepth = tex2D( DPBackSampler, vTexBack );
}

//Lighting and shadow
float3 vNormal = normalize( In.normal );
float3 vLight = normalize( In.light );

float diffuse = saturate( dot(vLight, vNormal) ) * g_LightDiffuse * g_MaterialDiffuse;
float ambient = g_LightAmbient * g_MaterialAmbient;

if ( (fDPDepth + SHADOW_EPSILON) < fSceneDepth ) {
color = g_mColor * ambient;
} else {
color = g_mColor * ( ambient + diffuse );
}

return float4(color, 1);
}



And this is the C++/DirectX source code, of course I've already set the effect parameters



D3DXMATRIX lightView;
D3DXVECTOR3 lightPosW = vLightPos;
D3DXVECTOR3 lightTargetW(0.0f, -1.0f, 0.0f);
D3DXVECTOR3 lightUpW(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&mDPView, &lightPosW, &lightTargetW, &lightUpW);


for(UINT i = 0; i < cPass; i++)
{
V( g_pEffect9->BeginPass( 0 ) );

V( g_pEffect9->SetMatrix( mhWVP , &(mFloorWorld * mView * mProj) ) );
V( g_pEffect9->SetMatrix( mhWorld, &mFloorWorld ) );
D3DXVECTOR4 vColor = D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f );
g_pEffect9->SetVector(mhEmissive, &vColor);
V( g_pEffect9->CommitChanges() );
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

vColor = D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f );
V( g_pEffect9->SetVector(mhEmissive, &vColor) );
V( g_pEffect9->SetMatrix( mhWVP, &(mSphereWorld * mView * mProj) ) );
V( g_pEffect9->SetMatrix( mhWorld, &mSphereWorld ) );
V( g_pEffect9->CommitChanges() );
V( g_pSphere->DrawSubset(0) );

V( g_pEffect9->EndPass() );
}

V( g_pEffect9->End() );

I think I've already figured out that the 2 paraboloids located at the origin, then we set up the view matrix is position(0,0,0) lookAt(0,0,5) as building the shadow maps. Next, in the second pass, we need to use the view matrix of the light, completely different with the paraboloid's matrix 'cause the light can locate anywhere we set.
You're only partially right.

The most important steps:

a.) creating shadow maps

- set front shadow map
- render scene from light's perspective (pos. dir: g_fDir = 1)

- disable back-face culling

- set back shadow map
- render scene from light's perspective (neg. dir: g_fDir = -1)

->shadow maps are created

b.) render final scene

- set scene render target and the shadow maps

- render from cam (view matrix)

that's it!

Your shadow maps have to be placed at the final light position.
Zero01, thanks for helping me but when I tried to render the scene but everything is in shadow :(, so I checked the shadows created in the first pass. The following images is the front and back shadow maps

the whole screen


Shadow maps
Front
Back


The code for setting up the light's view matrix

D3DXVECTOR3 lightPosW = vLightPos;
D3DXVECTOR3 lightTargetW(0, 0, 0);
D3DXVECTOR3 lightUpW(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&mLightView, &lightPosW, &lightTargetW, &lightUpW);


The shader for the first pass:

DPDepthInput_PS BuildShadowMapVS( DPDepthInput_VS In )
{
DPDepthInput_PS output;
output.pos = mul( float4(In.pos, 1), g_mDPWorldView );

//Project to DP space
output.pos /= output.pos.w;

output.pos.z *= g_fDir;

float fLength = length( output.pos.xyz );
output.pos /= fLength;

output.clipDepth = output.pos.z;

//calculate the normal vector at the intersection point
output.pos.x /= (output.pos.z + 1.0f);
output.pos.y /= (output.pos.z + 1.0f);

output.pos.z = ( fLength - g_fNear ) / ( g_fFar - g_fNear );
output.pos.w = 1.0f;

output.depth = output.pos.z;

return output;
}

float4 BuildShadowMapPS( DPDepthInput_PS In ) : COLOR {
clip( In.clipDepth );

return In.depth; //skip w because w = 1
}


Some information about the objects
light vLightPos( 0.0f, 8.0f, 3.0f );
the sphere at (-2, 2, -2)
//Triangle's vertices

MYVERTEX VertTriangle[3] = {
{ D3DXVECTOR3(-3.0f, 0.0f, 5.0f), D3DXVECTOR3(0.0f, 0.0f, 1.0f) },
{ D3DXVECTOR3(0.0f, 3.0f, 7.0f), D3DXVECTOR3(0.0f, .0f, 1.0f) },
{ D3DXVECTOR3(3.0f, 0.0f, 5.0f), D3DXVECTOR3(0.0f, 0.0f, 1.0f) }
};

Maybe there's something wrong with shadow maps because the sphere and triangle is closer to the light than the floor, but the floor's color is lighter in the sense that closer :(
The code is correct but there is definitly something wrong with your shadow maps -> are you sure that you use the above shader? -> there is no paraboloid projection on your shadow map! Maybe the effect params are wrong? and which format to you use? (R32F is recommended)
For the start, try to use highly tesselated geometry, so you would see does it actually looks like a paraboloid mappping or not.

Sorry, I didn't checked your code, too tired right now. Try using mine as a referrence. "uniform float direction" input value to vertex shader set's which part of hemisphere you need to render.
I'm using dx9 and input matrix is just a simple inverse of position\rotation\scale matrix of my light, it just sets it's position in world space and orientation.

ParBasis - inverse of position\rotation\scale matrix of my light
object_to_world - world matrix of geometry to render



// Vertex shader
in_sm_ps par_sm_vs(in_vs input, uniform float direction) {
in_sm_ps output;

float4 toWorld = mul(float4(input.pos.xyz, 1), object_to_world);
float4 clip_pos = mul(toWorld, ParBasis);

clip_pos = clip_pos / clip_pos.w;

clip_pos.z = clip_pos.z * direction;

float L = length( clip_pos.xyz );
clip_pos = clip_pos / L;

output.z_value = clip_pos.z;

clip_pos.z = clip_pos.z + 1;

clip_pos.xy = clip_pos.xy / clip_pos.z;

clip_pos.xy = clamp(clip_pos.xy, -1, 1); //trying to avoid overlaps

clip_pos.xy += sector.xy;
clip_pos.xy *= 1.f/4.f;

clip_pos.z = L / 1000;
clip_pos.w = 1;

output.clip_pos = clip_pos;

output.vertex_to_light = toWorld.xyz - light_position;

return output;
}
//---------------------------------------------------------------
float4 par_sm_ps(in_sm_ps input) : COLOR {
clip(input.z_value + 0.2);
float d = length(input.vertex_to_light);
float2 moments = GetMoments(d);
return float4(moments, 1, 1);
}
//---------------------------------------------------------------

// Techniques
technique sm_parabaloid_render { //Tech #2
pass P0 {

ZEnable = TRUE;
ZWriteEnable = TRUE;
CullMode = CCW;
VertexShader = compile vs_3_0 par_sm_vs(1);
PixelShader = compile ps_3_0 par_sm_ps();
}
}



[font="arial, verdana, tahoma, sans-serif"]Thank Viik, I am really appreciate it and I am also using dx9 but could you upload the complete project for me to reference or send to my email aiuvoanh@nate.com?. Because I want to do it on my own

Thank Zero01, now I am using R32F but it's slower :([/font]

The front and back shadow map are the same

The final screen


The shader with a slightly difference


DPDepthInput_PS BuildShadowMapVS( DPDepthInput_VS In )
{
DPDepthInput_PS output;
output.pos = mul( float4(In.pos, 1), g_mDPWorldView );

//Project to DP space
output.pos /= output.pos.w;

//output.pos.z *= g_fDir;

float fLength = length( output.pos.xyz );
output.pos /= fLength;

output.clipDepth = output.pos.z;

//calculate the normal vector at the intersection point
output.pos.x /= (output.pos.z + 1.0f);
output.pos.y /= (output.pos.z + 1.0f);

output.pos.z = ( fLength - g_fNear ) / ( g_fFar - g_fNear );
output.pos.w = 1.0f;

output.depth = output.pos.z;

return output;
}

float4 BuildShadowMapPS( DPDepthInput_PS In ) : COLOR {
clip( In.clipDepth );

return In.depth; //skip w because w = 1
}



the code for setting up parameters


void setupLightView( float fDirection ) {
D3DXVECTOR3 lightPosW = vLightPos;
D3DXVECTOR3 lightTargetW( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 lightUpW(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&mLightView, &lightPosW, &lightTargetW, &lightUpW);

HRESULT hr;
V( g_pEffect9->SetFloat( mhDirection, fDirection ) );
V( g_pEffect9->SetFloat( mhFar, 30.0f ) );
V( g_pEffect9->SetFloat( mhNear, 0.10f ) );
}



I comment the following line in shader, otherwise the whole screen will be black in the second pass :(. One more thing, when I comment it, the front and shadow map is the same
output.pos.z *= g_fDir

It's about the shadow, if you take a look at the final screen, you will see that there's something wrong with the floor's border and the sphere's shadow
1. The R32F format is slower, but more accurate!
2. You shouldn't comment out the g_fDir param!

If you want, send me your code (mail address in my profile) and I will fix it!

This topic is closed to new replies.

Advertisement