Search code examples
c#openglframebufferopentk

Not able to render to a texture bound to a framebuffer


I am trying to set up a rendering pipeline, and as a result of this, i am trying to set up rendering to a texture so i can sample it later for blurring and the like.

I have a vertex shader that looks like this:

#version 400

//Heyy renderpasses
subroutine void RenderPass();
subroutine uniform RenderPass currentPass;

in vec3 ex_normal;
in vec3 ex_color;
in vec4 ShadowCoord;
in vec3 lightDir_cameraspace;
in vec3 normal_cameraspace;

layout(location=0) out vec4 color;
layout(location=1) out float depth;

uniform vec3 light_pos;
uniform sampler2D shadowMap;

void main()
{
    //Bootstrap for render pass
    currentPass();
}

//Render passes

subroutine(RenderPass)
void Default()
{
    //Config
    vec3 lightColor = vec3(1.0, 1.0, 1.0);
    float lightIntensity = 1.0;
    vec3 diffuseColor = ex_color;

    vec3 n = normalize( normal_cameraspace );
    // Direction of the light (from the fragment to the light)
    vec3 l = normalize( lightDir_cameraspace );

    float cosTheta = clamp( dot( n,l ), 0,1 );
    vec3 ambientLight = vec3(0.2, 0.2, 0.2);
    vec3 lightSum = ambientLight;
    float visibility = 1.0;
    float shadowSample = texture( shadowMap, ShadowCoord.xy ).z;

    float bias = 0.005*tan(acos(cosTheta)); // cosTheta is dot( n,l ), clamped between 0 and 1
    bias = clamp(bias, 0,0.01);

    if ( shadowSample  <  ShadowCoord.z-bias){ 
        visibility = 0.3;
    }

    color = vec4(ambientLight + (diffuseColor*visibility*lightColor*lightIntensity/*cosTheta*/), 1.0);

}

subroutine(RenderPass)
void Diffuse()
{
    color = vec4(ex_color, 1.0);
    depth = gl_FragCoord.z;
}

subroutine(RenderPass)
void Depth()
{
    depth = gl_FragCoord.z;
}

This works fine when rendering to the window/framebuffer 0. However, when trying to render to a custom set up framebuffer, which i have wrapped in a class for convenience like this:

    private GameWindow _gameWindow;
    private Texture _texture;
    private int _framebufferId;

    public Framebuffer(GameWindow window)
    {
        _gameWindow = window;

        _framebufferId = GL.GenFramebuffer();
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, _framebufferId);

        _texture = new Texture(GL.GenTexture());
        GL.BindTexture(TextureTarget.Texture2D, _texture.Handle);
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, window.Width, window.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, (IntPtr)0);

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);

        GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, _texture.Handle, 0);

        GL.DrawBuffers(1, new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0 });

        GL.DrawBuffer(DrawBufferMode.None);

        if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
            throw new Exception("Framebuffer creation failed");
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
    }

    public Texture Texture
    {
        get
        {
            return _texture;
        }
    }

    public void BeginDraw()
    {
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, _framebufferId);
        GL.Viewport(0, 0, _gameWindow.Width, _gameWindow.Height);
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
    }
    public void EndDraw()
    {
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
    }

The texture ends up black. Am i misunderstanding something about piping color data into the texture?


Solution

  • You set up the frame buffer correctly and you set up the color attachment and the draw buffer correctly, but than you specify the color buffers which are drawn into with DrawBufferMode.None.

    Delete this line:

    GL.DrawBuffer(DrawBufferMode.None);
    

    Note, since a frame buffer is bound GL.DrawBuffer will specify the color buffers, which are drawn into, of the bound frame buffer.

    The accepted answer to the question What does GL_COLOR_ATTACHMENT do? says:

    The default is GL_COLOR_ATTACHMENT0.

    So you can completely skip to specify the color buffer.