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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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,6 +326,47 @@ float IntegrateQuadSpecular(in float3 v[5], in float vertexCount, in bool double
|
||||
return sum;
|
||||
}
|
||||
|
||||
// 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 dirToCamera,
|
||||
in float3 p[4],
|
||||
inout float3 polygon[5]
|
||||
)
|
||||
{
|
||||
// Transform the points of the light into the space of the normal's hemisphere.
|
||||
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
|
||||
// the clip is returned in vertexCount. It's possible for the vertexCount of the resulting clipped quad to be
|
||||
// 0 - all points clipped (no work to do, so return)
|
||||
// 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(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
|
||||
@@ -334,31 +376,21 @@ float IntegrateQuadSpecular(in float3 v[5], in float vertexCount, in bool double
|
||||
// diffuse - The output diffuse response for the quad light
|
||||
// specular - The output specular response for the quad light
|
||||
void LtcQuadEvaluate(
|
||||
in float3 normal,
|
||||
in float3 dirToView,
|
||||
in float3x3 ltcMat,
|
||||
in Surface surface,
|
||||
in LightingData lightingData,
|
||||
in Texture2D ltcMatrix,
|
||||
in Texture2D<float2> ltcAmpMatrix,
|
||||
in float3 p[4],
|
||||
in bool doubleSided,
|
||||
out float diffuse,
|
||||
out float specular)
|
||||
out float diffuseOut,
|
||||
out float3 specularOut)
|
||||
{
|
||||
// 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)};
|
||||
|
||||
// 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
|
||||
// the clip is returned in vertexCount. It's possible for the vertexCount of the resulting clipped quad to be
|
||||
// 0 - all points clipped (no work to do, so return)
|
||||
// 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);
|
||||
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)
|
||||
// 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);
|
||||
|
||||
// Check if all points below horizon
|
||||
if (endIdx == startIdx + 1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
p0 = firstPoint; // Restore the original p0
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
+5
-11
@@ -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, lightingData, SceneSrg::m_ltcMatrix, SceneSrg::m_ltcAmplification, ViewSrg::m_polygonLightPoints, startIndex, endIndex, diffuse, specularRgb);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user