OpenGL in C# – an object oriented introduction to OpenTK

OpenGL and C# are two of my favourite technologies.

In this post I would like to give a small intro on how to develop games or other 3D accelerated applications using them together.

We will go over:

  • how to create a window with an OpenGL context that we can render to;
  • how to create vertex buffers, load shaders, and render vertices.

For the purpose of this post I will keep things as simple as possible. However, instead of writing a horribly hard-coded example, we will use proper object oriented design to abstract away a lot of the interface of OpenGL.

This will allow us to focus on the intended behaviour of our program, instead of getting lost in the OpenGL API.

I use the same approach for my own work with OpenGL, which has resulted in my comprehensive wrapper library amulware.Graphics, which is for example used in my game Roche Fusion.

The library is open source and can be found here. For the purpose of this post we will however start from scratch.

Further, I assume that you know the basics of C#, have a rough idea of how modern graphics pipelines work and what a shader is.

Index

Given the length of this post and the amount of code included, I split it up into several pages. Here are some links to quickly jump to the part you are interested in:

  1. Overview (this page)
  2. OpenTK, Window Management, Basics
  3. Vertex Buffer and Array Objects, Shaders, Vertex Attributes and Uniforms
    (the meat of this post)
  4. Putting it all together, Conclusion

Other links:

Why OpenGL?

Before we start, I would like to give a little context on why I like to use OpenGL.

The biggest argument I could make if I was trying to convince someone to use OpenGL is that it is the cross-platform graphics API. This may change over the next few years with the development of Vulkan, but for now OpenGL is used on Linux, Mac, mobile devices, as well as Windows.

The only real alternative, when working low-level, is to use Direct3D, the rendering API of Microsoft’s DirectX. However, DirectX is only supported on Windows, which seems to make the choice obvious.

While earlier versions of OpenGL are by now extremely outdated, the API was redesigned in 2008 for version 3.0. We will use none of the features deprecated and removed since then, and instead focus on OpenGL 3.0 and higher.

Support for those versions is rampant these days, with OpenGL 3.0 being available on AMD Radeon HD2xxx and higher, NVidia 8xxx and higher, and Intel integrated GPU’s since Sandy Bridge.

Virtually anything – barring very low-budget integrated chips – that can be bought today supports OpenGL 4.0 or higher.

Pages: 1 2 3 4

Leave a Reply

10 comments

  1. 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

    • Paul Scharf says:

      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 :)

  2. ozzyM says:

    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.

    • Paul Scharf says:

      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.2
      That 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! :)

  3. 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?

    • Paul Scharf says:

      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 use System.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! :)

  4. Dapo Olaleye says:

    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 :)