浏览代码

Merge pull request #372 from EvgeniiG/master

Add transmission support for area lights
/main
GitHub 7 年前
当前提交
dcd07ceb
共有 2 个文件被更改,包括 143 次插入102 次删除
  1. 227
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  2. 18
      Assets/ScriptableRenderPipeline/ShaderLibrary/AreaLighting.hlsl

227
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


struct PreLightData
{
// General
float NdotV; // Geometric version (not clamped)
float NdotV; // Geometric version (could be negative)
// GGX iso
float ggxLambdaV;

float3 specularFGD; // Store preconvoled BRDF for both specular and diffuse
float diffuseFGD;
// area light
float3x3 ltcXformGGX; // TODO: make sure the compiler not wasting VGPRs on constants
float3x3 ltcXformDisneyDiffuse; // TODO: make sure the compiler not wasting VGPRs on constants
float3 ltcGGXFresnelTerm;
float ltcDisneyDiffuseMagnitude;
// Area lights (17 VGPRs). Scalarize?
float3x3 orthoBasisViewNormal; // Right-handed view-dependent orthogonal basis around the normal (6x VGPRs)
float3x3 ltcTransformDiffuse; // Inverse transformation for Lambertian or Disney Diffuse (4x VGPRs)
float3x3 ltcTransformSpecular; // Inverse transformation for GGX (4x VGPRs)
float ltcMagnitudeDiffuse;
float3 ltcMagnitudeFresnel;
// area light clear coat
float3x3 ltcXformClearCoat; // TODO: make sure the compiler not wasting VGPRs on constants

float theta = FastACos(NdotV); // For Area light - UVs for sampling the LUTs
float2 uv = LTC_LUT_OFFSET + LTC_LUT_SCALE * float2(bsdfData.perceptualRoughness, theta * INV_HALF_PI);
// Note we load the matrix transpose (avoid to have to transpose it in shader)
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
preLightData.ltcTransformDiffuse = k_identity3x3;
#else
// Get the inverse LTC matrix for Disney Diffuse
preLightData.ltcTransformDiffuse = 0.0;
preLightData.ltcTransformDiffuse._m22 = 1.0;
preLightData.ltcTransformDiffuse._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_DISNEY_DIFFUSE_MATRIX_INDEX, 0);
#endif
preLightData.ltcXformGGX = 0.0;
preLightData.ltcXformGGX._m22 = 1.0;
preLightData.ltcXformGGX._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
preLightData.ltcTransformSpecular = 0.0;
preLightData.ltcTransformSpecular._m22 = 1.0;
preLightData.ltcTransformSpecular._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
// Get the inverse LTC matrix for Disney Diffuse
// Note we load the matrix transpose (avoid to have to transpose it in shader)
preLightData.ltcXformDisneyDiffuse = 0.0;
preLightData.ltcXformDisneyDiffuse._m22 = 1.0;
preLightData.ltcXformDisneyDiffuse._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_DISNEY_DIFFUSE_MATRIX_INDEX, 0);
// Construct a right-handed view-dependent orthogonal basis around the normal
preLightData.orthoBasisViewNormal[0] = normalize(V - bsdfData.normalWS * preLightData.NdotV);
preLightData.orthoBasisViewNormal[2] = bsdfData.normalWS;
preLightData.orthoBasisViewNormal[1] = normalize(cross(preLightData.orthoBasisViewNormal[2], preLightData.orthoBasisViewNormal[0]));
float ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
float ltcGGXFresnelMagnitude = ltcMagnitude.g;
preLightData.ltcDisneyDiffuseMagnitude = ltcMagnitude.b;
float ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r; // The difference of magnitudes of GGX and Fresnel
float ltcGGXFresnelMagnitude = ltcMagnitude.g;
float ltcDisneyDiffuseMagnitude = ltcMagnitude.b;
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
preLightData.ltcMagnitudeDiffuse = 1;
#else
preLightData.ltcMagnitudeDiffuse = ltcDisneyDiffuseMagnitude;
#endif
// TODO: the fit seems rather poor. The scaling factor of 0.5 allows us
// to match the reference for rough metals, but further darkens dielectrics.

F = Sqr(-F * bsdfData.coatCoverage + 1.0);
F /= preLightData.ieta; //TODO: LaurentB why / ieta here and not for other lights ?
preLightData.ltcGGXFresnelTerm = F * bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
preLightData.ltcMagnitudeFresnel = F * bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
preLightData.ltcGGXFresnelTerm = bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
preLightData.ltcMagnitudeFresnel = bsdfData.fresnel0 * ltcGGXFresnelMagnitudeDiff + (float3)ltcGGXFresnelMagnitude;
}
return preLightData;

// Currently, we only model diffuse transmission. Specular transmission is not yet supported.
// We assume that the back side of the object is a uniformly illuminated infinite plane
// (we reuse the illumination) with the reversed normal of the current sample.
// We apply wrapped lighting instead of the regular Lambertian diffuse
// to compensate for these approximations.
float3 EvaluateTransmission(BSDFData bsdfData, float NdotL, float3 lightColor, float diffuseScale, float shadow)
// with the reversed normal (and the view vector) of the current sample.
float3 EvaluateTransmission(BSDFData bsdfData, float intensity, float shadow)
float illuminance = ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
shadow = bsdfData.useThinObjectMode ? shadow : 1;
illuminance *= shadow;
shadow = bsdfData.useThinObjectMode ? shadow : 1;
float3 backLight = lightColor * (Lambert() * illuminance * diffuseScale);
float backLight = intensity * shadow;
return backLight * bsdfData.transmittance; // Premultiplied with the diffuse color
}

{
BSDF(V, L, positionWS, preLightData, bsdfData, diffuseLighting, specularLighting);
diffuseLighting *= lightData.color * (illuminance * lightData.diffuseScale);
specularLighting *= lightData.color * (illuminance * lightData.specularScale);
diffuseLighting *= illuminance * lightData.diffuseScale;
specularLighting *= illuminance * lightData.specularScale;
// We apply wrapped lighting instead of the regular Lambertian diffuse
// to compensate for approximations within EvaluateTransmission().
float illuminance = Lambert() * ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
diffuseLighting += EvaluateTransmission(bsdfData, NdotL, lightData.color, lightData.diffuseScale, shadow);
diffuseLighting += EvaluateTransmission(bsdfData, illuminance * lightData.diffuseScale, shadow);
// Save ALU by applying 'lightData.color' only once.
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
}
//-----------------------------------------------------------------------------

bsdfData.roughness = max(bsdfData.roughness, lightData.minRoughness); // Simulate that a punctual ligth have a radius with this hack
BSDF(V, L, positionWS, preLightData, bsdfData, diffuseLighting, specularLighting);
diffuseLighting *= lightData.color * (illuminance * lightData.diffuseScale);
specularLighting *= lightData.color * (illuminance * lightData.specularScale);
diffuseLighting *= illuminance * lightData.diffuseScale;
specularLighting *= illuminance * lightData.specularScale;
// We apply wrapped lighting instead of the regular Lambertian diffuse
// to compensate for approximations within EvaluateTransmission().
float illuminance = Lambert() * ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
diffuseLighting += EvaluateTransmission(bsdfData, NdotL, lightData.color, lightData.diffuseScale, shadow);
diffuseLighting += EvaluateTransmission(bsdfData, illuminance * lightData.diffuseScale, shadow);
// Save ALU by applying 'lightData.color' only once.
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
}
#include "LitReference.hlsl"

lightData.diffuseScale *= intensity;
lightData.specularScale *= intensity;
// TODO: This could be precomputed.
// Translate the light s.t. the shaded point is at the origin of the coordinate system.
lightData.positionWS -= positionWS;
// TODO: some of this could be precomputed.
// Translate the endpoints s.t. the shaded point is at the origin of the coordinate system.
P1 -= positionWS;
P2 -= positionWS;
// Rotate the endpoints into the local coordinate system.
P1 = mul(P1, transpose(preLightData.orthoBasisViewNormal));
P2 = mul(P2, transpose(preLightData.orthoBasisViewNormal));
// Construct a view-dependent orthonormal basis around N.
// TODO: it could be stored in PreLightData, since all LTC lights compute it more than once.
float3x3 basis;
basis[0] = normalize(V - bsdfData.normalWS * preLightData.NdotV);
basis[1] = normalize(cross(bsdfData.normalWS, basis[0]));
basis[2] = bsdfData.normalWS;
// Rotate the endpoints into the local coordinate system (left-handed).
P1 = mul(P1, transpose(basis));
P2 = mul(P2, transpose(basis));
// Compute the binormal.
// Compute the binormal in the local coordinate system.
float3 B = normalize(cross(P1, P2));
float ltcValue;

#ifdef LIT_DIFFUSE_LAMBERT_BRDF
ltcValue = LTCEvaluate(P1, P2, B, k_identity3x3);
#else
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformDisneyDiffuse);
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;
#endif
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformDiffuse);
ltcValue *= lightData.diffuseScale;
diffuseLighting = bsdfData.diffuseColor * (preLightData.ltcMagnitudeDiffuse * ltcValue);
}
[branch] if (bsdfData.enableTransmission)
{
// Flip the view vector and the normal. The bitangent stays the same.
float3x3 flipMatrix = float3x3(-1, 0, 0,
0, 1, 0,
0, 0, -1);
// Use the Lambertian approximation for performance reasons.
// The matrix multiplication should not generate any extra ALU on GCN.
ltcValue = LTCEvaluate(P1, P2, B, mul(flipMatrix, k_identity3x3));
diffuseLighting = bsdfData.diffuseColor * lightData.color * ltcValue;
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
diffuseLighting += EvaluateTransmission(bsdfData, ltcValue, 1);
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformClearCoat);
specularLighting += preLightData.ltcClearCoatFresnelTerm * (ltcValue * bsdfData.coatCoverage);
// TODO
// ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformClearCoat);
// ltcValue *= lightData.specularScale;
// specularLighting = preLightData.ltcClearCoatFresnelTerm * (ltcValue * bsdfData.coatCoverage);
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformGGX);
specularLighting += preLightData.ltcGGXFresnelTerm * ltcValue;
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcTransformSpecular);
ltcValue *= lightData.specularScale;
specularLighting += preLightData.ltcMagnitudeFresnel * ltcValue;
}
specularLighting *= lightData.color * lightData.specularScale;
}
// Save ALU by applying 'lightData.color' only once.
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
}

lightData.diffuseScale *= intensity;
lightData.specularScale *= intensity;
// TODO: store 4 points and save 12 cycles (24x MADs - 12x MOVs).
float3 p0 = lightData.positionWS + lightData.right * halfWidth + lightData.up * halfHeight;
float3 p1 = lightData.positionWS + lightData.right * halfWidth + lightData.up * -halfHeight;
float3 p2 = lightData.positionWS + lightData.right * -halfWidth + lightData.up * -halfHeight;
float3 p3 = lightData.positionWS + lightData.right * -halfWidth + lightData.up * halfHeight;
// Translate the light s.t. the shaded point is at the origin of the coordinate system.
lightData.positionWS -= positionWS;
float4x3 lightVerts;
// TODO: some of this could be precomputed.
lightVerts[0] = lightData.positionWS + lightData.right * halfWidth + lightData.up * halfHeight;
lightVerts[1] = lightData.positionWS + lightData.right * halfWidth + lightData.up * -halfHeight;
lightVerts[2] = lightData.positionWS + lightData.right * -halfWidth + lightData.up * -halfHeight;
lightVerts[3] = lightData.positionWS + lightData.right * -halfWidth + lightData.up * halfHeight;
float4x3 matL = float4x3(p0, p1, p2, p3) - float4x3(positionWS, positionWS, positionWS, positionWS);
// Rotate the endpoints into the local coordinate system.
lightVerts = mul(lightVerts, transpose(preLightData.orthoBasisViewNormal));
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
ltcValue = LTCEvaluate(matL, V, bsdfData.normalWS, preLightData.NdotV, k_identity3x3);
#else
ltcValue = LTCEvaluate(matL, V, bsdfData.normalWS, preLightData.NdotV, preLightData.ltcXformDisneyDiffuse);
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;
#endif
// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformDiffuse));
ltcValue *= lightData.diffuseScale;
diffuseLighting = bsdfData.diffuseColor * (preLightData.ltcMagnitudeDiffuse * ltcValue);
}
[branch] if (bsdfData.enableTransmission)
{
// Flip the view vector and the normal. The bitangent stays the same.
float3x3 flipMatrix = float3x3(-1, 0, 0,
0, 1, 0,
0, 0, -1);
// Use the Lambertian approximation for performance reasons.
// The matrix multiplication should not generate any extra ALU on GCN.
float3x3 ltcTransform = mul(flipMatrix, k_identity3x3);
// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(lightVerts, ltcTransform));
diffuseLighting = bsdfData.diffuseColor * lightData.color * ltcValue;
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
diffuseLighting += EvaluateTransmission(bsdfData, ltcValue, 1);
ltcValue = LTCEvaluate(matL, V, bsdfData.coatNormalWS, preLightData.coatNdotV, preLightData.ltcXformClearCoat);
specularLighting += preLightData.ltcClearCoatFresnelTerm * (ltcValue * bsdfData.coatCoverage);
// TODO
// ltcValue = LTCEvaluate(lightVerts, V, bsdfData.coatNormalWS, preLightData.coatNdotV, preLightData.ltcXformClearCoat);
// specularLighting = preLightData.ltcClearCoatFresnelTerm * (ltcValue * bsdfData.coatCoverage);
matL = mul(matL, preLightData.ltcCoatT);
// matL = mul(matL, preLightData.ltcCoatT);
V = preLightData.refractV;
// V = preLightData.refractV;
ltcValue = LTCEvaluate(matL, V, bsdfData.normalWS, preLightData.NdotV, preLightData.ltcXformGGX);
specularLighting += preLightData.ltcGGXFresnelTerm * ltcValue;
specularLighting *= lightData.color * lightData.specularScale;
// Polygon irradiance in the transformed configuration.
ltcValue = PolygonIrradiance(mul(lightVerts, preLightData.ltcTransformSpecular));
ltcValue *= lightData.specularScale;
specularLighting += preLightData.ltcMagnitudeFresnel * ltcValue;
// Save ALU by applying 'lightData.color' only once.
diffuseLighting *= lightData.color;
specularLighting *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
}

18
Assets/ScriptableRenderPipeline/ShaderLibrary/AreaLighting.hlsl


#endif
}
// For polygonal lights.
float LTCEvaluate(float4x3 L, float3 V, float3 N, float NdotV, float3x3 invM)
{
// Construct a view-dependent orthonormal basis around N.
// TODO: it could be stored in PreLightData, since all LTC lights compute it more than once.
float3x3 basis;
basis[0] = normalize(V - N * NdotV);
basis[1] = normalize(cross(N, basis[0]));
basis[2] = N;
// rotate area light in local basis
invM = mul(transpose(basis), invM);
L = mul(L, invM);
// Polygon irradiance in the transformed configuration
return PolygonIrradiance(L);
}
float LineFpo(float tLDDL, float lrcpD, float rcpD)
{
// Compute: ((l / d) / (d * d + l * l)) + (1.0 / (d * d)) * atan(l / d).

正在加载...
取消
保存