Friday, February 22, 2008
Nope, no engine updates today. Instead I'll give you a website recommendation.
If you're a bit weird like me, that is, you rather read graphics papers than fiction before you go to sleep, you probably already have this one in your bookmarks.
Ke-Sen Huang keeps an index of all papers available online from every academic graphics conference worth it's name.
I'm yet to find a good rescource that lists all papers and presentations from more commercially oriented conferences like GDC. Feel free to share your own bookmarks :)
Wednesday, February 20, 2008
I've added soft shadows to the engine. I use Percentage-Closer Soft Shadows (PCSS), described in this paper. It differs from regular PCF in that a "blocker-serach" step is used to approximate a shadow penumbra size. The estimated penumbra size is then used to control the filter size. It's not real penumbra shadows but it looks quite convincing.Believe it or not, but until now my engine had no support for normal mapping. Now it does. The dynamic indirect lighting is also affected by the normal maps.
Time for the screenshots:
Note the green light that is reflected from the wall (not visible) onto the scene.
The scene is also lit by an enviroment map.
Friday, February 08, 2008
I got the indirect lighting to work correctly. There were some stupid bugs in my SH code. In the screenshots I use a 3x3x3 grid of sampling points (see last post) and one bonce of indirect light. There is also a (very) small constant ambient term so that no surfaces are completely black. Combined with SSAO it looks quite nice.
The scene is simple and HDR is deactivated so that the lighting effects is more apparent.
Friday, February 01, 2008
Each reflective object has it's own cube enviroment map. I support multiple bounces by spreading out the cube map updates over a number of frames. This means there can be some subtle "popping" in the reflections. Acceptable for my application.
I now support 64 or 128 bit HDR rendering. Pretty standard stuff where I do tone mapping based on image luminance. Of course there is also a bloom filter (as if we're not tired of that one by now;))
One of the biggest drawbacks with deferred shading is the lack of support for multisample antialias (at least with DX9). The usual thing to do is to hack antialias by performing an edge detection filter and blurring the image only on the edges. It's a dirty hack but it works quite well.
Dynamic indirect illumination
This is a variant of this paper. In short, I partition the world into a uniform grid, and at each grid point I capture the incident radiance field. This is done by rendering a cube map and then projecting it to spherical harmonics coefficients. The coefficients are stored in a number of volume textures. When rendering the frame, SH cofficients representing the incident radiance at each pixel are fetched from the volume texture and used to approximate the incident diffuse lighting at each pixel.
Right now there are some problems with my implementation but I'll solve that soon ;)
At last, the mandotary screenshot:
Thursday, January 10, 2008
I've done quite a lot of non graphic stuff. I've improved the engine code here and there and I've added picking for example.
On the graphic side, I've added support for cube maps and thus omidirectional shadows. All lights now also supports gobos, i.e. color textures that are projected from the lights. There is also support for reflections, but I'm still working on dynamic ones.
Scenes with a lot of lights also means a lot of shadow maps. For this reason, I've implemented a shadow map queue. When a shadow map needs an update it's added to the queue and every frame a number of entries in the queue are removed and processed. So only a small number of shadow maps are updated each frame. This of course means that there can be some noticable shadow lag when objects are moved around. For the type of application I have in mind for this engine, that is acceptable.
Monday, December 03, 2007
Since I have no new cool visuals to show, I'd thought I should blog about some random tech-topic. So lets talk about vectorization in shaders. Doing this in your HLSL code can improve the compiled code significantly. For example, a naive implementation of my bilateral boxfilter looks something like this:
With the ps2_b profile, this compiles to:
This is an example of bad vectorization. The shader compiles to 151 instructions of witch 124 is arithmetic. The problem is that many instructions (like pow and abs) are not used with full power. Many instructions are SIMD instructions and can work on multiple data in parallel.
We can rewrite this shader to perform some of the arithmetic's in parallel like this:
This compiles to:
This time there is 108 instructions of witch 81 arithmetic.
In this shader, when calculating the weights, more work is done per instruction. For example, the pow instruction is used only three times instead of eight. The summation of weights are done with two add and one dp4 instead of nine add.
Note that we could have vectorized the texture coordinate calculations as well, but then we would need SM 3.0 (arbitrary swizzles) and change how the offset constant is set up.
With a small effort we got rid of 43 ALU instructions! It should be noted that this necessarily won't lead to a speed-up since instruction count is just part of the story. ALU/Texture instruction ratio, texture cache etc. comes in to play as well. On my Radeon X1600 this shader is limitied by texture lookups so the win is not that big.
At last I would like to point out that I'm by no means a shader optimization guru, just a guy trying to fill his blog ;)
Thursday, November 29, 2007
I've not been able to work much on the engine the last week since I've been busy with school projects.
Some things have been done though. I've updated the deferred rendering system to work with light volumes instead of full-screen quads. This alone provides a huge speedup as long as the lights are reasonably small. This also made me think about light attenuation. Funny enough, this thread at gamdev popped up today. As discussed in the thread, I also wanted to find a way to set a maximum radius for a light, without affecting its atenuation too much. After some playing around with Maple, I found that max(0, 1-1/maxRadius*x)/(1+k*x^2) does the job quite good (this function is suggested in the thread) . I implemented it in my lighting shaders and the result is fine. I also took the opportunity to shave of a few instructions.
Here are some screens:
I've also ordered a AMD HD3870. While slightly slower than the Nvidia 8800GT, it's slightly cheaper and most importantly: it's available ;)