Search code examples
c#direct3dslimdx

Why does a valid Texture not reach the Shader? (Direct3D9)


Hello everyone I'm currently trying to create a deferred renderer for my graphics engine using c# and SlimDX. As a resource I use this tutorial which is very helpful eventhough it's intended for XNA. But right now I'm stuck... I have my renderer set up to draw all geometry's color, normals and depth to seperate render target textures. This works. I can draw the resulting textures to the restored backbuffer as sprites and I can see that they contain just what they are supposed to. But when I try to pass those Textures to another shader, in this case to create a light map, weirds things happen. Here's how I draw one frame:

public bool RenderFrame(FrameInfo fInfo){
    if(!BeginRender()) //checks Device, resizes buffers, calls BeginScene(), etc.
         return false;
    foreach(RenderQueue queue in fInfo.GetRenderQueues()){
        RenderQueue(queue);
    }
    EndRender(); //currently only calls EndScene, used to do more
    ResolveGBuffer();
    DrawDirectionalLight(
        new Vector3(1f, -1f, 0), 
        new Color4(1f,1f,1f,1f), 
        fi.CameraPosition, 
        SlimMath.Matrix.Invert(fi.ViewProjectionMatrix));
}

private void ResolveGBuffer() {
    if(DeviceContext9 == null || DeviceContext9.Device == null)
        return;
    DeviceContext9.Device.SetRenderTarget(0, _backbuffer);
    DeviceContext9.Device.SetRenderTarget(1, null);
    DeviceContext9.Device.SetRenderTarget(2, null);
}

private void DrawDirectionalLight(Vector3 lightDirection, Color4 color, SlimMath.Vector3 cameraPosition, SlimMath.Matrix invertedViewProjection) {
    if(DeviceContext9 == null || DeviceContext9.Device == null)
        return;
        DeviceContext9.Device.BeginScene();
       _directionalLightShader.Shader.SetTexture(
           _directionalLightShader.Parameters["ColorMap"], 
           _colorTexture);
       _directionalLightShader.Shader.SetTexture(
           _directionalLightShader.Parameters["NormalMap"], 
           _normalTexture);
       _directionalLightShader.Shader.SetTexture(
           _directionalLightShader.Parameters["DepthMap"], 
           _depthTexture);
       _directionalLightShader.Shader.SetValue<Vector3>(
           _directionalLightShader.Parameters["lightDirection"], 
           lightDirection);
       _directionalLightShader.Shader.SetValue<Color4>(
           _directionalLightShader.Parameters["Color"], 
           color);
       _directionalLightShader.Shader.SetValue<SlimMath.Vector3>(
           _directionalLightShader.Parameters["cameraPosition"], 
           cameraPosition);
       _directionalLightShader.Shader.SetValue<SlimMath.Matrix>(
           _directionalLightShader.Parameters["InvertViewProjection"], 
           invertedViewProjection);
       _directionalLightShader.Shader.SetValue<Vector2>(
           _directionalLightShader.Parameters["halfPixel"], 
           _halfPixel);

       _directionalLightShader.Shader.Technique = 
           _directionalLightShader.Technique("Technique0");

       _directionalLightShader.Shader.Begin();
       _directionalLightShader.Shader.BeginPass(0);
       RenderQuad(SlimMath.Vector2.One * -1, SlimMath.Vector2.One);
       _directionalLightShader.Shader.EndPass();
       _directionalLightShader.Shader.End();
       DeviceContext9.Device.EndScene();
}

Now when I replace the call to DrawDirectionalLight with some code to draw _colorTexture, _normalTexture and _depthTexture to the screen everything looks ok, but when I use the DrawDirectionalLight function instead I see wild flickering. From the output of PIX it looks like my textures do not get passed to the shader correctly:

pix_screenshot

Following the tutorial the texture parameters and samplers are defined as follows:

float3 lightDirection;
float3 Color;
float3 cameraPosition;
float4x4 InvertViewProjection;
texture ColorMap;
texture NormalMap;
texture DepthMap;

sampler colorSampler = sampler_state{
Texture  = ColorMap;
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter= LINEAR;
MinFilter= LINEAR;
MipFilter= LINEAR;
};

sampler depthSampler = sampler_state{
Texture  = DepthMap;
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter= POINT;
MinFilter= POINT;
MipFilter= POINT;
};

sampler normalSampler = sampler_state{
Texture  = NormalMap;
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter= POINT;
MinFilter= POINT;
MipFilter= POINT;
};

Now my big question is WHY? There are no error messages printed to debug output.

EDIT:

the rendertargets/textures are created like this:

_colorTexture = new Texture(DeviceContext9.Device,
            DeviceContext9.PresentParameters.BackBufferWidth,
            DeviceContext9.PresentParameters.BackBufferHeight,
            1,
            Usage.RenderTarget,
            Format.A8R8G8B8,
            Pool.Default);

        _colorSurface = _colorTexture.GetSurfaceLevel(0);

        _normalTexture = new Texture(DeviceContext9.Device,
            DeviceContext9.PresentParameters.BackBufferWidth,
            DeviceContext9.PresentParameters.BackBufferHeight,
            1,
            Usage.RenderTarget,
            Format.A8R8G8B8,
            Pool.Default);

        _normalSurface = _normalTexture.GetSurfaceLevel(0);

        _depthTexture = new Texture(DeviceContext9.Device,
            DeviceContext9.PresentParameters.BackBufferWidth,
            DeviceContext9.PresentParameters.BackBufferHeight,
            1,
            Usage.RenderTarget,
            Format.A8R8G8B8,
            Pool.Default);

        _depthSurface = _depthTexture.GetSurfaceLevel(0);

EDIT 2:

The problems seems to lie in the directionalLightShader itselft since passing other regular textures doesn't work either.


Solution

  • The answer to my problem is as simple as the problem was stupid. The strange behaviour was caused by 2 different errors:

    1. I was just looking at the wrong events in PIX. The textures we passed correctly to the shader but I didn't see it because it was 'hidden' in the BeginPass-event (behind the '+').
    2. The pixel shader which I was trying to execute never got called because vertices of the fullscreen quad I used to render were drawn in clockwise order... my CullMode was also set to clockwise...

    Thanks to everyone who read this question!