kl_mallory's picture

VBOs, FBOs, and Orthographical Projection Matrices! Oh My!

So I've been playing around with OpenTK, and I've looked thoroughly through the examples provided and some of the projects other people have contributed. I've decided to go forward and start building some proof of concept tests, and I'm having trouble right away with client side ortho projections. I've decided to exclusively use shaders and VBO's for everything, including 2D drawing. There are reasons for this, mostly because shaders allow for some really cool effects, and eventually I hope to find it faster overall to do things this way.
So I've noticed right away that I had to do things differently than most examples because just loading ortho for the Projection and an Identity Matrix for the ModelView caused nothing to render at all on the Framebuffer, which was strange because immediate mode examples worked. I guess this is because the vertex shader is resolving the model view matrix, but I'm not sure, I haven't found a lot of info on this. So I loaded the ModelView with an Ortho projection and the 2d test showed on the framebuffer via screenshot, but then failed to map the texture when drawing the texturecoords. So basically I still ended up with a blank screen. But even the frame buffer screenshot doesn't look right, it looks like I am only seeing a portion of the area I should be seeing and the amount of rectangle I see, seems to depend on the depth of the projection matrix??? Haven't figured that out yet.

I'm posting my code below, be be forewarned most of the setup is behind classes. I've flattened things out a bit for the sake of posting and things are kind of disheveled from trying different things but I'm an OO guy. SwapBuffers is in the Test GameWindow, not attached. I don't get any errors after linking, compiling, attaching, setting uniforms, or drawing arrays. So I'm stumped, and can't find much information on this.

If someone sees something wrong, right away with my code, or can point me too an article that really goes over this, that would be great. It really seems like most examples use immediate mode, and I'm kind of over that. So I'm trying to move forward with shaders, and I really like some of the effects I have created already. Hoping someone could help out, I really don't want to go back to DirectX. :-(

I'm new to OpenGL BTW. But I understand the basic concepts and have read many tutorials and I have 12 years prof managed programming under my belt.

BTW shaders tested in Render Monkey and Shader Designer, and seem to work fine. Thanks!

        protected Random rnd = new Random();
 
        public TestFrameBufferVbo(GameWindow gameWindow)
        {
            _gameWindow = gameWindow;
            _gameWindow.Resize += new EventHandler<EventArgs>(gameWindow_Resize);
        }
 
        //Called by "onLoad"
        public void Load()
        {
            InitializeComponents(this);
 
            SetVisible(true);
            SetActive(true);
        }
 
        protected void InitializeComponents(Components.Controls.IControl parent)
        {
            var shaderRepo = new ShaderResourceRepository(ShaderResources.ResourceManager);
 
            GL.ClearColor(Color.White);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            GL.Enable(EnableCap.DepthTest);
            GL.DepthFunc(DepthFunction.Lequal);
 
            GL.CullFace(CullFaceMode.Back);
            GL.Enable(EnableCap.CullFace);
            GL.Enable(EnableCap.Multisample);
 
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
 
            _colorShader = new SimpleFactory(shaderRepo).Create(_gameWindow.Context);
            _textureShader = new SingleTextureFactory(shaderRepo).Create(_gameWindow.Context);
 
            _cvbo = new ColorVertexBuffer(_gameWindow.Context);
            _tvbo = new TextureVertexBuffer(_gameWindow.Context);
 
            _frameBuffer = new TextureFrameBuffer(_gameWindow.Context, _gameWindow.Width, _gameWindow.Height);
 
            gameWindow_Resize(this, new EventArgs());
 
            NeedsRedraw = true;
        }
 
//notice I have to set the Ortho on both the projection and the modelview.in order to get anything on the framebuffer.
        void gameWindow_Resize(object sender, EventArgs e)
        {
            var w = _gameWindow.ClientRectangle.Width;
            var h = _gameWindow.ClientRectangle.Height;
 
            float aspectRatio = w / (float)h;
 
            Trace.TraceInformation(string.Format("Resizing ViewPort: width={0},height={1}", w, h));
 
            GL.Viewport(0, 0, w, h);
 
            //For some reason the further distance I set, the more rectangles show up on the frambuffer?
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, w, 0, h, -1, 1000);
 
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
            GL.Ortho(0, 1, 0, 1, -1, 1);
 
            NeedsRedraw = true;
        }
 
        void gameWindow_UpdateFrame(object sender, FrameEventArgs e)
        {
            Update(e.Time);
 
            NeedsRedraw = false;
        }
 
        void gameWindow_RenderFrame(object sender, FrameEventArgs e)
        {
            Draw(e.Time);
        }
 
        public void Update(double gameTime)
        {
            //Some helpful tutorials I've been looking at.
            //http://www.opengl.org/resources/faq/technical/transformations.htm
            //http://www.songho.ca/opengl/gl_transform.html
 
            if (!NeedsRedraw)
                return;
 
            GL.PushAttrib(AttribMask.AllAttribBits);
            {
                //disable this first, this will affect the viewport, and the matrix.
                GL.Disable(EnableCap.DepthTest);
 
                _frameBuffer.Use(); //Basically Use means "Bind"
                _colorShader.Use();
 
                GL.Viewport(0, 0, _frameBuffer.Width, _frameBuffer.Height);
 
                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
                GL.Enable(EnableCap.Texture2D);
 
                GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
                var buffer = new List<TextureVertex>();
 
                //these are the TexCoords I will use later.
                //wind them counter-clockwise according to vertex3f coords.
                buffer.Add(new TextureVertex(0, 1, 0, 0, 0));
                buffer.Add(new TextureVertex(0, 0, 0, 1, 0));
                buffer.Add(new TextureVertex(1, 0, 1, 1, 0));
                buffer.Add(new TextureVertex(1, 1, 1, 0, 0));
 
                _tvbo.BufferData(buffer);
 
                var vertices = new List<ColorVertex>();
 
                 // Basically for my test I am drawing a lot of rectangles on the framebuffer with alpha. "Blending" is enabled in the init.
                for (var i = 0; i < 10000; i++)
                {
                    var c = Color.FromArgb(rnd.Next());
                    var ca = Color.FromArgb(rnd.Next(0, 255), c);
 
                    var x = rnd.Next(50, _frameBuffer.Width - 150);
                    var y = rnd.Next(50, _frameBuffer.Height - 150);
                    var w = rnd.Next(50, (_frameBuffer.Width - x));
                    var h = rnd.Next(50, (_frameBuffer.Height - y));
 
                    //wind them counter-clockwise
                    //first triangle
                    vertices.Add(new ColorVertex(x, y, 0, c));
                    vertices.Add(new ColorVertex(x, y + h, 0, c));
                    vertices.Add(new ColorVertex(x + w, y + h, 0, c));
                    //second traingle
                    vertices.Add(new ColorVertex(x + w, y + h, 0, c));
                    vertices.Add(new ColorVertex(x + w, y, 0, c));
                    vertices.Add(new ColorVertex(x, y, 0, c));
                }
 
                _cvbo.BufferData(vertices);
 
                _cvbo.Use(); //also includes client state ColorBuffer and and VertexBuffer.
 
                GL.DrawArrays(BeginMode.Triangles, 0, _cvbo.Length);
 
                 //screen shot code from OpenTK example.
                _frameBuffer.Texture.ToFile(string.Format("TestFrameBufferVbo{0}", Guid.NewGuid()), gameTime);
 
                _cvbo.Disable();
            }
            GL.PopAttrib();
 
            _colorShader.Disable(); //Disabel is the same as "Bind" default.
 
            _frameBuffer.Disable();
 
            GL.Enable(EnableCap.DepthTest);
 
            NeedsRedraw = false;
        }
 
        public void Draw(double gameTime)
        {
            GL.PushAttrib(AttribMask.AllAttribBits);
            {
                //set this first, 
                GL.Disable(EnableCap.DepthTest);
 
                GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
                _frameBuffer.Texture.Use();
                _textureShader.Use();
                _textureShader.TexturingType = 2;
                _textureShader.SetTexture(_frameBuffer.Texture.TextureUnitOrdinal);
 
                GL.ActiveTexture(TextureUnit.Texture0);
                GL.Enable(EnableCap.Texture2D);
                GL.ClientActiveTexture(TextureUnit.Texture0);
 
                _tvbo.Use(); //also includes client state VertexBuffer and TexCoord.
 
                GL.DrawArrays(BeginMode.Triangles, 0, _tvbo.Length);
 
                _tvbo.Disable();
 
                var error = GL.GetError();
                if (error != ErrorCode.NoError)
                    throw new Exception(error.ToString());
 
                //Swap buffers is happening in the test game window after this call.
            }
            GL.PopAttrib();
        }
Inline Images
Framebuffer Screenshot of rectangles

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
kl_mallory's picture

Sorry, I guess I should include my vbo Use() code.

            GL.EnableClientState(ArrayCap.ColorArray);
            GL.EnableClientState(ArrayCap.VertexArray);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, Id);
 
            GL.ColorPointer(4, ColorPointerType.UnsignedByte, BlittableValueType.StrideOf(_colorVertices), new IntPtr(0));
            GL.VertexPointer(3, VertexPointerType.Float, BlittableValueType.StrideOf(_colorVertices), new IntPtr(16));

and my TextCoord buffer code...

            GL.EnableClientState(ArrayCap.TextureCoordArray);
            GL.EnableClientState(ArrayCap.VertexArray);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, Id);
 
            GL.TexCoordPointer(2, TexCoordPointerType.Float, BlittableValueType.StrideOf(_textureVertices), new IntPtr(0));
            GL.VertexPointer(3, VertexPointerType.Float, BlittableValueType.StrideOf(_textureVertices), new IntPtr(8));