Adding clearcoat to linear transform cosine light and several bug fixes (#6018)

* Adding clearcoat to linear transform cosine lights (quad and polygon lights). Also fixed several warnings in various places in our shaders.

Signed-off-by: Ken Pruiksma <pruiksma@amazon.com>

* Fixes from PR review

Signed-off-by: Ken Pruiksma <pruiksma@amazon.com>

* Updates from review feedback - pulled out some of the duplicate code into functions. This required some minor restucturing. Ran ASV Area light tests to make sure nothing changed and validated clearcoat was working in a separate project.

Signed-off-by: Ken Pruiksma <pruiksma@amazon.com>
monroegm-disable-blank-issue-2
Ken Pruiksma 4 years ago committed by GitHub
parent f97ec14cf8
commit b15f97ae97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -76,23 +76,23 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface)
{
case 0:
baseMap = ViewSrg::m_decalTextureArrayDiffuse0.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps0.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps0.Sample(PassSrg::LinearSampler, decalUV).rg;
break;
case 1:
baseMap = ViewSrg::m_decalTextureArrayDiffuse1.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps1.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps1.Sample(PassSrg::LinearSampler, decalUV).rg;
break;
case 2:
baseMap = ViewSrg::m_decalTextureArrayDiffuse2.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps2.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps2.Sample(PassSrg::LinearSampler, decalUV).rg;
break;
case 3:
baseMap = ViewSrg::m_decalTextureArrayDiffuse3.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps3.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps3.Sample(PassSrg::LinearSampler, decalUV).rg;
break;
case 4:
baseMap = ViewSrg::m_decalTextureArrayDiffuse4.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps4.Sample(PassSrg::LinearSampler, decalUV);
normalMap = ViewSrg::m_decalTextureArrayNormalMaps4.Sample(PassSrg::LinearSampler, decalUV).rg;
break;
}

@ -48,9 +48,9 @@ float3 GetSpecularLighting(Surface surface, LightingData lightingData, const flo
// HdotV = HdotL due to the definition of half vector
float3 clearCoatF = FresnelSchlick(HdotL, 0.04) * surface.clearCoat.factor;
float clearCoatRoughness = max(surface.clearCoat.roughness * surface.clearCoat.roughness, 0.0005f);
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF );
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF);
specular = specular * (1.0 - clearCoatF) * (1.0 - clearCoatF) + clearCoatSpecular;
specular = specular * (1.0 - clearCoatF) + clearCoatSpecular;
}
specular *= lightIntensity;
@ -95,7 +95,7 @@ PbrLightingOutput DebugOutput(float3 color)
{
PbrLightingOutput output = (PbrLightingOutput)0;
float defaultNormal = float3(0.0f, 0.0f, 1.0f);
float3 defaultNormal = float3(0.0f, 0.0f, 1.0f);
output.m_diffuseColor = float4(color.rgb, 1.0f);
output.m_normal.rgb = EncodeNormalSignedOctahedron(defaultNormal);

@ -67,6 +67,6 @@ float3 ApplyParallaxCorrectionAABB(float3 aabbMin, float3 aabbMax, float3 aabbPo
// compute parallax corrected reflection vector, OBB version
float3 ApplyParallaxCorrectionOBB(float4x4 obbTransformInverse, float3 obbHalfExtents, float3 positionWS, float3 reflectDir)
{
float4 p = mul(obbTransformInverse, float4(positionWS, 1.0f));
float3 p = mul(obbTransformInverse, float4(positionWS, 1.0f)).xyz;
return ApplyParallaxCorrectionAABB(-obbHalfExtents, obbHalfExtents, float3(0.0f, 0.0f, 0.0f), p, reflectDir);
}

@ -60,7 +60,7 @@ float3 GetIblSpecular(
// compute blend amount based on world position in the reflection probe volume
float blendAmount = ComputeLerpBetweenInnerOuterOBBs(
ObjectSrg::GetReflectionProbeWorldMatrixInverse(),
(float3x4)ObjectSrg::GetReflectionProbeWorldMatrixInverse(),
ObjectSrg::m_reflectionProbeData.m_innerObbHalfLengths,
ObjectSrg::m_reflectionProbeData.m_outerObbHalfLengths,
position);
@ -121,4 +121,3 @@ void ApplyIBL(Surface surface, inout LightingData lightingData)
}
}
}

@ -256,15 +256,16 @@ void NormalizeQuadPoints(inout float3 p[5], in int vertexCount)
}
// Transforms the 4 points of a quad into the hemisphere of the normal
void TransformQuadToOrthonormalBasis(in float3 normal, in float3 dirToView, inout float3 p[4])
void TransformQuadToOrthonormalBasis(in float3 normal, in float3 dirToView, in float3 p[4], out float3 tp[5])
{
float3x3 orthoNormalBasis = BuildViewAlignedOrthonormalBasis(normal, dirToView);
// Transform points into orthonormal space
p[0] = mul(orthoNormalBasis, p[0]);
p[1] = mul(orthoNormalBasis, p[1]);
p[2] = mul(orthoNormalBasis, p[2]);
p[3] = mul(orthoNormalBasis, p[3]);
tp[0] = mul(orthoNormalBasis, p[0]);
tp[1] = mul(orthoNormalBasis, p[1]);
tp[2] = mul(orthoNormalBasis, p[2]);
tp[3] = mul(orthoNormalBasis, p[3]);
tp[4] = float3(0.0, 0.0, 0.0); // Extra vertex for if quad becomes a pentagon after clipping to hemisphere.
}
// Integrates the edges of a quad for lambertian diffuse contribution.
@ -325,28 +326,16 @@ float IntegrateQuadSpecular(in float3 v[5], in float vertexCount, in bool double
return sum;
}
// Evaluate linear transform cosine lighting for a 4 point quad.
// normal - The surface normal
// dirToView - Normalized direction from the surface to the view
// ltcMat - The LTC matrix for specular, or identity for diffuse.
// p[4] - The 4 light positions relative to the surface position.
// doubleSided - If the quad emits light from both sides
// diffuse - The output diffuse response for the quad light
// specular - The output specular response for the quad light
void LtcQuadEvaluate(
// Transform points p into the normal's hemisphere, then clip them to the hemisphere. Returns total number of points after clipping.
int LtcQuadTransformAndClip(
in float3 normal,
in float3 dirToView,
in float3x3 ltcMat,
in float3 dirToCamera,
in float3 p[4],
in bool doubleSided,
out float diffuse,
out float specular)
inout float3 polygon[5]
)
{
// Transform the points of the light into the space of the normal's hemisphere.
TransformQuadToOrthonormalBasis(normal, dirToView, p);
// Initialize quad with dummy point at end in case one corner is clipped (resulting in 5 sided polygon)
float3 v[5] = {p[0], p[1], p[2], p[3], float3(0.0, 0.0, 0.0)};
TransformQuadToOrthonormalBasis(normal, dirToCamera, p, polygon);
// Clip the light polygon to the normal hemisphere. This is done before the LTC matrix is applied to prevent
// parts of the light below the horizon from impacting the surface. The number of points remaining after
@ -355,10 +344,53 @@ void LtcQuadEvaluate(
// 3 - 3 points clipped, leaving only a triangular corner of the quad
// 4 - 2 or 0 points clipped, leaving a quad
// 5 - 1 point clipped leaving a pentagon.
int vertexCount = 0;
ClipQuadToHorizon(v, vertexCount);
ClipQuadToHorizon(polygon, vertexCount);
return vertexCount;
}
// Evaluate the LTC specular reflectance of points in polygon. Does not scale by fresnel.
float LtcEvaluateSpecularUnscaled(
in float2 ltcCoords,
in Texture2D ltcMatrix,
in float3 polygon[5],
in int vertexCount,
in bool doubleSided)
{
// Look up the values for the LTC matrix based on the roughness and orientation.
float3x3 ltcMat = LtcMatrix(ltcMatrix, ltcCoords);
// Transform the quad based on the LTC lookup matrix
ApplyLtcMatrixToQuad(ltcMat, polygon, vertexCount);
// IntegrateQuadSpecular uses more accurate integration than diffuse to handle smooth surfaces correctly.
return IntegrateQuadSpecular(polygon, vertexCount, doubleSided);
}
// Evaluate linear transform cosine lighting for a 4 point quad.
// normal - The surface normal
// dirToView - Normalized direction from the surface to the view
// ltcMat - The LTC matrix for specular, or identity for diffuse.
// p[4] - The 4 light positions relative to the surface position.
// doubleSided - If the quad emits light from both sides
// diffuse - The output diffuse response for the quad light
// specular - The output specular response for the quad light
void LtcQuadEvaluate(
in Surface surface,
in LightingData lightingData,
in Texture2D ltcMatrix,
in Texture2D<float2> ltcAmpMatrix,
in float3 p[4],
in bool doubleSided,
out float diffuseOut,
out float3 specularOut)
{
// Initialize quad with dummy point at end in case one corner is clipped (resulting in 5 sided polygon)
float3 polygon[5];
// Transform the points of the light into the space of the normal's hemisphere and clip to the hemisphere
int vertexCount = LtcQuadTransformAndClip(surface.normal, lightingData.dirToCamera, p, polygon);
if (vertexCount == 0)
{
// Entire light is below the horizon.
@ -366,12 +398,37 @@ void LtcQuadEvaluate(
}
// IntegrateQuadDiffuse is a cheap approximation compared to specular.
diffuse = IntegrateQuadDiffuse(v, vertexCount, doubleSided);
float diffuse = IntegrateQuadDiffuse(polygon, vertexCount, doubleSided);
ApplyLtcMatrixToQuad(ltcMat, v, vertexCount);
float2 ltcCoords = LtcCoords(dot(surface.normal, lightingData.dirToCamera), surface.roughnessLinear);
float specular = LtcEvaluateSpecularUnscaled(ltcCoords, ltcMatrix, polygon, vertexCount, doubleSided);
// IntegrateQuadSpecular uses more accurate integration to handle smooth surfaces correctly.
specular = IntegrateQuadSpecular(v, vertexCount, doubleSided);
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
float2 schlick = ltcAmpMatrix.Sample(PassSrg::LinearSampler, ltcCoords).xy;
float3 specularRgb = specular * (schlick.x * surface.specularF0 + (1.0 - surface.specularF0) * schlick.y);
if(o_clearCoat_feature_enabled)
{
int vertexCountCc = LtcQuadTransformAndClip(surface.clearCoat.normal, lightingData.dirToCamera, p, polygon);
if (vertexCountCc > 0)
{
float2 ltcCoordsCc = LtcCoords(dot(surface.clearCoat.normal, lightingData.dirToCamera), surface.clearCoat.roughness);
float clearCoatSpecular = LtcEvaluateSpecularUnscaled(ltcCoordsCc, ltcMatrix, polygon, vertexCountCc, doubleSided);
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
const float clearCoatSpecularF0 = 0.04;
float2 schlickCc = ltcAmpMatrix.Sample(PassSrg::LinearSampler, ltcCoordsCc).xy;
float F = schlickCc.x * clearCoatSpecularF0 + (1.0 - clearCoatSpecularF0) * schlickCc.y;
F *= surface.clearCoat.factor;
// Attenuate diffuse and specular based on how much light the clearcoat layer reflects
diffuse = diffuse * (1.0 - F);
specularRgb = (specularRgb * (1.0 - F)) + (clearCoatSpecular * F);
}
}
diffuseOut = diffuse;
specularOut = specularRgb;
}
// Checks an edge against the horizon and integrates it.
@ -397,7 +454,7 @@ void LtcQuadEvaluate(
// 4. Both points are below the horizon
// - Do nothing.
void EvaluatePolyEdge(in float3 p0, in float3 p1, inout float3 prevClipPoint, in float3x3 ltcMat, inout float diffuse, inout float specular)
void EvaluatePolyEdge(in float3 p0, in float3 p1, in float3x3 ltcMat, inout float3 prevClipPoint, inout float diffuse, inout float specular)
{
if (p0.z > 0.0)
{
@ -428,6 +485,74 @@ void EvaluatePolyEdge(in float3 p0, in float3 p1, inout float3 prevClipPoint, in
}
}
// Same as above but only evaluates specular (used for clear coat)
void EvaluatePolyEdgeSpecularOnly(in float3 p0, in float3 p1, in float3x3 ltcMat, inout float3 prevClipPoint, inout float specular)
{
if (p0.z > 0.0)
{
if (p1.z > 0.0)
{
// Both above horizon
specular += IntegrateEdge(normalize(mul(ltcMat, p0)), normalize(mul(ltcMat, p1)));
}
else
{
// Going from above to below horizon
prevClipPoint = ClipEdge(p0, p1);
specular += IntegrateEdge(normalize(mul(ltcMat, p0)), normalize(mul(ltcMat, prevClipPoint)));
}
}
else if (p1.z > 0.0)
{
// Going from below to above horizon
float3 clipPoint = mul(ltcMat, ClipEdge(p1, p0));
specular += IntegrateEdge(normalize(mul(ltcMat, prevClipPoint)), normalize(clipPoint));
specular += IntegrateEdge(normalize(clipPoint), normalize(mul(ltcMat, p1)));
}
}
// Evaluates the intial points to start looping through a polygon light. The first point in polygon may be below the surface
// so care must be taking to figure out which point to start with and what point to use to close the polygon.
void LtcPolygonEvaluateInitialPoints(
in float3 surfacePosition,
in float3x3 orthonormalMat,
in StructuredBuffer<float4> positions,
in uint startIdx,
inout float3 prevClipPoint,
inout float3 closePoint,
inout uint endIdx,
inout float3 p0)
{
// Prepare initial values
p0 = mul(orthonormalMat, positions[startIdx].xyz - surfacePosition); // First point in polygon
prevClipPoint = float3(0.0, 0.0, 0.0); // Used to hold previous clip point when polygon dips below horizon.
closePoint = p0;
// Handle if the first point is below the horizon.
if (p0.z < 0.0)
{
float3 firstPoint = p0; // save the first point so it can be restored later.
// Find the previous clip point so it can be used when the polygon goes above the horizon by
// searching backwards, updating the endIdx along the way to avoid reprocessing those points later
for ( ; endIdx > startIdx + 1; --endIdx)
{
float3 prevPoint = mul(orthonormalMat, positions[endIdx - 1].xyz - surfacePosition);
if (prevPoint.z > 0.0)
{
prevClipPoint = ClipEdge(prevPoint, p0);
closePoint = prevClipPoint;
break;
}
p0 = prevPoint;
}
p0 = firstPoint; // Restore the original p0
}
}
// Evaluates the LTC result of an arbitrary polygon lighting a surface position.
// pos - The surface position
// normal - The surface normal
@ -445,72 +570,102 @@ void EvaluatePolyEdge(in float3 p0, in float3 p1, inout float3 prevClipPoint, in
// EvaluatePolyEdge() later. During this search it also adjusts the end point index as necessary to avoid processing
// those points that are below the horizon.
void LtcPolygonEvaluate(
in float3 pos,
in float3 normal,
in float3 dirToView,
in float3x3 ltcMat,
in Surface surface,
in LightingData lightingData,
in Texture2D ltcMatrix,
in Texture2D<float2> ltcAmpMatrix,
in StructuredBuffer<float4> positions,
in uint startIdx,
in uint endIdx,
out float diffuse,
out float specular
out float diffuseOut,
out float3 specularRgbOut
)
{
if (endIdx - startIdx < 3)
{
return; // Must have at least 3 points to form a polygon.
}
uint originalEndIdx = endIdx; // Original endIdx may be needed for clearcoat
// Rotate ltc matrix
float3x3 orthonormalMat = BuildViewAlignedOrthonormalBasis(normal, dirToView);
float3x3 orthonormalMat = BuildViewAlignedOrthonormalBasis(surface.normal, lightingData.dirToCamera);
// Prepare initial values
float3 p0 = mul(orthonormalMat, positions[startIdx].xyz - pos); // First point in polygon
diffuse = 0.0;
specular = 0.0;
float3 prevClipPoint = float3(0.0, 0.0, 0.0); // Used to hold previous clip point when polygon dips below horizon.
float3 closePoint = p0;
// Handle if the first point is below the horizon.
if (p0.z < 0.0)
{
float3 firstPoint = p0; // save the first point so it can be restored later.
// Find the previous clip point so it can be used when the polygon goes above the horizon by
// searching backwards, updating the endIdx along the way to avoid reprocessing those points later
for ( ; endIdx > startIdx + 1; --endIdx)
{
float3 prevPoint = mul(orthonormalMat, positions[endIdx - 1].xyz - pos);
if (prevPoint.z > 0.0)
{
prevClipPoint = ClipEdge(prevPoint, p0);
closePoint = prevClipPoint;
break;
}
p0 = prevPoint;
}
// Check if all points below horizon
if (endIdx == startIdx + 1)
{
return;
}
// Evaluate the starting point (p0), previous point, and point used to close the polygon
float3 p0, prevClipPoint, closePoint;
LtcPolygonEvaluateInitialPoints(surface.position, orthonormalMat, positions, startIdx, prevClipPoint, closePoint, endIdx, p0);
p0 = firstPoint; // Restore the original p0
// Check if all points below horizon
if (endIdx == startIdx + 1)
{
return;
}
float diffuse = 0.0;
float specular = 0.0;
float2 ltcCoords = LtcCoords(dot(surface.normal, lightingData.dirToCamera), surface.roughnessLinear);
float3x3 ltcMat = LtcMatrix(ltcMatrix, ltcCoords);
// Evaluate all the points
for (uint curIdx = startIdx + 1; curIdx < endIdx; ++curIdx)
{
float3 p1 = mul(orthonormalMat, positions[curIdx].xyz - pos); // Current point in polygon
EvaluatePolyEdge(p0, p1, prevClipPoint, ltcMat, diffuse, specular);
float3 p1 = mul(orthonormalMat, positions[curIdx].xyz - surface.position); // Current point in polygon
EvaluatePolyEdge(p0, p1, ltcMat, prevClipPoint, diffuse, specular);
p0 = p1;
}
EvaluatePolyEdge(p0, closePoint, prevClipPoint, ltcMat, diffuse, specular);
EvaluatePolyEdge(p0, closePoint, ltcMat, prevClipPoint, diffuse, specular);
// Note: negated due to winding order
diffuse = -diffuse;
specular = -specular;
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
float2 schlick = ltcAmpMatrix.Sample(PassSrg::LinearSampler, ltcCoords).xy;
float3 specularRgb = specular * ((schlick.x * surface.specularF0) + (1.0 - surface.specularF0) * schlick.y);
if(o_clearCoat_feature_enabled)
{
// Rotate ltc matrix
float3x3 orthonormalMatCc = BuildViewAlignedOrthonormalBasis(surface.clearCoat.normal, lightingData.dirToCamera);
// restore original endIdx and re-evaluate initial points with matrix based on the clearcoat normal.
endIdx = originalEndIdx;
LtcPolygonEvaluateInitialPoints(surface.position, orthonormalMatCc, positions, startIdx, prevClipPoint, closePoint, endIdx, p0);
// Check if all points below horizon
if (endIdx != startIdx + 1)
{
float specularCc = 0.0;
float2 ltcCoordsCc = LtcCoords(dot(surface.clearCoat.normal, lightingData.dirToCamera), surface.clearCoat.roughness);
float3x3 ltcMatCc = LtcMatrix(ltcMatrix, ltcCoordsCc);
// Evaluate all the points
for (uint curIdx = startIdx + 1; curIdx < endIdx; ++curIdx)
{
float3 p1 = mul(orthonormalMatCc, positions[curIdx].xyz - surface.position); // Current point in polygon
EvaluatePolyEdgeSpecularOnly(p0, p1, ltcMatCc, prevClipPoint, specularCc);
p0 = p1;
}
EvaluatePolyEdgeSpecularOnly(p0, closePoint, ltcMatCc, prevClipPoint, specularCc);
// Note: negated due to winding order
specularCc = -specularCc;
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
const float clearCoatSpecularF0 = 0.04;
float2 schlickCc = ltcAmpMatrix.Sample(PassSrg::LinearSampler, ltcCoordsCc).xy;
float F = clearCoatSpecularF0 * schlickCc.x + (1.0 - clearCoatSpecularF0) * schlickCc.y;
F *= surface.clearCoat.factor;
diffuse = diffuse * (1.0 - F);
specularRgb = (specularRgb * (1.0 - F)) + (specularCc * F);
}
}
diffuseOut = diffuse;
specularRgbOut = specularRgb;
}

@ -51,25 +51,19 @@ void ApplyPoylgonLight(ViewSrg::PolygonLight light, Surface surface, inout Light
float radiusAttenuation = 1.0 - (falloff * falloff);
radiusAttenuation = radiusAttenuation * radiusAttenuation;
float2 ltcCoords = LtcCoords(dot(surface.normal, lightingData.dirToCamera), surface.roughnessLinear);
float3x3 ltcMat = LtcMatrix(SceneSrg::m_ltcMatrix, ltcCoords);
float diffuse = 0.0;
float specular = 0.0;
float3 specularRgb = 0.0;
LtcPolygonEvaluate(surface.position, surface.normal, lightingData.dirToCamera, ltcMat, ViewSrg::m_polygonLightPoints, startIndex, endIndex, diffuse, specular);
diffuse = doubleSided ? abs(diffuse) : max(0.0, diffuse);
specular = doubleSided ? abs(specular) : max(0.0, specular);
LtcPolygonEvaluate(surface, lightingData, SceneSrg::m_ltcMatrix, SceneSrg::m_ltcAmplification, ViewSrg::m_polygonLightPoints, startIndex, endIndex, diffuse, specularRgb);
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
float2 schlick = SceneSrg::m_ltcAmplification.Sample(PassSrg::LinearSampler, ltcCoords).xy;
float3 specularRGB = specular * (schlick.x + (1.0 - surface.specularF0) * schlick.y);
diffuse = doubleSided ? abs(diffuse) : max(0.0, diffuse);
specularRgb = doubleSided ? abs(specularRgb) : max(0.0, specularRgb);
// Scale by inverse surface area of hemisphere (1/2pi), attenuation, and light intensity
float3 intensity = 0.5 * INV_PI * radiusAttenuation * abs(light.m_rgbIntensityNits);
lightingData.diffuseLighting += surface.albedo * diffuse * intensity;
lightingData.specularLighting += surface.specularF0 * specularRGB * intensity;
lightingData.specularLighting += specularRgb * intensity;
}
void ApplyPolygonLights(Surface surface, inout LightingData lightingData)

@ -112,22 +112,15 @@ void ApplyQuadLight(ViewSrg::QuadLight light, Surface surface, inout LightingDat
{
float3 p[4] = {p0, p1, p2, p3};
float2 ltcCoords = LtcCoords(dot(surface.normal, lightingData.dirToCamera), surface.roughnessLinear);
float3x3 ltcMat = LtcMatrix(SceneSrg::m_ltcMatrix, ltcCoords);
float diffuse = 0.0;
float specular = 0.0;
LtcQuadEvaluate(surface.normal, lightingData.dirToCamera, ltcMat, p, doubleSided, diffuse, specular);
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
float2 schlick = SceneSrg::m_ltcAmplification.Sample(PassSrg::LinearSampler, ltcCoords).xy;
float3 specularRGB = specular * (schlick.x + (1.0 - surface.specularF0) * schlick.y);
float3 specular = float3(0.0, 0.0, 0.0); // specularF0 used in LtcQuadEvaluate which is a float3
LtcQuadEvaluate(surface, lightingData, SceneSrg::m_ltcMatrix, SceneSrg::m_ltcAmplification, p, doubleSided, diffuse, specular);
// Scale by inverse surface area of hemisphere (1/2pi), attenuation, and light intensity
float3 intensity = 0.5 * INV_PI * radiusAttenuation * light.m_rgbIntensityNits;
lightingData.diffuseLighting += surface.albedo * diffuse * intensity;
lightingData.specularLighting += surface.specularF0 * specularRGB * intensity;
lightingData.specularLighting += specular * intensity;
}
else
{

@ -22,7 +22,7 @@
// ------- Diffuse Lighting -------
//! Simple Lambertian BRDF.
float3 DiffuseLambertian(float3 albedo, float3 normal, float3 dirToLight, float diffuseResponse)
float3 DiffuseLambertian(float3 albedo, float3 normal, float3 dirToLight, float3 diffuseResponse)
{
float NdotL = saturate(dot(normal, dirToLight));
return albedo * NdotL * INV_PI * diffuseResponse;

@ -177,7 +177,7 @@ float ComputeLerpBetweenInnerOuterAABBs(float3 innerAabbMin, float3 innerAabbMax
bool ObbContainsPoint(float4x4 obbTransformInverse, float3 obbHalfExtents, float3 testPoint)
{
// get the position in Obb local space, force to positive quadrant with abs()
float4 p = abs(mul(obbTransformInverse, float4(testPoint, 1.0f)));
float3 p = abs(mul(obbTransformInverse, float4(testPoint, 1.0f)).xyz);
return AabbContainsPoint(-obbHalfExtents, obbHalfExtents, p);
}

Loading…
Cancel
Save