Deferred Renderer w/ Luv color space question

Started by
2 comments, last by patw 13 years, 9 months ago
So I'm working with a light prepass renderer and was recently turned on to the idea of using Luv color space for light accumulation because of its ability to represent diffuse and specular color with only four channels (UV chromacity, plus diffuse and specular luminosity). I'm wondering though about the method for accumulating overlapping lights.

According to the article in the Shader X7 book, lights can be blended using this technique:

float4 blendLightInfo
(
in float2 lightColorUV,
in float NL_ATT,
in float RVn,
in float4 accumCurrent
)
{
return float4(
lerp( accumCurrent.rg, lightColorUV, saturate( ( NL_Att / accumCurrent.b ) * 0.5 ),
accumCurrent.b + NL_Att,
accumCurrent.a + saturate( RVn * NL_Att )
);
}

However, this seems wrong. For example, if the NL_Att is 0.5 and accumCurrent.b is 0.25, you're going to get the same chromacity blend as if NL_Att is 0.5 and accumCurrent.b is 0.125 (or anything else under half of NL_Att, for that matter). You'll get something that'll look sort of right most of the time, but it wont be a smooth interpolation between the two chromacities.

Is there something that I'm missing here?
Advertisement
One slight clarification: It does not let you store specular color, but it does allow you to more accurately re-construct specular than RGB storage. With RGB storage, you usually approximate luminance by extracting it from the RGB color, however this saturates luminance at 1.0. With Luv, luminance is actually stored, and so it allows you to blend lights in HDR since, for the purposes of lights (in Lambertian shading), luminance is: N dot L * Attenuation

You are correct about the blend. The blend is most accurate when blending lights of similar luminance, since this value gets clamped (otherwise the color would extend beyond the two source colors and that would also be bad). The ideal way to do this, in my opinion, is not to LERP but to use some kind of curve (probably something based on: e^x) to blend the light colors. I would also like the function to be adjustable via parameters to give more control to the artists over the way lights blend.

Ultimately I settled on a lerp because it was cheap. Some day it would be cool to do Luv and maybe the blend function on SPU's but I decided Luv was too expensive on the Xbox360. (For pre-pass on SPUs, check out: Parallelized Light Pre-Pass Rendering with the Cell Broadband Engine by Steven Tovey and Stephen McAuley, in GPU Pro)
Thanks for the clarification. Here's one idea I've been toying with for Luv light accumulation:


float4 blendLightInfo
(
in float2 lightColorUV,
in float NL_ATT,
in float RVn,
in float4 accumCurrent
)
{
return float4(
accumCurrent.rg + lightColorUV * NdotL,
accumCurrent.b + NL_Att,
accumCurrent.a + saturate( RVn * NL_Att ) );
}


Then when reading from the light accum buffer:

void getAccumLightInfo
(
in float4 accumCurrent,
out float2 lightColorUV,
out float NL_Att,
out float RVn_Att
)
{
lightColorUV = accumCurrent.rg / accumCurrent.b;
NL_Att = accumCurrent.b;
RVn_Att = accumCurrent.a;
}


The nice thing about this is that it's a simple additive blend, which means it can use hardware blending, so no fancy tricks or intermediate textures would be needed to accumulate overlapping lights. Downsides are that it requires an extra reciprocal operation to read from the light accumulation buffer, and that the light accumulation buffer probably needs to be floating-point. Think something like that would fly?

What made you decide that it was too costly on the 360? Resolving to an intermediate buffer for accumulation?
Yeah the memory transfer is always the killer. Without a trivial blend, the memory transfer costs effectively eliminate the benefit of pre-pass over multi-buffer, and it noticeably scales up performance cost as # of lights increase; the very problem deferred lighting tries to solve.

This topic is closed to new replies.

Advertisement