Thursday, February 25, 2010
at
6:51 AM
|
I've begun working on light buffer generation. While tackling this, I realized my normal buffer generation isn't accurate. I'm using the view space normal compressed with only XY where Z is reconstructed. While using 16bit float keeps accuracy pretty well, we loose the Z's sign info and this does not bode well for us. The reason is that while for the most part Z is always positive facing, there is bound to be edge cases where it is not. Especially when we are using normal map to distort a surface's normal. So I begun a search to find if I could improve my normal buffer rendering. To my surprise, someone by the name of Aras did the homework for me. Thanks Aras! :)
Just so you know, I'm not a math junkie. So deciphering what was done within that page took me quite a good while. That said, I decided to pick two method out of the selection to test out; Stereographic Projection and Cry Engine 3 method. From what I understood, Cry Engine 3's method sacrifices the X, Y's accuracy for a very good Z value. Comparatively, Stereographic Projection produces more even distortion. However, since we're using two channel 16bit float g-buffer format, both data loss is pretty insignificant. After some testing, I came to the conclusion that both method produce almost 100% similar lighting. The difference is unnoticeable to the naked eye. Hence, I decided to use the cheaper of the two, which happens to be Stereographic Projection.
So.. Normal G-Buffer fixed!
Now, as we know, shadow casting is a very expensive process. So for the most part, we would want to avoid shadow casting. However this leads to one problem; light leaking. Given a light in a room, if light is not applied with shadow casting, the light will leak through the wall into the adjacent room. This becomes an ugly behavior. So how does one fix this? When using forward rendering, we had the flexibility of doing selective light masking. This worked very well for the case mentioned, but how do we bring it to the deferred model? From what I see, my best bet is to use the stencil buffer. However, I'm not quite sure how cheap stencil buffers are. From what I read, clearing stencil buffer is expensive. Also, stencil depth is only 8bits for any modern cards (being that the other 24bits are for depth buffer). Also, for fillrate optimization, we would want to mask out the depth bound of lighting volume for each local light we render. Hence, that would take up 1 bit of the stencil buffer, leaving only 7 for light grouping.
I am not familiar with stencil buffer and do not know exactly what kind of cost it would impose on rendering. But writing and switching stencil ref value during the G-Buffer rendering phase seems scary to me. I will have to keep setting the stencil ref value for each Renderable being rendered. From what I gather, the best way for me to implement this is to add a RenderObjectListener during the G-Buffer render state, then set the stencil ref value for each renderable in the callback. Then after G-Buffer mode is done, remove the listener. However, there is one issue with this. Since the callback is dealing with Renderable, I have no way to find out the light mask for that Renderable since the light mask is set in the MovableObject. As of now, I have no clue how to handle this.
Just so you know, I'm not a math junkie. So deciphering what was done within that page took me quite a good while. That said, I decided to pick two method out of the selection to test out; Stereographic Projection and Cry Engine 3 method. From what I understood, Cry Engine 3's method sacrifices the X, Y's accuracy for a very good Z value. Comparatively, Stereographic Projection produces more even distortion. However, since we're using two channel 16bit float g-buffer format, both data loss is pretty insignificant. After some testing, I came to the conclusion that both method produce almost 100% similar lighting. The difference is unnoticeable to the naked eye. Hence, I decided to use the cheaper of the two, which happens to be Stereographic Projection.
So.. Normal G-Buffer fixed!
Now, as we know, shadow casting is a very expensive process. So for the most part, we would want to avoid shadow casting. However this leads to one problem; light leaking. Given a light in a room, if light is not applied with shadow casting, the light will leak through the wall into the adjacent room. This becomes an ugly behavior. So how does one fix this? When using forward rendering, we had the flexibility of doing selective light masking. This worked very well for the case mentioned, but how do we bring it to the deferred model? From what I see, my best bet is to use the stencil buffer. However, I'm not quite sure how cheap stencil buffers are. From what I read, clearing stencil buffer is expensive. Also, stencil depth is only 8bits for any modern cards (being that the other 24bits are for depth buffer). Also, for fillrate optimization, we would want to mask out the depth bound of lighting volume for each local light we render. Hence, that would take up 1 bit of the stencil buffer, leaving only 7 for light grouping.
I am not familiar with stencil buffer and do not know exactly what kind of cost it would impose on rendering. But writing and switching stencil ref value during the G-Buffer rendering phase seems scary to me. I will have to keep setting the stencil ref value for each Renderable being rendered. From what I gather, the best way for me to implement this is to add a RenderObjectListener during the G-Buffer render state, then set the stencil ref value for each renderable in the callback. Then after G-Buffer mode is done, remove the listener. However, there is one issue with this. Since the callback is dealing with Renderable, I have no way to find out the light mask for that Renderable since the light mask is set in the MovableObject. As of now, I have no clue how to handle this.
Posted by
Lf3T-Hn4D
2 comments:
When visualizing differences, it is often better to do ((val1 - val2) / 2) + 0.5 rather than just abs(val1 - val) to know what direction the error is in.
(also, if you didn't do abs(diff), you might've missed the negative differences in that pic)
Yes, I'm aware of that. :) The way I did that difference visualization is simply using Gimp's difference mode which is just a simple abs(val1 - val). Nevertheless, I think it's a good enough representation since the difference for the most part is only in the wrong Z value generated by the X&Y reconstruct Z method. Personally, I'm more concerned about how to handle light grouping efficiently.
Post a Comment