March 08, 2007

Prototyping a renderer in seven days - Rendering

Last post I talked about an experiment I made to prototype a renderer under a short deadline. This time I'll continue on this and explain how I did the rendering.

Rendering

Since this was to be done in seven days I didn't have time to go fancy with the rendering. It had to be quickly implemented, simple and at the same time fast.

The easiest to achieve better performance in 3D rendering is find the functions that are the most expensive (processing wise) and to modify the code to call them less often. In Direct3D those are the device's change state functions. So I set this as a requirement when I created the renderer and this was in fact the only real optimization made on the rendering system.

SceneDatabase class

This class contains the structure that represents the scene in memory. The scene was constructed in a tree form made to reduce automatically the calls to the change states functions. Each node of the tree represented settings to send to the renderer prior to the rendering itself.

Tree nodes were created for specific simple attributes : Materials, Transforms, Renderables. Material nodes contained information related to the material of the object to render whether it was a texture, an effect (shader) or colors. Transform nodes were the world transform to apply before rendering the object. Finally, Renderable nodes were used for all the meshes to render to the screen.

To minimize cost of the change state functions the nodes were set according to their cost. Under the root of the tree were the Materials which will cost more and you need to optimize, next were the Transforms and then the Renderables.




RenderQueue, RenderOperation, Renderer classes

Those are the three classes (with the SceneDatabase) that form the core of the rendering system. The renderer queries the SceneDatabase for a list of objects to render, this was implemented using the RenderQueue class. The RenderOperation class contained all the information for what I'd call a "unit of rendering".

The render operation (RenderOperation) was formed of a Material, Transform and Renderable which were previously queried in the SceneDatabase. In other words all the information needed to render a mesh was present.

The RenderQueue is a structure mostly designed to contain a list/vector of RenderOperations. The SceneDatabase, by its design already sorts the RenderOperations by Materials. Here, the RenderQueue could sort them by other factors implemented in a way that resembles the function that some of the std containers have that acts like operators used for sorting.

What went wrong

Nothing was really wrong, since this was meant for simplicity I was avoiding a lot of problems. The only real problem I got there was the problems I got with the content pipeline, I didn't have loadable content to test the rendering part until the last hours. Testing and debugging weren't done so there is probably a lot of buggy code due to the fact I was doing my midterms at the same time and had a lot of homework (I was also sleepy in the last hours I worked on this project).


What went right

This was designed for simplicity and I kept it simple until the end. The only thing that complicates the design is the RenderQueue and RenderOperation classes which were there because of the requirement to minimize the number of calls to the Direct3D device.

How to improve the design

The design was lacking a lot of feature I'd like to see in an engine. Mostly I'd drop the fixed pipeline and use shaders everywhere I could leading to a code that could be easier to bring to newer grounds (like DirectX 10).

I'd also add scene partitioning structures like quadtrees/octrees to structure so it would be easier to implement some features that requires spatial information on the scene (ex.: collisions).

March 01, 2007

Prototyping a renderer in seven days - Content Pipeline

In the last days I did a small experimentation on prototyping : prototyping a 3D renderer as complete as it could be in seven days but as I was overloaded by homeworks and exams (midterm) I didn't forced it to be seven consecutive days. It took me around two weeks to complete the experiment and have a basic prototyped renderer.

The goals of the experiment were mostly to try new things that I had in mind but couldn't scale to the current design of what I was working on and to see what I could achieve under such a short deadline. In the next days I'll present what has been done during that experiment in a way that looks like a postmortem ;).


Content Pipeline

One of the thing I wanted to experiment the most is the content pipeline. I wanted something flexible/extensible to drive all the content of the game, something that would be easy to read and modify by artists. To achieve this I based everything on XML using the TinyXML library. All content objects were XML files describing all that is needed to load the resources.

Every content file was assigned to a loader for the resource to be loaded. Every content loader loads a IContent object which is a loaded resource and can be casted to its real type later.


The ContentManager class was designed to choose which loader to use to load a certain content file.


Once the content loader is created you need to register it with the ContentManager which will read the type of content its loading and the ID of the loader. It will use that information later during the loading to choose the right loader for the content (by using the loader ID in the content's XML file).


What went right

The concept itself was great : all the content the engine uses was data driven. In other words, if a game was using a content model which was called "models/monster" anyone could go and replace the mesh and texture that the content file was loading and the engine will just load those files instead (no need to recompile).

It's easy to add new functionalities to this system. If you need a loader that is not already there, just create a new class inheriting the IContentLoader class and register an instance with the ContentManager. Once the loader is registered the system is ready to load that new type of file.


What went wrong

Lack of time to make proper tools. Because of that I had to bypass the system and directly load the texture files and the mesh files. I wanted everything to be driven by the XML files, the ContentManager just loading XML files and using the proper loaders to load the content. Proper tools is probably the most important thing for easily integrating the content into the engine and seven days prototyping without any plan didn't allow me to work on tools (for example I had to rely on what is already available in the .X format for the models).


How to improve the design


Having a tool that creates packages (like pak of zip files). Creating the XML files for the content could be linked with that process and those could be part of the same archive. Using package files is often to solve performance issues and it should be an obligation for the release build but during the creation of the game the system should be able to load content from the folders directly.

Content hotloading would also be a great feature to add to the content manager to ease the job of the artists. Hotloading is done by monitoring the filesystem for changes and notifying the ContentManager of any changes in the loaded assets. The ContentManager then reloads the modified content and updates the other systems (like the scene object database).

February 11, 2007

First post

Hi,

Since this is my first post on this blog I guess I should talk about myself first. I'm 24 years old, currently doing my third year at university where I discovered a passion for graphic programming and image processing/analysis.

Like many others I'd like to work in the video games industry. I had two internships in a video game company where I was working on games soon to be released. There, I was also introduced to the process that leads to making and distributing a video games.

My interests are mostly about graphic programming, more specifically real-time rendering, and image analysis and processing. I'm currently working on my own 3D rendering engine that I wish it to become, with time, a great platform video games. I'm also looking to integrate the tools needed for machinima since this is something that interests me (probably my artistic side) and it's also getting more and more popular. I wish in the future to work on something for my other passion but my renderer takes all the spare time I have.

I created this blog with the intent to share and discuss my reflections about my interests whether its something that happened around me or something that came up working on my 3d engine. I might also talk about the work I'm doing for school or at home, I also see this like a developer log (if I see the need to talk about something). I'd also like to share knowledge by writing short articles about my new discoveries, designs or implementations.

Stay tuned for next episode...

JFF