Window Management
To be able to make use of OpenGL in C# at all, we need some sort of wrapper around the C interface of the API. While there are alternatives, the most popular choice is probably OpenTK, the Open Toolkit library.
The library provides a low level wrapper around OpenGL, allowing us to use all its features. It also includes a large amount of useful mathematical types, including vectors and matrices which are a key element in computer graphics.
Further, it includes cross-platform window management, allowing us to run the exact same code on any platform without having to worry much about creating windows and handling associated events.
In fact, the only thing we have to do to create both a window, and an OpenGL context to render with is create an instance of OpenTK’s GameWindow
class, and call its Run()
method.
To allow for our own behaviour, we will subclass the class. We will give some default parameters in our base constructor call to make sure the window and context are initialised correctly, and then call the Run()
method in our programs static Main()
.
Basic OpenGL calls
To access any kind of OpenGL functionality, we will use OpenTK’s static GL
class. There are several different versions of it, and which one you want to use depends on the platform you are targeting.
If, like us today, you are going for Windows/Mac/Linux then you should use the one in OpenTK.Graphics.OpenGL
.
The most basic things we can do are:
- show the version of the context that we created using
GL.GetString()
; - set the size of our viewport to the same size as our window in
GameWindow.OnResize()
usingGL.Viewport()
(you need to do this to see anything); - clear the screen before rendering our frame, and swapping the backbuffer afterwards using
GL.ClearColor()
,GL.Clear()
, andGameWindow.SwapBuffers()
.
Adding these things our class looks as follows.
If you are familiar with OpenGL, you may notice that we are using virtually the same commands that one would use in a C++ or C application.
GL.GetString()
instead of glGetString()
, etc.
This pattern is true for almost the entire OpenGL API in OpenTK, making it not only easier to use when switching from pure OpenGL, but also allowing us to easily look up the documentation of any GL call online.
10 comments
Thanks a lot for writing this! It’s a really nice post and clearly explains the basics of OpenGL. I really want to do some stuff in OpenGL – mainly because XNA feels kinda quirky sometimes – and this is a great kickstart.
As to other subjects, one thing I am particularly interested in would be gpu particles, and since you used them in RF (pretty extensively to say the least) I figure you’d know enough about them to do a post about it ;)
Thanks, and keep the good stuff coming!
Luca
Thanks Luca!
I will definitely be posting about those particles and lots of other topics.
There is already a rough write-up regarding the particles on the Roche Fusion devlog: http://rochefusion.com/devlog/239/from-thousands-to-millions-of-particles
But I will definitely do a more low-level post with an example in the future!
Thanks again, and be sure to let me know how it goes if you look into OpenGL.
Yay triangles! :D http://i.imgur.com/IhaM4mR.png
I figured it’d be best to simply follow the turotial step by step, and that went quite well I think.
I did find myself looking for methods that weren’t defined yet though. For example with the ShaderProgram, you add the GetAttributeLocation and GetUniformLocation methods after you use them. Not too big a deal however, and I figured it out quite quickly ;) It also really helped to have the complete example project and your library on GitHub for reference or looking something up. It’s nice that by following this you not only teach the basics but create a simple framework while doing so, which is minimalistic yet really useful.
It is interesting how much more freedom you have in comparison to XNA :O even though that also means you have to do a bit more work. However once you have a basic framework (like this) set up that helps a lot. It takes quite some getting used too, but I’ll probably spend most of my upcoming spare time on OpenGL now ^^.
You got me hooked :) Thanks again!
PS: I also read the particle post, really interesting stuff! And the GPU particle system doesn’t look as complicated as I feared :P Still, a full post or even tutorial on that would be cool :)
Perfect. I have been looking for OpenGL + C# + GLSL since many months and finally. Thank you. I will just follow each and every. my #version 140 is it ok? . I haven’t tried your code so far but I will do. Hope you will be creating from the basic and with the same Good Explanation and I have just started learning this, hope you will stay with us. Thank you.
Hey,
I’m glad to hear this post is useful for you!
#version 140
is for GLSL version 1.4, which comes with OpenGL 3.1 (very confusing version combinations!)That should work fine for most things, but there is very little hardware that supports exactly OpenGL 3.1
Older (very old really) hardware tends to go up to 2.1, and almost everything else at least supports 3.2, or newer.
So I usually use
#version 150
which comes with OpenGL 3.2That also works better on non-windows platforms (especially Mac OSX) which can be more picky about what OpenGL version you try to use.
Hope that answers your question.
In either case, let me know if you have any other questions! :)
You don’t seem to talk about the potential pitfalls or challenges related to determining the size of a buffer and the offsets of data in it. You have the size of a ColouredVertex hard-coded at (3+4)*4, but doesn’t this assume that the compiler is aligning members of the struct in a particular way? If you attempt to use sizeof(ColouredVertex) you’ll get a compiler error that talks about why the size of this structure may not be constant. Isn’t this a potential problem?
Hey Benjamin,
You’re right that getting the struct size right is very important. If something goes wrong with that, you get lots of crashes in the worst, and something like the following in the best case:
I did not go over that here to keep things relatively brief, though.
As you say, their is no guarantee for the compiler to actually use what seems the most obvious memory layout, unless you force it to do so, using
StructLayoutAttribute
(though .NET seems to do so in most cases, while Mono is somewhat less predictable). For example[StructLayout(LayoutKind.Sequential, Pack = 1)]
would always result in the ‘obvious’ memory layout.Regarding the size, we also do not have to rely on hardcoding. While
sizeof()
indeed does not work for structs, we can useSystem.Runtime.InteropServices.Marshal.SizeOf(typeof(TVertex))
to get the size at runtime.So as you rightly say, there a bunch of things here we can do wrong, but these are by no means problems we cannot work around (and relatively easily so).
Hope that answers your questions! :)
I’m a little lost as to how i could use any of this as to generate a texture or sprite. Heck even a movable object (Vector).
Though, i only say any of this because i am very new to C# and OpenTK. I moved from ActionScript 2 to AS3 to Haxe and now i’m trying to go for the “Real” programming languages and i’m kinda lost here and there when it comes to just making a movable object (Like a movie clip with some texture or what-not).
Sorry, guess i’m just really a noob when it comes to things way outside my comfort zone and this is the first post i’ve seen on this website during my quest of trying to find a OpenTK tutorial that doesn’t rely on immediate mode (Since i heard it’s for all intents and purposes: slower, limiting and basically bad in a sense and i didn’t want to rely on unity for… various reasons) but… isn’t there at least some way to translate all this into generating a sort of content pipe for vector and bitmap graphics or any form of texture and object other than just triangles (which apparently seems to be the most popular shape to make in most tutorials i’ve seen).
Sorry if i’m rambling on, just trying to figure out how to basically generate a texture using a png or jpg image at least and movable and rotatable object with all this since i’m really new to OpenTK :)
This is a pretty big question, and there is no way I can make the time to answer it fully, but here are some thoughts and pointers:
In general:
It sounds like the problem isn’t so much OpenTK/OpenGL, but that you haven’t worked on this low level before. To be able to work with OpenGL, you need a decent understanding of graphics pipelines, linear algebra, and best practices. You can of course fill in the gaps and learn all these things, but it’s a lot of work, and maybe going with something like Unity, MonoGame, or whatever that takes some of this off of your shoulders might be a good middle ground (but of course this is entirely up to you).
Some more specific things:
– In the end, triangles are pretty much everything we render these days. If you want a rectangle: two triangles. If you want a more complex shape, whether 2d or 3d: bunch of triangles.
– For 3d stuff, we would use transformation matrices to move around the 3d geometry per object, for 2d stuff, it’s usually easier to just create the rectangles/quads (from two triangles each) each frame for all sprites.
– Applying textures to a quad is not that hard, but it does involve a bunch of steps you have to get right: loading the texture, uploading it to OpenGL, binding it to the shader program (using uniforms – a good thing to look up), and sampling it in the shader program from UV coordinates you pass with your vertices.
Here is some code related to sprite drawing in my OpenTK graphics library:
https://github.com/amulware/awgraphics/blob/master/src/amulware.Graphics/Core/Texture.cs
https://github.com/amulware/awgraphics/blob/master/src/amulware.Graphics/Core/surfaces/settings/TextureUniform.cs
https://github.com/amulware/awgraphics/blob/master/src/amulware.Graphics/Sprites/Simple/Sprite2DGeometry.cs
https://github.com/amulware/awgraphics/blob/master/data/shaders/uvcolor_vs.glsl
https://github.com/amulware/awgraphics/blob/master/data/shaders/uvcolor_fs.glsl
For a relatively small program (and I’m sure there are better examples, but here is one of mine I can think of) that renders an image:
https://github.com/amulware/generidgamedev-localised-crepuscular-rays
As you can see, it’s not trivial. It took me years until I was really confident working with all this on such a low level.
Anyways, I hope this helps!
Thank you so much for the reply. Yeah, i’ll look into the links you sent me and do more research on stuff related to such levels.
I’ve also attempted to look at Monogame but i do wish to learn OpenGL so it’s more of a side project for now and i’d rather not use Unity as it feels more restrictive than just making my own application/engine/user interface from the very core (I have made a physics engine quite a few times based on Classic Sonic Physics and managed to get them to be very accurate, optimized and non buggy so…).
Thanks again.