Mobile-D's picture

Trouble Getting Blending to Work

I'm new to OpenTK and fairly new to programming in general, so forgive me if the solution here is obvious. I'm trying to get some very simple blending to work. Everything I've been doing so far has been working with simple, un-textured primitives rendered in immediate mode. For simplicity's sake, I've tried to rework the StarterKit Gamewindow application to blend two triangles together, and I'm posting that simple code here.

In this example, I've only modified the OnLoad and OnRenderFrame methods.
Attached at the bottom is a screenshot of my output.

What am I missing to successfully enable blending?

// Released to the public domain. Use, modify and relicense at will.
 
using System;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
namespace StarterKit
{
    class Game : GameWindow
    {
        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game()
            : base(800, 600, GraphicsMode.Default, "OpenTK Quick Start Sample")
        {
            VSync = VSyncMode.On;
        }
 
        /// <summary>Load resources here.</summary>
        /// <param name="e">Not used.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
 
            GL.ClearColor(0.1f, 0.2f, 0.5f, 0.0f);
            GL.Enable(EnableCap.DepthTest); 
            GL.BlendEquation(BlendEquationMode.FuncAdd);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
        }
 
        /// <summary>
        /// Called when your window is resized. Set your viewport here. It is also
        /// a good place to set up your projection matrix (which probably changes
        /// along when the aspect ratio of your window).
        /// </summary>
        /// <param name="e">Not used.</param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
 
            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
 
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }
 
        /// <summary>
        /// Called when it is time to setup the next frame. Add you game logic here.
        /// </summary>
        /// <param name="e">Contains timing information for framerate independent logic.</param>
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
 
            if (Keyboard[Key.Escape])
                Exit();
        }
 
        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelview);
 
            GL.Begin(BeginMode.Triangles);
 
            GL.Color4(1.0f, 1.0f, 0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, 4.0f);
            GL.Color4(1.0f, 0.0f, 0.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, 4.0f);
            GL.Color4(0.2f, 0.9f, 1.0f, 1.0f); GL.Vertex3(0.0f, 1.0f, 4.0f);
 
            GL.Enable(EnableCap.Blend);
 
            GL.Color4(1.0f, 1.0f, 0.0f, 0.5f); GL.Vertex3(0.0f, -1.0f, 4.0f);
            GL.Color4(1.0f, 0.0f, 0.0f, 0.5f); GL.Vertex3(2.0f, -1.0f, 4.0f);
            GL.Color4(0.2f, 0.9f, 1.0f, 0.5f); GL.Vertex3(1.0f, 1.0f, 4.0f);
 
            GL.Disable(EnableCap.Blend);
 
            GL.End();
 
            SwapBuffers();
        }
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // The 'using' idiom guarantees proper resource cleanup.
            // We request 30 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
                game.Run(30.0);
            }
        }
    }
}
Inline Images

Comments

Comment viewing options

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

I think you're just lacking the GL.BlendFunc and/or GL.BlendEquation calls. Try messing around with those.

Mobile-D's picture
freethinker wrote:

I think you're just lacking the GL.BlendFunc and/or GL.BlendEquation calls. Try messing around with those.

Well, I called those functions in the OnLoad method of the program. Adding them to the rendering portion doesn't seem to affect anything.

freethinker's picture

My mistake. Maybe you need to alter the alpha channel by calling GL.Color4 on one or both of the triangles. People often disable the depth test before blending too.

Mobile-D's picture
freethinker wrote:

Maybe you need to alter the alpha channel by calling GL.Color4 on one or both of the triangles. People often disable the depth test before blending too.

Thanks for the feedback! Can you explain what you mean by 'alter the alpha channel by calling GL.Color4'? Or even better, show me a bit of a code example?

I've played around with disabling the depth test, and while I can see why it's often disabled, disabling it hasn't helped me out yet.

EDIT: I think I've figured it out!

 protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.BlendEquation(BlendEquationMode.FuncAdd);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
 
            Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelview);
 
            GL.Begin(BeginMode.Triangles);
 
            GL.Color4(1.0f, 1.0f, 0.0f, 1.0f); GL.Vertex3(-1.0f, -1.0f, 4.0f);
            GL.Color4(1.0f, 0.0f, 0.0f, 1.0f); GL.Vertex3(1.0f, -1.0f, 4.0f);
            GL.Color4(0.2f, 0.9f, 1.0f, 1.0f); GL.Vertex3(0.0f, 1.0f, 4.0f);
 
            GL.End();
 
            GL.Enable(EnableCap.Blend);
 
            GL.Begin(BeginMode.Triangles);
 
            GL.Color4(1.0f, 1.0f, 0.0f, 0.5f); GL.Vertex3(0.0f, -1.0f, 4.0f);
            GL.Color4(1.0f, 0.0f, 0.0f, 0.5f); GL.Vertex3(2.0f, -1.0f, 4.0f);
            GL.Color4(0.2f, 0.9f, 1.0f, 0.5f); GL.Vertex3(1.0f, 1.0f, 4.0f);
 
            GL.Disable(EnableCap.Blend);
 
            GL.End();
 
            SwapBuffers();
        }

This gives me the result I want. I think the important thing I was missing was to call a NEW GL.Begin(BeginMode.Whatever) after enabling blending.