Tuesday 23 November 2010

Progress on the Main Game UI

A really brief update on the UI that will be used in the gameplay screen. Nothing very special to report, I am working my way through XNA and I must admit that while some stuff is extra cool, some bits are getting a bit annoying like trying to use the SpriteBatch class with custom effect. This is more complex than it should be and although you can find some way around the issues and it is rather documented on te web, you just get the feeling that it could be easier than that. It is woth mentionning that I am still using XNA 3.1 and maybe these issues are fixed in 4.0. I'll upgrate to the latest version a some point in time but so far I am glad to be able tu keep using VS 2008 as I am really used to it (XNA 4.0 doesn't install on pre VS2010 to my knowledge).
Also, I am getting a bit worried by the performances, mainly because of the gaussian blur shader that I use in a few places. I could repalce that by a Poisson disk blur filter which I may do after the game is implemented. The way I use the SpriteBatch also seems really inefficient so hopefully there will be plenty of room for optimization without struggling that much.

Here is a video of how it looks so far:


-m

Friday 19 November 2010

More work on the UI

Some visual improvements, plus another, more complex UI page.
This is all coming along very well and I am uite pleased and excited :)


-m

Monday 15 November 2010

First version of the Game UI

I have been working on the UI system for my XNA game since most of the added value will be a neat presentation layer. I came up with a fairly simple UI system that builds up on my state machine class I talked about last time. The whole thing is rather straightworward to use. Here is a quick video of it in action:



One of the interesting thing about this UI framework is the ability for any widget to specify its neighours, so when the focus moves, the UI page can figure out who should recieve the focus. Here is a snippet from the UIWidget class which is base for all widgets:

   public class UIWidget : StateMachine
   {
       ...
       public UIWidget LeftNeighbour
      {
           get;
           set;
       }
      public UIWidget RightNeighbour
       {
           get;
           set;
       }
       public UIWidget UpNeighbour
       {
           get;
           set;
       }
       public UIWidget DownNeighbour
       {
           get;
           set;
       }
       ...
   }

Widgets are laid out on UIPage objects. A UIPage keeps track of the focussed widget and processes pad inputs. When recieving a pad message, it picks the right neibour from the focussed widget and transfers focus to it. Note that multiple controls can have the same neighbour for a particular direction, so you can create rather complex layouts with a bit of work.

That's all for today!

Friday 12 November 2010

C# State Machine class

For my little XNA game that I am developping at the moment, the main thing I needed was a simple Finite State Machine class that I could use as the basis for prtty much any game object, especially for all the GUI and GameState logic.

I didn't want to spend too much time on a framework or grab one of the many libraries available here and there and then spend some time learning how to use it. Instead, I had the feeling that using the reflection capabilities of C#, I could easily and quickly come up with a simple piece of code that would fulfill my needs for this project. Functionnality-wise, my inspiration was Steve Rabin's article about a set of C++ macros for writing simple state machines. I used them quite a lot in the past and liked the fact the simple feature set, perfectly suited for small scale projects.

Basically, a State Machine can be in a certain number of differnt states and transition from one to another. Each state has:
  • an Enter() function callled when this state becomes active. This is the perfect place to do per-state setups
  • an Update() function that should be called once per frame
  • an Exit() function, called when leaving a state for another one. This is the perfect place to do some cleanup before leaving the state
State and handlers are defined via a simple naming convention that applies everywhere:
   StateName__Handler(...)


As a quick example to make that obvius, let's have a look at the Default state (which does nothing at all):
   public virtual void Default__Enter(string _OldState){}
   public virtual void Default__Exit(string _NewState){}
   public virtual void Default__Update(GameTime _GameTime){}



On top of that, each state can define message handlers for any message it wants to support. Message are defined by a simple string. For instance, the handler for a message called TakeDamage in the Default state and parametrized with an amount of damage points would imply the following bits:

   public virtual void Default__TakeDamage(int _Damage)
   {
      Health -= _Damage;
   }

And game code would send the message like this:
   Target.ProcessMessage( "TakeDamage", 10 );

As you can see this is all really simple. But here comes the goodness :)
  • You can have handlers that handle the same message differently per state:
   public virtual void Default__TakeDamage(int _Damage)
   {
      Health -= _Damage;

   }

   public virtual void Invincible__TakeDamage(int _Damage)
   {
   }
  • You can derive a state machine class from an existing class and override handlers so they do different things:
   class Soldier : StateMachine
   {
      public virtual void Default__TakeDamage(int _Damage)
      {
         Health -= _Damage;

      }
   }

   class SoldierFragile : Soldier
   {
      public virtual void Default__TakeDamage(int _Damage)
      {
         Health -= _Damage * 5;

      }
   }

The implementation might be rather simple and compact but it'still quite powerfull as you can see.

However, nothing is perfect in this world and I am sure some design choices are arguable ... but they suit my needs so I'm fine with it. I think the major concerns would be:
  • Weak state referencing as it is all done by strings and naming convention. So if you write typos or rename stuff around, this is likely to break. More error handling could be added but ultimately, this is just a string and this is rather fragile.
  • State specific variables will live at instance scope, not state scope. This is because I want to be able to acces the state machine members from anystate (this reduces the nb of accessors and stuff you need to write)
If you are interested in giving it a try or looking how it is done, you can find the source code with a stupid test case here. Note that I personally use it with XNA but this is rather generic and could be used without XNA. In fact, the provided implementation doesn't use XNA although it is straightforward to adapt it. In XNA, the State machine class should derive fron GameComponent.

Feedback welcome !

-m

Wednesday 10 November 2010

Another project !

I've been thinking quite a lot about what's motivationg me in writing code and games at home, as this is also what I do for a living (lucky me!). More specifically I tried to analyze why I statrt lots of projects and rarely finish any of them. Long story short, I think it all boils down to me being more interested in writing nice code and developping a nice tech that creating a fully finished game with it as the ratio of time spent on thinking about tech vs game is probably 20:1 ... All that is great and I've learnet and keep learning a lot from this "R&D" but this doesn't provide the rewarding feeling of having completed something entirely (which is a really really nice one - I've expereienced it twice recently when finishing the development of Enslaved - Odyssey to the West and its DLC)

So to break that cycle, I want to start working on a project that has the opposite characteristics of my usual projects:
  • Not technically challenging, so there is no opportunity to get sidetracked/lured by interesting problems to solve
  • Design is simple, achievable end well established, so again there is not a lot of fiddling around with tons of ideas before getting a grasp of what thet game I want to make is all about
  • Added value is in the final product being neat and polished
  • Not attached to its codebase. This is a weird one but over the years, I realized that if I write a C++ engine for a game, I get really attached to the codebase and want to make it as neat and well architectured as can be - certainly because I have this long term project of coming up with some tech that is full-featured enough for XBLA-scope projects. On the other hand, I tend to consider code written in any other language as some discardable one-off thing where I wont bother spend ages polishing code to death. Consequently, I'll write this new project in C# / XNA so I can get it done quickly, because the language is inherently efficient and because I won't be too bothered to hack things around when needed. (Moreover, I think there are a lot of lessons to learn from the XNA architecture that I could apply in my C++ engine)
  • A 1 person project. I don't want to depend on anyone nor have people depending on me for this project. No that peaolpe I have been working with on other stuff are a problem - I love them and they are skilled/reliable/etc ... but I just want to try something different this time. This mean almost no art/anim etc as I can do basic stuff but that's it :) I am also looking forward to the music/sound bit as this will bridge my passion for code/games and playing music :)
I have my mind set on what this project will be and the best way to sum that up is: "a remake of Picross with a neat interface a-la PS3's crossmedia bar" ... More details in my next post.

In the meantime, take care !

-m

Thursday 2 September 2010

Material Editor Prototype

It's been a couple of weeks since my last post, mostly because I've been quite busy at work, but also because I reached a point in my work on the Light PrePass renderer where I need to sleep on it for a bit so I can then clean the code and improve what I have (this is how I do most of my refactor ... write stuff, stop and think aboutit, refactor/remove code/make it nice ... then rince, repeat).

In the meantime, I started working on the future Material Editor that I will need when the renderer is up ad running. I want a node-based editor a la UnrealEd or other graphical shader editors. And having this king of graph editor would be handy for other stuff like animation trees, visual level scripting tool (a la Unreal Kismet), state machines, etc ...

My toolchain is written mostly in C# (I'll develop the link Engine/Editor in a future post) so writing GUI is not as bad as the usual C++/MFC nightmare. Moreover, I found a superb 2D drawing library called Piccolo.NET a few years ago and its concept of Zoomable User Interface (ZUI) is exactly what I needed for this project. After a few days of work, I have a first version of the GUI running with some underlying graph model behind it. It supports Undo/Redo via a bunch of undoable commands that modify the graph Model. Modifications of the Model generate events that the UI hooks onto and mirror.

I'll give more details about the internals when the code design gets a bit more stable as it is still in early stages, but I am really pleased with the result so far.

Time to conclude with a screenshot :)

Thursday 12 August 2010

Light PrePass: Neon Lights !

A couple of days ago I was wondering what kind of new light types I would be able to model with the Light Prepass renderer that I wouldn't be able to implement easily with a standard forward renderer...

I came up with the simple idea of neon lights I could model with a line segment and a radius of influence. The main algorithm would be to find for each fragment the closest point on the neon segment which is easily done in the pixel shader :

float4 findClosestPointOnSegemntFromPoint(
    float4 vA,        // start of the neon segment
    float4 vB,        // end of the neon segment
    float vP          // point to light    )
{
    float4 dir = normalize( vB - vA );      // direction vector of the segment
    float len = distance( vA, vB );         // length of the segment

    float t = dot( (P - vA), dir );         // distance of the closest point P on the seg from the origin
    float normalized_t = t / len;           // points belonging to the segment will be in [0;1]
    normalized_t = saturate( normalized_t );// discatding points not belonging to the segment

    float4 vClosestPoint = vA + dir * len * normalized_t;        // Closest point !
   
    return vClosestPoint;
}

 Then I simply use this point as if it was the source of a point light. The results are actually quite nice:



The main issue will be to cast shadows from this type of lights but I can probably live without.

In conclusion, deferred rendering is definitely cool!

Tuesday 10 August 2010

Light PrePass: Light Pass done.

A screenshot that shows the different type of lights supported in the light pass for now:


- A directional light (purple) with an ambient component (dark blue)
- A red point light, with an inner radius
- A blue point light
- A yellow spotlight, with an inner angle
- A green spotlight

The next step is now the material pass - combining this light information with every object's material info.

Saturday 7 August 2010

Light PrePass: Spot Lights !

This one will be a brief post, just wanted to share the first 2 spotlights of the renderer :)
Here they are:


Just need to add a nice angular falloff and this is good to go ... (and I should maybe make a nicer test scene because this one is really ugly)

-m

Friday 6 August 2010

Light PrePass Renderer update

I resumed working on the light prepass renderer, trying to solve a few issues before adding more features to it.

The first thing was to use a sphere mesh for point lights instead of a fullscreen pass, in order to dramatically cut down the fillrate requirements. A fullscreen pass would still be faster if the camera is inside the light but on a general case, I assume that this case will be rare and didn't implement a special case for it (I might add that as an optim if needed later on).

For that to work I had to change the shaders a bit because the view space position reconstruction code only worked for fullscreen quads. I currently use the VPOS HLSL semantic to get the screen position of the current pixel and from there compute proper UV and ray vector. This works well but I would prefer not to rely on VPOS so I'll fix the shaders later on to generate the screen positions myself in the vertex shader.


Next thing I noticed is that it makes things simpler to only draw the backface triangles of my sphere as this works even if the camera is inside the light (all that is kinda similar to the old shadow volumes issues, Carmack's reverse, etc ...). Another issue may rise when the sphere gets clipped by the far plane. To fix that, I added the following line to the vertex shader that transforms his geometry:

    VS_OUTPUT main_LPP_PointLight( VS_INPUT _Input )
    {
        float4 vScreenPosition = mul( float4(_Input.vPosition, 1), g_mWorldViewProj );
   
    vScreenPosition.w = vScreenPosition.z;
        output.vPos = vScreenPosition;
        return output;
    }

This projects any vertex that is behind the far plane on the farplane and caps the hole that would have resulted in far clipping parts of the mesh. This is achievd by making sure that z/w = 1 all the time. Again, this used to be a shadow volume trick I think ...

Then, I found another artefact that I had to fix, cf the image below:



This time the culprit was the depth target generated during the geometry pass. Basically, the buffer was cleared to 0, which would map all the pixels to the far plane value ... creating a sort of solid wall at the end of the view frustum. And if a light got close to the far plane, it would start to light these pixels. The fix for that was to be able to discard pixels that were not written during the geometry pass. Ideally clearing the target with a value of -1 would be ideal but this is not supported by the Clear() method available in DX9 as the value gets clamped in the range [0;1], To simulate that a simple trick is:
  • Clear the depth buffer to 0
     Device::GetInstance().Clear( ClearFlag_All, 0x00000000, 1.0f, 0 );
  • store the depth in [1;2] instead of [0;1] in the geometry pass output
     PS_OUTPUT main_LPP_GeometryPass( VS_OUTPUT _Input )
     {
          ...
          output.RT0_Color = -_Input.vPosition.z / g_vProjectionAttributes.w + 1;     
          ...
     }
  • subtract 1 to the value we read back from the depth target. if this pixel was written, we get a nice depth in [0;1]. If not, we get -1 and we can clip this pixel 
     float4 main_LPP_PointLight( PS_INPUT _Input ) : COLOR0
     {
          ...
          float    depth = tex2D( g_tDepthBuffer, uv ).x;              
         depth = depth - 1;
         clip( depth );
          ...
     }

With these fixes, I thing I'm good with the basics for the point lights and most of it should be applicable to spot lights as well ... Back to work !

Sunday 1 August 2010

Memory Leaks

Yesterday, I spent some time trying to fix any memory leak I could find. This is the kind of things that I like to check regularly as it is a massive pain when you do it after it's not been done in a while. More importantly, leaks are often a good indicator that areas of code require more design and code quality attention so that's always worth keeping an eye on that.

There are several ways to track memory leaks and there is already a lot of tools available and web articles on this subject. I will probably have a look at more advanced solutions in the future but for this session I used a really basic yet powerful method. The CRT library that ships with Visual Studio has some debug functionality to help track leaks down. Basically the allocator can track all the allocations that were made and that were not deallocated before exiting the application. This is done by adding a single line at the very beginning of your entry point function (you can put it anywhere really but you really want that call to happen as early as possible so you can start tracking allocations):

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

If you happen to have memory leaks, after closing the app, you should see in the Output window of Visual Studio something that looks like that:

Detected memory leaks!
Dumping objects ->
{2221} normal block at 0x08FE63D0, 164 bytes long.
 Data: <                > D4 88 1A 10 FF FF FF FF FF FF FF FF 00 00 00 00
{2191} normal block at 0x090771C8, 164 bytes long.
 Data: <                > D4 88 1A 10 FF FF FF FF FF FF FF FF 00 00 00 00
{2079} normal block at 0x09077590, 164 bytes long.
 Data: <                > D4 88 1A 10 FF FF FF FF FF FF FF FF 00 00 00 00
{2047} normal block at 0x08FD9918, 164 bytes long.
 Data: <                > D4 88 1A 10 FF FF FF FF FF FF FF FF 00 00 00 00
{469} normal block at 0x08FE5F98, 164 bytes long.
 Data: <                > D4 88 1A 10 FF FF FF FF FF FF FF FF 00 00 00 00
Object dump complete.

This is the list of all the allocated memory blocks that were not deallocated. Notice the number in the brackets at the beginning of every block - that's where things get interesting :) This number is an identifier for this particular memory allocation. The good thing is that there is another function you can use at the very beginning of your app to break into the debugger whe
n that specific allocation happens, so you can work out why there is no deallocation and fix the issue :

_CrtSetBreakAlloc( 2221 ); // Breaks in the debugger when alloc id=2221 is made !

This is not as lean as using some tools like BoundsChecker or more advanced debug functionnality you can embed in your software but it comes out of the box - on windows at least. I find that if you have it turned on all the time and regularly check your log output, then you can fix the leaks as soon as they appear and keep an application that is stable memorywise.

Thursday 29 July 2010

Texel to Pixel Centers ... and a Splash screen !

After a pretty intense period at work, things are nicely settling down and I found some time to work on my various things on the engine during the last couple of days.

I mainly worked on some ground work inside the resource management code in order to make sure I can create any type of resource using the serialization/reflection code but also by simply providing a block of data in memory, independently of where the data is coming from. This sounds pretty simple and obvious but enforcing that for all types of binary resources gives you a nice and flexible code architecture and makes things more separated and testable.

About the renderer, I noticed some rendering artifacts on the light pass and started investigating where this was coming from. I first suspected issues with my shader code as I am no expert but it turns out that the culprit was a well known fact about D3D9: Texel to Pixel centers misalignement. Instead of me attempting to explain the issue and solution, here is the official page from D3D9's online help about that matter:
http://msdn.microsoft.com/en-us/library/bb219690%28VS.85%29.aspx

And here are 2 shots, the left one showing the artifacts and the right one showing the result once the bug fixed:


Finally, I spent some time looking at how threads are implemented in C#, what is the interface exposed to the user etc ... As a simple way to use that knowledge, I implemented a splash screen for the editor, that is updated in a separate thread. Nothing particularly hard here but I am really pleased with the result ... probably the best my somewhat limited artistic talent can produce:



That's all for today, hoping to find more time to spend on adding more stuff to the renderer and then move on.

Saturday 17 July 2010

Busy times ...

Not of a lot of updates lately as I've been spending most of my time and energy at finishing the game I work on in my company. Lots of work but this is a very interesting moment and another opportunity to learn a lot.

I'll get back to my engine as soon as we are done :)


-m

Tuesday 22 June 2010

Light PrePass in the editor

I made some fixes so I can have more than 1 light and their contribution nicely accumulates in the light buffer. Moreover, I fixed some minor bugs so I can use all that in my editor and move the camera and lights easily. It's not that much but I'll just put a screenshot :


I hope I'll have some more time this week to work on point and directional lights as well as improving the point lights (by drawing a 3D sphere or a 2D billboard instead of a fullscreen quad). And also more time to posts details about all that, with code snippets maybe :)

-m

Lessons learnt while writing shaders

I wrote more shader code over the past week than I ever did before that, and there are several things I learnt while doing so about that. I thought that might be useful to share that even if some are straightforward or just common sense.

First of all, PIX is your friend. I repeat: PIX is your friend! Make sure you can run this tool with your app and get the vertex and pixel shader debugging features working, this is invaluable... That being said, PIX is a little bit whimsical at times so you need to make sure that your app is complian with PIX, ie:
  • Shaders are compiled in debug mode so you don't have to debug the assembly output but your actual code. This is done by passing D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION as flags to D3DXCompileShader(...). 
  • Having 0 warnings while compiling your shaders improves stability
  • If you experience troubles, you can try switching to softvare vertex processing or using the reference device (whis is going to be super slow but helps catching some bugs)

Next thing is about 3D maths and how it is done on computers - both CPU and GPU... There are many reasons why maths can go wrong down the chain if you're not careful. The kind of questions I tend to ask myself to try and prove me wrong and then eventually right when I write 3D maths includes:
  • Which coordinate system this Matrix/Vector is into?
  • Should I do Matrix * Vector or Vector * Matrix ??
  • Should I use this Matrix or it's inverse? Transpose?
  • Is it Z-up or Y-up?
  • Is it a left handed or right handed coordinate system?
  • In that float4, what should the W component be?
Regarding the last bullet point on homogenous coordinates, I tend to use float4 over float as much as I can. I find it clearer especially when vectors and positions are stored in textures. By doing so, you minimize the number of .xyz that suffixes your variable when doing float4->float3 or the float4( vec, 0 or 1) when you do float3->float4 ... So basically, I pull the needed data from the shader inpu and textures info float4s and then try to stick on working with those and not mixing types too much. I still need to investigate the performance implications but my early tests tend to show that the shader compiler is really good at optimizing all that.

I'll probably post separately about lots of 3D maths quirks so I'll have that reference material somewhere in a reliable place.

-m

Monday 21 June 2010

Work in progress

After posting the previous ticket, I started hacking my previous forward renderer in order to implement a first draft of the new rendering loop. I generally think that even when you worked through the theory, you always end up experiencing a lot of small issues that arises while you implement you idea. That's why I wanted to quickly get my hands dirty and face the actual practical problems.That's how I learn :)

Here is a screenshot of what I have so far:



The scene features a character in bind pose and a simgle point light, placed in front of its waist. The main view is still empty as the Material Pass is not done yet, but at the bottom, you can see some debug output of GBuffers 0, 1 and 2, storing depth, normals and light preview (ie. diffuse + diffuse*specular^8) respectively.

Following is a sort of log going through various bugs/issues I had to solve. I extensively used PIX for debugging the shaders. It was very unstable because of bugs in my rendering code. Switching to the reference rasterizer allowed me to fix those bugs. In turn, the stability of PIX has improved significantly, to a point where it is really reliable.

Default values in GBuffers:
GBuffer 0 stores the linear distance to camera for each pixel. This distance will be used in lighting calculations. In order to avoid any artifact, pixel that are part of the void need to have a distance ideally equal to positive infinity. For that, and because this rendertarget is a R32F buffer, I clear it to 0x7FFFFFFF, which according to the IEEE standard is the greatest 32bits positive float value.

GBuffer1 stores the normal vector for each pixel, directly as float values. The ovious default value for this buffer is 0, so the normal will be initialized to a null vector for all the pixel that were not rendered during the Geometry Pass

Reconstructing the position from the Depth value:
I struggled quite a bit to get it right, only to realize that I had a blatant bug elswhere in one of the shaders ... That's where PIX come in handy!.. The main idea is to reconstruct the position using the depth and a ray vector that originates from the camera and passes through the current pixel. This ray can be deduced from the camera frustum corners. For that, I compute in the main app the vector that goes from the camera to the top right corner of the camera frustum. As I want this vector in view-space, it has coordinates looking like

cFrustumRayInfo = Vector3( dx, dy, 1 ) * FarDistance;

Then, in the Vertex shader, I use this vector (passed as a constant) and the clip-space position of the current pixel (which is always going to be in the [-1,1] range on both axis) to compute the ray that originates from the camera and passes through this pixel

output.vRay = float3( dx * clipspace.x, dy * clipspace.y, FarDistance );

This gets output to the pixel shader and thus interpolated per-pixel. In there, I sample the depth from the GBuffer0 filled in the Geometry Pass and I can reconstruct the position by doing

float4 vPosition = float4( depth * in.vRay, 1 );

I think that it is one of the best way to do t because that will either if you write a fullscreen quad or just portions of the screen. And depending the type of lights you're dealing with, you surely want to do both, as writing a fullscreen quad for a point light with a radius of 10 pixel is a bit of a waste, isn't it?


That's it, more stuff when'I ll be able to work further on :)

-m

Saturday 19 June 2010

Light PrePass Renderer

Over the past few weeks, I've been experimenting with various ideas for the renderer of my pet engine. I set my mind on the Light PrePass first described by Wolfgang Engel (http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html) because that methods looks really promising. And then I also had the opportunity to discuss that with a friend at work who is really knowledgable about all that and that finished to convince me :)

As I progress through the implementation of the renderer in my engine, I would like to keep a log of issues and solutions I came across. Mainly becausethere is a fair amount of documentation on the principle itself but not that many about the gritty details of the implementation - or at least, that doesn't cover all my questions so far, maybe because I'm not that experienced with deferred rendering and so on.

What follows is a breakdown of thing that are already implemented with some details about implementation choices and issues.

Render Passes:

The main idea is to have 3 (or 4) rendering passes:

  1. (Optionally,) A ZPrePass where objects are rendered in the ZBuffer only, without color information output thus enabling this pass to run twice as fast.
  2. A Geometry Pass, where GBuffers are filled with information like the position and normal vector of the geometry for each pixel
  3. A Light Pass, where light information for each pixel is calculated using the GBuffers from the Geometry pass
  4. A Material Pass where information from the 2 former passes plus per-object material parameters can be combined for generating the final color value for each pixel
GBuffers:

So the first thing to think about is, as stated in many documentation, how to organize output data into GBuffers so we use as less RenderTarget memory as possible without sacrificing flexibility and image quality.

Here is what I plan to use:

 Buffer        | Format        |     8 bits     |    8 bits     |    8 bits     |     8 bits       |
---------------+---------------+----------------+---------------+---------------+------------------+
 Depth/Stencil | D24S8         |                 Depth                          |    Stencil       |
 GBuffer 0     | R32F          |                    Linear Depth (View Space)                      |
 GBuffer 1     | G16R16F       |           VSNormal.X           |           VSNormal.Y             |
 GBuffer 2     | A8R8G8B8      |    Diffuse.R   |   Diffuse.G   |   Diffuse.B   | Specular Factor  |
 Back Buffer   | A8R8G8B8      |       R        |      G        |      B        |       A          |

Those buffers will be rendered as follows:

ZPrePass: Depth is output to the DepthStencil buffer. Nothing special here, apart from turning off the color output, to enable doubling the speed of this pass. This is done by calling
m_pDevice->SetPixelShader( NULL ); 
m_pDevice->SetRenderState( D3DRS_COLORWRITEENABLE, 0 ); // restore it by passing 0x0000000F
Geometry Pass: GBuffers 0 and 1 will be filled during the Geometry Pass. As suggested in many papers, instead of storing the position, I will store the depth with a full 32bits precision and then reconstruct the position from the depth and the view/proj matrices. For the normal vector, I only store 2 of the 3 channels and reconstruct it. Also I know that many techniques for packing/unpacking normals exists and have been discussed but I'll dig into that later on.

Light Pass: GBuffer2 will receive lighting information generated during the Light Pass. During this pass, the diffuse contribution of each light is simply accumulated. For the specular factor, as it is commonly done, I choose to discard color information and only store a modulation factor that will amplify the diffuse color. This can be inaccurate in some situations where the scene contains multiple lights with different colors and intensity but I'm happy to sacrifice that over memory usage. One thing I am not too sure of right now if the format I should use for that. If I output these values into a A8R8G8B8 buffer, I believe that these numbers will be clamped in the range [0, 1], preventing me from doing the lighting in HDR. I could use some trick and always normalize it in the [0,2] range a-la Unreal to fake the HDR but I'd really like to have a proper HRD [0, +inf [ range. I'll have to dig into that a bit more.

Optionally, I could also generate a Velocity buffer during the Geometry Pass, in order to be able to make a nice perpixel motion blur as a post-process. I'll leave that for now and will come back to it later.

Wrap up:

Right now, this is as far as I went. I need to do some ground work in my engine before I can start writing code and shaders for all that but I think I have enough info to start working on a draft implementation.

I still need to clear lots of things out, here's a list of questions I'll have to answer.

  • Which format for the Light Buffer if I want true HDR?
  • Depth in linear space instead of homogenous space?How does the hardware do the 'divide by w' and can this be an issue?
  • Effect of texture filtering when using these buffers?
  • Better way of storing normals?
  • Gamma space vs Linear space?
  • Is there something better than a traditional forward renderer for translucent geometry?
  • How to incorporate shadows in all that?

That's all for today !

-m

First Light

This is the innaugural post of this blog, where I intend to post mainly on game development related topics.

So, more content to come (I guess that it it how all blogs start but I don't care) :)

-m