Advertisement

Light Indexed Deferred Rendering - incorrect result

Started by September 04, 2018 08:15 PM
2 comments, last by AndreyVK_D3D 6 years, 5 months ago

Hi all!

I'm trying to implement the technique: Light Indexed Deferred Rendering. I modified the original demo:

1) Has removed some UI elements.

2)  Has removed View Space light calculation, 

3) I fill the Light indices during startup.

4) Optional: I tried to use UBO instead of Texture1D uncomment //#define USE_UBO

My modified version of demo

My implementation details:

I use the constant buffers instead of Texture1D for storing of the light source information. Instead of OpenGL, I use Direct3D11.

My implementation is divided on following parts:

1)  Packing of light indices for each light during startup:


void LightManager::LightManagerImpl::FillLightIndices()
{
	int n = static_cast<int>(lights.size());
	for (int lightIndex = n - 1; lightIndex >= 0; --lightIndex) {
		Vector4D& OutColor = lightIndices.push_back();
		// Set the light index color 
		ubyte convertColor = static_cast<ubyte>(lightIndex + 1);
		ubyte redBit = (convertColor & (0x3 << 0)) << 6;
		ubyte greenBit = (convertColor & (0x3 << 2)) << 4;
		ubyte blueBit = (convertColor & (0x3 << 4)) << 2;
		ubyte alphaBit = (convertColor & (0x3 << 6)) << 0;
		OutColor = Vector4D(redBit, greenBit, blueBit, alphaBit);
		const float divisor = 255.0f;
		OutColor /= divisor;
	}
}

2) Optional/Test implementation: Update lights positions(animation).

3) Rendering The Light source Geometry into RGBA RenderTarget (Light sources Buffer) using 2 shaders from demo:

Pixel shader:


uniform float4 LightIndex : register(c0);
struct PS {
    float4 position : POSITION;
};
float4 psMain(in PS ps) : COLOR {
    return LightIndex;
};

Vertex shader:


uniform float4x4 ViewProjMatrix : register(c0);
uniform float4 LightData : register(c4);
struct PS {
	float4 position : POSITION;
};
PS vsMain(in float4 position : POSITION) {
	PS Out;
	Out.position = mul(float4(LightData.xyz + position.xyz * LightData.w, 1.0f), ViewProjMatrix);
	return Out;
}

These shaders is compiled in 3DEngine into C++ code.

4) Calculating of the final lighting, using the prepared texture with light indices. The pixel shaders can be found in attached project.

The final shaders:

Pixel:


//
DeclTex2D(tex1, 0); // terrain first texture
DeclTex2D(tex2, 1); // terrain second texture
DeclTex2D(BitPlane, 2); // Light Buffer

struct Light {
	float4 posRange;		// pos.xyz + w - Radius
	float4 colorLightType;	// RGB color + light type
};

// The light list
uniform Light lights[NUM_LIGHTS];

struct VS_OUTPUT {
   float4 Pos:       POSITION;
   float2 texCoord: TEXCOORD0;
	float3 Normal:    TEXCOORD1;
	float4 lightProjSpaceLokup : TEXCOORD2;
	float3 vVec : TEXCOORD3;
};

// Extract light indices
float4 GetLightIndexImpl(Texture2D BitPlane, SamplerState sBitPlane, float4 projectSpace) {
	projectSpace.xy /= projectSpace.w;
	projectSpace.y = 1.0f - projectSpace.y;
	float4 packedLight = tex2D(BitPlane, projectSpace.xy);
	float4 unpackConst = float4(4.0, 16.0, 64.0, 256.0) / 256.0;
	float4 floorValues = ceil(packedLight * 254.5);
	float4 lightIndex;
	for(int i = 0; i < 4; i++) {
		packedLight = floorValues * 0.25;
		floorValues = floor(packedLight);
		float4 fracParts = packedLight - floorValues;
		lightIndex[i] = dot(fracParts, unpackConst);
	}
	return lightIndex;
}

#define GetLightIndex(tex, pos) GetLightIndexImpl(tex, s##tex, pos)

// calculate final lighting
float4 CalculateLighting(float4 color, float3 vVec, float3 Normal, float4 lightIndex)
{
	float3 ambient_color = float3(0.2f, 0.2f, 0.2f);
	float3 lighting = float3(0.0f, 0.0f, 0.0f);
	for (int i = 0; i < 4; ++i) {
		float lIndex = 255.0f * lightIndex[i];
		// read the light source data from constant buffer
		Light light = lights[int(lIndex)]; 
	    // Get the vector from the light center to the surface
		float3 lightVec = light.posRange.xyz - vVec;
// original from demo doesn't work correctly
#if 0
 		// Scale based on the light radius
		float3 lVec = lightVec / light.posRange.a;
		float atten = 1.0f - saturate(dot(lVec, lVec));
#else
		float d = length(lightVec) / light.posRange.a;
		const float3 ConstantAtten = float3(0.4f, 0.01f, 0.01f);
		float atten = 1.0f / (ConstantAtten.x + ConstantAtten.y * d + ConstantAtten.z * d * d);
#endif	
		lightVec = normalize(lightVec);
		float3 H = normalize(lightVec + vVec);
		float diffuse = saturate(dot(lightVec, Normal));
		float specular = pow(saturate(dot(lightVec, H)), 16.0);
		lighting += atten * (diffuse * light.colorLightType.xyz * color.xyz + color.xyz * ambient_color + light.colorLightType.xyz * specular);
	}
	return float4(lighting.xyz, color.a);
}

float4 psMain(in VS_OUTPUT In) : COLOR 
{  
	float4 Color1 = tex2D(tex1, In.texCoord); 
	float4 Color2 = tex2D(tex2, In.texCoord);
	float4 Color = Color1 * Color2;

	float3 Normal = normalize(In.Normal);
	// get light indices from Light Buffer
	float4 lightIndex = GetLightIndex(BitPlane, In.lightProjSpaceLokup);
	// calculate lightung	
	float4 Albedo = CalculateLighting(Color, In.vVec, Normal, lightIndex);

	Color.xyz += Albedo.xyz;
	return Color;
}

Vertex Shaders:


//
uniform float4x4 ViewProjMatrix : register(c0);

struct VS_OUTPUT {
   float4 Pos:       POSITION;
   float2 texCoord: TEXCOORD0;
	float3 Normal:    TEXCOORD1;
	float4 lightProjSpaceLokup : TEXCOORD2;
	float3 vVec : TEXCOORD3;
};

float4 CalcLightProjSpaceLookup(float4 projectSpace) 
{	
	projectSpace.xy = (projectSpace.xy + float2(projectSpace.w, projectSpace.w)) * 0.5;
	return projectSpace;
}

VS_OUTPUT VSmain(float4 Pos: POSITION, float3 Normal: NORMAL, float2 texCoord: TEXCOORD0)
{
	VS_OUTPUT Out;
	Out.Pos = mul(float4(Pos.xyz, 1.0f), ViewProjMatrix);
	Out.texCoord = texCoord;
	Out.lightProjSpaceLokup = CalcLightProjSpaceLookup(Out.Pos);
	Out.vVec = Pos.xyz;
	Out.Normal = Normal;
	return Out;
}

The result:

image.thumb.png.3afc14e70cb22dcba3fc433f230dbf69.png

We can show the Light sources Buffer - texture with light indices:(console command: enableshowlightbuffer 1)

image.thumb.png.b67f14abc5f2aac8c1958305ac2bc44b.png

If we try to show the light geometry we will see the following result(console enabledrawlights 1)

image.thumb.png.dde7e4e91c8b547c6a4a40c6c0baea9b.png

And my the demo of Light indexed deferred rendering:

https://www.dropbox.com/s/5t9f5vpg83sspfs/3DMove_multilighting_gd.net.7z?dl=0

1) Try to run demo, moving on terrain using W,A,S,D.

2) Try to show light geometry(console command enabledrawlights 1), light buffer(console command: enableshowlightbuffer 1)

What do i do wrong ? how to fix the calculation of lighting ?

3DGraphics,Direct3D12,Vulkan,OpenCL,Algorithms

I don't have time to look over all code here, but just leave a suggestion: Familiarize yourself with RenderDoc or Nvidia Nsight, or even Visual studio graphics debugger. It will save you in the long run. Probably some of your GPU-side data is stale, and you can inspect all of it with a graphics debugger.

Advertisement

Hi @turanszkij, thank you for your responce.

3DGraphics,Direct3D12,Vulkan,OpenCL,Algorithms

This topic is closed to new replies.

Advertisement