Hipolipolopigus's picture

[Resolved] Issues rendering a 2D GUI (Or anything 2D for that matter) over a 3D "Scene"

Hi everyone,

I've been working with OpenTK for 2D graphics for a while now, and I've decided to start fiddling about with 3D. I'm confident with 2D graphics, but 3D adds a whole new dimension of complexity (See what I did there? :P)

I'm trying to render a 2D GUI over a 3D "scene" (Not even sure that I'm doing THAT correctly to be honest...) however it appears that whenever I apply the 3D camera/projection matrices, the 2D GUI is not able to render at all. Here's the code for initializing 2D (Where Parent is a class which inherits GameForm and Size is Parent.Size);

            GL.LoadIdentity();
            GL.Viewport(0, 0, Size.X, Size.Y);
            GL.MatrixMode(MatrixMode.Projection);
            GL.Scale(2.0, -2.0, 1.0);
            GL.Translate(-0.5, -0.5, 0.0);
            GL.Scale(1.0 / (double)Size.X, 1.0 / (double)Size.Y, 1.0);
 
            GL.Enable(EnableCap.Blend);
            GL.BlendEquation(BlendEquationMode.FuncAdd);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

Which works fine, it renders the 2D texture without any problems. Until I attempt to add 3D with its' own Initializing method (Which is from the "Immediate mode" example from the OpenTK source);

            GL.LoadIdentity();
            GL.Viewport(0, 0, Size.X, Size.Y);
            GL.MatrixMode(MatrixMode.Projection);
            double aspect_ratio = Size.X / (double)Size.Y;
            OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)aspect_ratio, 1, 64);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref perspective);
 
            Matrix4 lookat = Matrix4.LookAt(0, 5, 5, 0, 0, 0, 0, 1, 0);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref lookat);;

And then the code to draw the 3D Scene (Which also works fine without the 2D side of things);

GL.Begin(BeginMode.Quads);
 
            GL.Color3(System.Drawing.Color.Silver);
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
 
            GL.Color3(System.Drawing.Color.Honeydew);
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
 
            GL.Color3(System.Drawing.Color.Moccasin);
 
            GL.Vertex3(-1.0f, -1.0f, -1.0f);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
 
            GL.Color3(System.Drawing.Color.IndianRed);
            GL.Vertex3(-1.0f, -1.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
 
            GL.Color3(System.Drawing.Color.PaleVioletRed);
            GL.Vertex3(-1.0f, 1.0f, -1.0f);
            GL.Vertex3(-1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
 
            GL.Color3(System.Drawing.Color.ForestGreen);
            GL.Vertex3(1.0f, -1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, -1.0f);
            GL.Vertex3(1.0f, 1.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 1.0f);
 
            GL.End();

In the end the program ends up working in the following order;

Clear(Color and Depth)
Init 3D
Draw Cube
Init 2D
Draw Sample Texture
Swap Buffers
Loop

TL;DR: Mixing 2D and 3D results in nothing but the ClearColor, whilst they both work separately.

Can anybody point out anything that's going awry? 3D is quickly becoming frustrating!

Cheers,
Morgan

EDIT: Resolved using;

Init2D()
{
GL.Viewport(0, 0, Size.X, Size.Y);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0.0, Size.X, Size.Y, 0.0, -1.0, 1.0);
GL.MatrixMode(MatrixMode.ModelView);
GL.LoadIdentity();
 
GL.Enable(EnableCap.Blend);
GL.BlendEquation(BlendEquationMode.FuncAdd);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
}

And

Init3D()
{
GL.Viewport(0, 0, Size.X, Size.Y);
GL.MatrixMode(MatrixMode.Projection);
double aspect_ratio = Size.X / (double)Size.Y;
OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)aspect_ratio, 1, 64);
GL.LoadMatrix(ref perspective);
GL.MatrixMode(MatrixMode.Modelview);
Matrix4 lookat = Matrix4.LookAt(0, 5, 5, 0, 0, 0, 0, 1, 0);
GL.LoadMatrix(ref lookat);
}

Thanks to KryThorne ^^


Comments

Comment viewing options

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

You typically want to disable depth test and back face culling when rendering 2D stuff. Remember to turn them back on when you start rendering 3D. Also turn off blending for 3D.

Hipolipolopigus's picture

Okay, thanks for that heads-up. I can now render the 3D scene at the same as the GUI without any adverse effects on the scene. Still no GUI visible, unfortunately.

KryThorne's picture

Some of these calls are coming in the wrong order - You're loading an identity matrix before you've actually set which matrix to work with.

The 2D code should really be setting up an orthographic projection(?).

The 3D code is setting the matrix mode to Projection when it's already on such, plus loading an identity matrix then loading it's own matrix over such needlessly.

I suspect the reason they're working separately is they're working on top of reasonable default settings.

For now for the 2D code block try this at the top:

GL.Viewport(0, 0, Size.X, Size.Y);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Scale(2.0, -2.0, 1.0);  //Not sure about these 3 lines to be honest. GL.Ortho may work better here
GL.Translate(-0.5, -0.5, 0.0);
GL.Scale(1.0 / (double)Size.X, 1.0 / (double)Size.Y, 1.0);
GL.MatrixMode(MatrixMode.ModelView);
GL.LoadIdentity();

And for the 3D code try:

GL.Viewport(0, 0, Size.X, Size.Y);
//Setup projection
GL.MatrixMode(MatrixMode.Projection);
double aspect_ratio = Size.X / (double)Size.Y;
OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)aspect_ratio, 1, 64);
GL.LoadMatrix(ref perspective);
 
//Setup model view
GL.MatrixMode(MatrixMode.Modelview);
Matrix4 lookat = Matrix4.LookAt(0, 5, 5, 0, 0, 0, 0, 1, 0);
GL.LoadMatrix(ref lookat);

I'm admittedly writing this without testing, but it's hopefully a nudge in the right direction. If you can get these two working separately they should cooperate with one another.

Hipolipolopigus's picture

... Permission to kiss your feet...? I've been trying to work this out for a couple of days, thanks! :D

And no luck with GL.Ortho, I think I'll just stick to these lines for now :]

KryThorne's picture

No problem, glad it worked!

As for Ortho.. Hmm.. The way you're setting up 2D at the moment what are the screen bounds you're going for? If I'm reading things correctly I think you're aiming for the topleft of the screen to be 0.0, 0.0 and the bottomright to be 1.0, 1.0?

Hipolipolopigus's picture

It should be TL as {0,0} and BR as {Size.X, Size.Y}, just makes it far easier to know exactly where things are, at least that's the way I think I've done it (and the way it works haha)

KryThorne's picture

Curious! I'd say replacing those three lines in the 2D code with:

GL.Ortho(0.0, Size.X, Size.Y, 0.0, -1.0, 1.0);

But that might be me being a bit too optimistic!

Hipolipolopigus's picture

Mhm, it looks like the Ortho method did it :D

Another thing that's a bit weird is the camera rotation (Definitely did something wrong there too! ); it'll look around, but It appears to look left and right parabolically >_< Not sure whether to make another thread about it or recycle this one -__-'