I have a utility class for Framebuffer objects which i use to generate FBO's, bind them, render to them, and render them to screen as 2d textures.
When using this class, i can successfully make fbo textures, render to them, and render them to screen.
However, the colors seem messed up once i render them to screen.
What seems to be happening is that the color i set as drawing color ends up as the background color of the FBO (but only if i make an actual draw call after setting the color), and the drawing i made always ends up black.
What i am expecting based on my code, is a texture with a white background, and two small colored rectangles (one purple and one cyan) on them, drawn to the screen two times.
what i am getting is this :
a cyan background with two small black rectangles.
Source code follows :
FboRenderTexture.cs
public class FboRenderTexture : IDisposable
{
public int textureId = 0;
private int fboId = 0;
public int Width;
public int Height;
public FboRenderTexture(int width, int height)
{
Width = width;
Height = height;
Init();
}
//semi pseudocode
public void DrawToScreen(float xoffset = 0, float yoffset = 0)
{
if (textureId != -1)
{
GL.BindTexture(TextureTarget.Texture2D, textureId);
GL.Begin(BeginMode.Quads);
//todo : might also flip the texture since fbo's have right handed coordinate systems
GL.TexCoord2(0.0, 0.0);
GL.Vertex3(xoffset, yoffset, 0.0);
GL.TexCoord2(0.0, 1.0);
GL.Vertex3(xoffset, yoffset+Height, 0.0);
GL.TexCoord2(1.0, 1.0);
GL.Vertex3(xoffset+Width, yoffset+Height, 0.0);
GL.TexCoord2(1.0, 0.0);
GL.Vertex3(xoffset+Width, yoffset, 0.0);
GL.End();
}
}
private void Init()
{
// Generate the texture.
textureId = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, textureId);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
// Create a FBO and attach the texture.
GL.Ext.GenFramebuffers(1, out fboId);
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, fboId);
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt,
FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, textureId, 0);
// Disable rendering into the FBO
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
}
// Track whether Dispose has been called.
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// Clean up what we allocated before exiting
if (textureId != 0)
GL.DeleteTextures(1, ref textureId);
if (fboId != 0)
GL.Ext.DeleteFramebuffers(1, ref fboId);
disposed = true;
}
}
}
public void BeginDrawing()
{
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, fboId);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
GL.PushAttrib(AttribMask.ViewportBit);
GL.Viewport(0, 0, Width, Height);
}
public void EndDrawing()
{
GL.PopAttrib();
GL.Ext.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); // disable rendering into the FBO
}
}
usage
public class Buffers : CreativeSharp.core.CSInstance //inherits from OpenTK.GameWindow, adds some simple drawing stuff.
{
private FboRenderTexture buffer;
public Buffers() : base(800, 600, "buffers")
{
GL.Enable(EnableCap.Texture2D);
buffer = new FboRenderTexture(128, 128);
NoStroke();
this.Closed += Buffers_Closed;
}
private void SetupBuffer()
{
buffer.BeginDrawing();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GL.Color4(1f, 0f, 1f, 0f);
DrawRectangle(10,10, 30, 30);
GL.Color4(0f, 1f, 1f, 1f);
DrawRectangle(50, 10, 30, 30);
GL.Color4(1f, 1f, 1f);
buffer.EndDrawing();
}
void Buffers_Closed(object sender, EventArgs e)
{
buffer.Dispose();
}
public override void DrawContent()
{
SetupBuffer();
GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GL.Color4(1f, 1f, 1f, 1f);
buffer.DrawToScreen(0,0);
buffer.DrawToScreen(512,0);
}
public override void Update()
{
}
private void DrawRectangle(float x, float y, float w, float h)
{
GL.Begin(PrimitiveType.Quads);
GL.Vertex3(x, y, 0);
GL.Vertex3(x + w, y, 0);
GL.Vertex3(x + w, y + h, 0);
GL.Vertex3(x, y + h, 0);
GL.End();
}
}
Somewhat embarrassingly, the cause of my problems was that i was not setting white as drawing color before drawing the fbo's texture. This caused the colors to come out all wrong.