3D Engine Abstraction Layer

August 24, 2008

So, as I mentioned the other day, I’ll be making a 3D engine specifically suited to technically simpler 3D games, such as indie developers might want to make. I’ve started working on this now, and there’s two major lessons I’ve learned over the years: 1) keep it simple, and 2) don’t add features you don’t need yet (also known as the KISS and YAGNI rules).

Many are the times when I’ve tried to keep things simple, but failed somewhere along the way – it’s so damn easy to overcomplicate things, and I’ve found that keeping it simple can at times be really hard.

There’s also been plenty of occasions when I have thought I’ve been keeping features at a minumum, while in reality I’ve been thinking too far ahead, and kept adding things I’ve anticipated that I’ll need further down the line. Only to end up with lots of bloat, and code I don’t really enjoy working with.

When I made the Pixie game engine, I managed to avoid most of those mistakes from the past, and I’ve ended up with a really nice, well structured engine, which is a joy to work with, so I’m determined to apply the same principles to the 3D engine.

In fact, Pixie is such a great codebase to work with, that I will build the 3D engine on top of it, which will allow me to use the same nice, clean infrastructure and platform abstraction layers.

So, my first task in making this 3D engine, is to add an abstraction layer for 3D hardware. It would certainly be possible to work with DirectX or OpenGL directly, but that has some serious disadvantages.  As I said in the previous post about this engine, I want it to be suitable for indie developers, and that means it should work on both Windows and OsX (as many self-publishing indies report a similar number of sales on OsX as they see on Windows, even though the Windows userbase is much larger).

I wouldn’t want to use OpenGL for a Windows game – that’s just asking for trouble, as many potential customers wouldn’t have suitable drivers to get OpenGL to work, and in that case would probably not even bother trying to get the demo to work. And you’d obviously not use DirectX on the Mac. Note that I won’t be supporting any fancy stuff such as Shaders – this will be strictly a Fixed Function engine, for ease-of-use, performance and, most importantly, compatibility.

Here’s the full abstraction layer for accessing 3D hardware, such as it is at the moment. I’ve only added functionality I actually need, not stuff I anticipate that I will need later on. When that time comes, I can decide whether it’s a must to have it, and then add it, or if it’s something I can live without, and just leave it.

platform_3d

As you can see, there’s not much in there. Functionality to create Vertex/Index buffers and Textures, set transformation matrices, specify dynamic lights, toggle a couple of renderstates and rendering indexed or non-indexed triangles.

The goal here have been to streamline the whole rendering API, to just a handfull of methods that I actually use, and to specify them in such a way that I would like to work with them, without attempting to conform to a specific API. At this point in time, anything outside of this would just be distracting and add bloat. I suspect though, that I will be adding a few more things to this down the line. Time will tell.

In the main abstraction interface above, there’s methods to create vertex/index buffers and textures. I’d like to show you what the interface for the index buffer itself looks like:

platform_3d_indexbuffer

Now, this one is actually very simple: you can "Bind" the indexbuffer, which essentially makes it the indexbuffer that will be used in the next calls to the Render method used for indexed primitives. The rest of the methods are used to fill the index buffer with index data values.

The vertex buffer is essentially the same, but with more accessors for the different components. Which components are available are specified by passing a combination of VertexFormat flags to the CreateVertexBuffer method (and are similar to the Flexible Vertex Format of DirectX, though not identical).

platform_3d_vertexbuffer

And last, for completeness, the interface for textures:

platform_3d_texture

Which again is similar, but here we pass an additional parameter to the Bind method, to indicate at which texture stage we want to use it.

The idea is to use these concepts in my higher level 3D engine code, so that it is independent of the actual rendering API used. I’m making a D3D9 implementation of this to start with, but will extend it to a DirectX3 version as well, for compatibility (to be used as a fallback on systems which doesn’t have a recent version of DirectX installed – means I have to get reacquainted with Execute Buffers… argh!), as well as an OpenGL version and a basic Software renderer (as the ultimate fallback for when there’s no 3D hardware).

Keeping the function set limited should make the work on the different versions a bit easier, which is a good thing :-)

6 Responses to “3D Engine Abstraction Layer”

  1. Mattias says:

    Thanks :-)

    Yeah, I’m going to keep working on it, and post here about my progress. I’ll put up the source for download once I’ve got something that is working and seems stable.

  2. Carlos Cardenas A.K.A. Necroside says:

    Nice work, hope to see it online soon.

  3. marcos machado says:

    hi mattias!i have a 1 or 2 questions :) you make uml diagrams before source code of yours game engines? if not, why? What you think about uml diagrams? and what games industry think about this?i like create uml diagrams in modeling process.. not only for me, but for all who try read my source code… i think: with diagrams is more easy understand the source and how stuff works…tks.. ciao :)

  4. Mattias says:

    Well, my take on this have changed a lot over the years. I learned UML a long time ago, and initially thought it was great, wanting to apply it all the time.

    When I started working in the games industry, I found that using UML wasn’t really appreciated – at many companies, I was the only one who knew how to read UML, so using them didn’t really help others to understand the code.

    Also, management was usually of the opinion that designing code before you started writing it was a waste of time, so they wouldn’t allow it. The irony of the that, is that they were actually right, but only because of the way they kept moving the goal posts all the time.

    You can’t use extensive design and planning up front if the requirements and specification change dramatically throughout the project.

    Now that I’m lucky enough to have left the games industry, I can of course decide things for myself, and I have a quite relaxed attitude towards design and planning.

    I’ve learned from experience, that the only thing that matters, is that you have a clear idea of the concept you’re currently implementing, along with a willingness to change and redo parts of your code when it no longer fits. It’s by far the most productive method for developing games.

    If you find that sketching a few UML class diagrams on a scrap of paper helps you visualize where you’re going with the code you’re working on at the moment, then by all means use it. But don’t go over the top designing things and making pretty diagrams – better spend that time keeping your code clean, neat and working well.

  5. Almir Bravin says:

    hi MattiasSorry to address a diferent question but why ” I’m lucky enough to have left the games industry ” isnt´a good area to be ?best wishesAlmir Bravin

  6. Mattias says:

    Well, it’s got its ups and downs. At many studios, you get to work a lot of overtime due to management screwups, and you generally don’t have much say in what the games should be like – you generally just write the code you’re told.That being said, there’s good studios as well, and when I was in the industry, I enjoyed some good, long stretches of just good fun (when I worked on Crackdown for example).

Leave a Reply