Hi,
I am implementing indexed deferred rendering engine according to Damian Trebilco's article from here:
http://lightindexed-deferredrender.googlecode.com/files/LightIndexedDeferredLighting1.1.pdf
In my case I don't want to make a geometry prepass and will therefore capture every single lights source on a view ray. This will allow me to draw lit transparent obejcts. We are building a top-down game so in our case we only need to support up to 8 lights sources and that's all. To implement this I am using the bit-shifting method of storing lights IDS, like described in aforementioned article. I will explain it as it is the main point of the question.
In order to store every lights that hangs on a view ray for a given pixel, their indices (from 1 to 255 max) are sent into shader as four 8-bits variables, where only the top 2 bits hold the value of the index. I split the value at the CPU level and divide the values by 254.5f before sending them to shader (I tried 256 but it produced more precision loss, switching to 254.5 I managed to store up to 4 lights on SOME hardware without data loss instead of 3). The shader simply outputs the four variables, but the magic happens when the alpha-blending kicks in, here is the formula:
source*one+destination*0.25.
Multiplying by 0.25 shifts the bits in the destination texture down one level in order to free space for the new value. The new value is then stored via addition.
In the subsequent forward shader the indices are decoded with the following code:
float4 packedLight = tex2D(LIndexSampl,TC);
#define NUM_LIGHTS 256
// Unpack each lighting channel
float4 unpackConst = float4(4.0, 16.0, 64.0 , 256.0) / NUM_LIGHTS;
// Expand the packed light values to the 0.. 255 range
float4 floorValues = ceil(packedLight * 254.5f);
for(int i=0; i< 4; i++)
{
packedLight = floorValues * 0.25f; // Shift two bits down
floorValues = floor(packedLight); // Remove shifted bits
float texCoord = dot((packedLight - floorValues), unpackConst);
The most recently written light gets retrieved first. The loop then proceeds to light the object by reading light parametersfrom a 256x1 texture using the retrieved texCoord as lookup coordinates.
But the problem is, I can only store up to 4 (and on some hardware only 3) lights before the data I have in the texture start deteriorating (r8g8b8a8 surface). That means that if I draw another light into the texture, the bits get messed up which means that in the forward shader i can retrieve a completely different value (not even close to the original - can't fix by simply storing 3 (and even 5) spaces in the light's parameters texture for each light). However, according to the article, this technique should be able to store up to 16 unique light indices (as I understood the author tried and succeeded with this) and, moreover, it should support any number of overdraws as older light indices should simply be pushed out by math rules to free space for the newer ones. I did try to use HdrBlendable texture format which theoretically should easily support up to 8 lights, but it had precicely the same problems.
What am I missing? Why is my data getting messed up? Anyone has ideas?
For anyone interested, here is my XNA 4 project, which supports up to 4 lights (sometimes :/). Please try it and write if 4 lights work for you:
https://drive.google.com/file/d/0B8dysKzeYPBQM1JmbGdIa0NjQmc/edit?usp=sharing
I am implementing indexed deferred rendering engine according to Damian Trebilco's article from here:
http://lightindexed-deferredrender.googlecode.com/files/LightIndexedDeferredLighting1.1.pdf
In my case I don't want to make a geometry prepass and will therefore capture every single lights source on a view ray. This will allow me to draw lit transparent obejcts. We are building a top-down game so in our case we only need to support up to 8 lights sources and that's all. To implement this I am using the bit-shifting method of storing lights IDS, like described in aforementioned article. I will explain it as it is the main point of the question.
In order to store every lights that hangs on a view ray for a given pixel, their indices (from 1 to 255 max) are sent into shader as four 8-bits variables, where only the top 2 bits hold the value of the index. I split the value at the CPU level and divide the values by 254.5f before sending them to shader (I tried 256 but it produced more precision loss, switching to 254.5 I managed to store up to 4 lights on SOME hardware without data loss instead of 3). The shader simply outputs the four variables, but the magic happens when the alpha-blending kicks in, here is the formula:
source*one+destination*0.25.
Multiplying by 0.25 shifts the bits in the destination texture down one level in order to free space for the new value. The new value is then stored via addition.
In the subsequent forward shader the indices are decoded with the following code:
float4 packedLight = tex2D(LIndexSampl,TC);
#define NUM_LIGHTS 256
// Unpack each lighting channel
float4 unpackConst = float4(4.0, 16.0, 64.0 , 256.0) / NUM_LIGHTS;
// Expand the packed light values to the 0.. 255 range
float4 floorValues = ceil(packedLight * 254.5f);
for(int i=0; i< 4; i++)
{
packedLight = floorValues * 0.25f; // Shift two bits down
floorValues = floor(packedLight); // Remove shifted bits
float texCoord = dot((packedLight - floorValues), unpackConst);
The most recently written light gets retrieved first. The loop then proceeds to light the object by reading light parametersfrom a 256x1 texture using the retrieved texCoord as lookup coordinates.
But the problem is, I can only store up to 4 (and on some hardware only 3) lights before the data I have in the texture start deteriorating (r8g8b8a8 surface). That means that if I draw another light into the texture, the bits get messed up which means that in the forward shader i can retrieve a completely different value (not even close to the original - can't fix by simply storing 3 (and even 5) spaces in the light's parameters texture for each light). However, according to the article, this technique should be able to store up to 16 unique light indices (as I understood the author tried and succeeded with this) and, moreover, it should support any number of overdraws as older light indices should simply be pushed out by math rules to free space for the newer ones. I did try to use HdrBlendable texture format which theoretically should easily support up to 8 lights, but it had precicely the same problems.
What am I missing? Why is my data getting messed up? Anyone has ideas?
For anyone interested, here is my XNA 4 project, which supports up to 4 lights (sometimes :/). Please try it and write if 4 lights work for you:
https://drive.google.com/file/d/0B8dysKzeYPBQM1JmbGdIa0NjQmc/edit?usp=sharing