Sign in to follow this  
reaper93

Projective Texturing for Reflections [SOLVED]

Recommended Posts

I have read Yann's water article and have adopted the methods put forward in order to implement reflections. Yann's Article: http://www.gamedev.net/reference/articles/article2138.asp I have it working although there are a few things that are not quite right. Here is an image of the render: As you can see its reasonably ok from this angle, however when I rotate my camera on the X axis (look up and down) the projected texture moves with it, which results in this: I think I know what the issue is but I am not sure how to go about fixing it. When I render the land to a texture, I render it as a reflection by transforming the current camera view matrix by : 1.0f, 0.0f, 0.0f, 0.0f 0.0f, -1.0f, 0.0f, 0.0f //Flip scene in y axis 0.0f, 0.0f, 1.0f, 0.0f 0.0f, 0.0f, 0.0f, 1.0f However depending on the angle of the camera, the scene is rendered to a different portion of the texture. I was under the impression that the projection coordinates will correctly place the texture based on the viewing angle? If so how would I make sure the texture is rendered to the same portion of the surface each time? I have included some source code: Matrices used for render to texture
        //The view projection for reflected scene render(this is passed into
        //the shader when rendering our geometry
        //Construct our reflection matrix
        D3DXMATRIX reflect;
        D3DXMatrixIdentity(&reflect);
        reflect(1,1) = -1.0f;

        //Transform current camera matrix by reflection matrix
        m_rViewMatrix = m_viewMatrix * reflect; 

        //Combine with projection and pass to shader
        m_rViewProj = m_rViewMatrix * m_proj;





Render to texture (Note: I am rendering to a 512x512 texture, this code is not very relevent, just included it to show the viewport I use. The render to texture itself works fine, the geometry is effectivly mirrored on the y plane(as I can see in Pix anyway)

        //Render our reflection texture
        D3DVIEWPORT9 vp = {0, 0, 512, 512, 0.0f, 1.0f};
        if(m_reflectTexture.beginScene(vp))
        {
            m_device->SetRenderTarget(0, m_reflectTexture.getSurface());
            m_device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, Colour::BLACK , 1.0f, 0 );
            m_landA.render(m_lights, m_camera, m_fxManager, "Terrain.fx", "Terrain", updateTime, m_landATextureList, m_textureManager.getTextureListSize("LandATextures"), true);
            m_reflectTexture.endScene();
        }





Water plane shader, Projective Texturing(Note: the ViewProjMatrix used here is not the reflected one, its the actual camera view * proj
//VERTEX SHADER:

    //Transform to world space position
    float3 WorldPosition = mul( float4(IN.Position, 1.0f), WorldMatrix );  
    OUT.Position = mul( float4(WorldPosition, 1.0f), ViewProjMatrix );

    //Note will pass this matrix in later as a shader constant, just quick hack for now
    float4x4 ref;
    ref[0] = float4(0.5f, 0.0f, 0.0f, 0.0f);
    ref[1] = float4(0.0f, 0.5f, 0.0f, 0.0f);
    ref[2] = float4(0.0f, 0.0f, 0.5f, 0.0f);
    ref[3] = float4(0.5f, 0.5f, 0.5f, 1.0f);
  
    float4x4 reflectMat = mul(ViewProjMatrix, ref );
    OUT.TexCoord1 = mul( float4(WorldPosition, 1.0f), reflectMat );

//PIXEL SHADER:

    // Project the texture coords and scale/offset to [0, 1].
    float4 projTex = IN.TexCoord1;
    projTex.xy /= projTex.w;            
    projTex.x =  0.5f*projTex.x + 0.5f; 
    projTex.y = -0.5f*projTex.y + 0.5f;

    //Apply an offset based on normal map for ripple effect
    projTex.xy += projTex.xy + (rippleOffset * normal.xy);
    projTex.w = 1.0f;

    //Sample using projected coords, use dummy light data for now
    OUT.Colour = (tex2D(Reflect, projTex.xy) * 0.7f) + ((sunFinal + ambientFinal) * 0.3f);
    return OUT;



[Edited by - reaper93 on January 20, 2009 5:10:26 PM]

Share this post


Link to post
Share on other sites
I'm not sure that matrix you use is right, you can create a reflect matrix using a plane with D3DXMatrixReflect. Oh and I just noticed, you are transforming the camera by the reflection? I dont think this will always work, its better to do the world matrix...just remember to reverse the culling.

Or, you can dispense with matrices and simply do the reflection in the vertex shader like this: pos.y -= pos.y

and then clip from the water level in the pixel shader...just pass pos.y into the pixel shader and do something like this:

half waterline=1;

if ((In.posy)>waterlevel)
{
waterline=-1;
}

clip(waterline);

-------------------------------------------------------
I think your texture projection is right...

Share this post


Link to post
Share on other sites
Hmm one thing I should point out is the water plane is not at 0 y, the whole scene is actually suspended a fair amount above y, will this cause the reflection texture to be wrong?

When I checked in Pix the render to texture looks reasonably fine, only thing I am not sure about it when I tilt the camera, I will try the method you mentioned Matt and post the results.

One thing though Matt, you said I am transforming the camera by the reflection, surly this is what I want to do so I can get a view projection that is reflected in order to render the geometry as a mirror? Or do you mean I should only be applying the reflection matrix to the geometry and leaving the camera matrix/view projection alone?

Share this post


Link to post
Share on other sites
Hey Matt, you were right about not transforming by the camera matrix... seems all the projective texturing is fine.

So for anybody who has the same problem in the future:

Instead of passing in the reflection matrix (transformed by the camera) like I was above


//Construct our reflection matrix
D3DXMATRIX reflect;
D3DXMatrixIdentity(&reflect);
reflect(1,1) = -1.0f;
reflect = reflect * world; //World matrix for the geometry we want to mirror
hr = effect->SetMatrix("ReflectMatrix", &reflect);



And then in the shader, obviously transform using the reflection matrix

//Vertex Shader
float3 WorldPosition = mul( float4(IN.Position, 1.0f), ReflectMatrix );
OUT.Position = mul( float4(WorldPosition, 1.0f), ViewProjMatrix );



Also before doing the render, you have to set your Cull Mode state to either CW or CWW depending on which way your orignal geometry is culled... otherwise you will get your geometry rendered inside out onto the texture.

Thanks to Matt for spotting the error.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this