Added new fabirc pbr mode;

Added new stocking surface feature;

Fixed the issue that diffuse bsdf is not energy conserving.
Fixed the bug that shader can not render alpha clip properly;
This commit is contained in:
2025-05-15 16:07:54 +09:00
parent d19322b768
commit 35dc7b15a6
21 changed files with 234 additions and 103 deletions

View File

@@ -53,6 +53,17 @@ bool UtsUseScreenSpaceShadow(DirectionalLightData light, float3 normalWS)
#endif
}
bool IsNonZeroBSDF(float3 L, UtsBSDFData bsdfData)
{
#if _MATERIAL_TYPE_FACE
return true;
#else
float NdotL = dot(bsdfData.normalWS, L);
return NdotL > 0.0;
#endif
}
void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bsdfData, BuiltinData builtinData,
float3 V, uint featureFlags, out LightLoopOutput lightLoopOutput)
{
@@ -87,6 +98,7 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
float3 L = -light.forward;
// Is it worth sampling the shadow map?
// Should we skip it if NdotL is negative? (i.e. transmission)
if ((light.lightDimmer > 0) && (light.shadowDimmer > 0))
{
context.shadowValue = GetDirectionalShadowAttenuation(context.shadowContext,
@@ -345,6 +357,11 @@ void UtsLightLoop(FragInputs fragInputs, PositionInputs posInput, UtsBSDFData bs
#endif
}
if (HasFlag(bsdfData.surfaceFeatures, SURFACEFEATURE_STOCKING))
{
UtsEvaluateLighting_Stocking(fragInputs, posInput, bsdfData.normalWS, V, aggregateLighting);
}
#ifndef _LIGHT_BASE_RIM_LIGHT_ON
if (HasFlag(bsdfData.surfaceFeatures, SURFACEFEATURE_RIM_LIGHT))
{

View File

@@ -57,8 +57,14 @@ float3 ComputeSpecularTerm(UtsBSDFData bsdfData, PreLightData preLightData, floa
float specularExponent = RoughnessToBlinnPhongSpecularExponent(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness));
DV = D_KajiyaKay(t, H, specularExponent);
float normalizeSpec = DV * rcp(specularExponent + 2) * 2 * PI;
float normalizeSpec = DV * rcp(specularExponent + 2.0) * TWO_PI;
DV = DV * normalizeSpec * _KKColor.rgb;
#elif _PBR_MODE_FABRIC
float D = D_Charlie(NdotH, bsdfData.roughnessT);
// V_Charlie is expensive, use approx with V_Ashikhmin instead
// float V = V_Charlie(NdotL, clampedNdotV, bsdfData.roughness);
float Vis = V_Ashikhmin(NdotL, clampedNdotV);
DV = D * Vis;
#elif _PBR_MODE_TOON
float specularExponent = RoughnessToBlinnPhongSpecularExponent(PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness));
DV = pow(NdotH, 5.0 * specularExponent);
@@ -108,14 +114,14 @@ DirectLighting UtsShadeSurface(PositionInputs posInput, UtsBSDFData bsdfData, Pr
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
if (Max3(lightColor.r, lightColor.g, lightColor.b) > 0.0)
{
SHADOW_TYPE sharpShadow = smoothstep(0.4, 0.6, shadow);
#if _RECEIVE_HAIR_SHADOW_ON && ENABLE_UTS_HAIR_SHAOW
sharpShadow *= GetHairShadow(posInput, L);
#endif
#if _SHADING_MODE_SDF
float angle;
float3 sdfTexture = SampleSDFTexture(L, uv, angle); // r: sdf shadow, g: sdf highlight, b: halfshadow
@@ -123,7 +129,7 @@ DirectLighting UtsShadeSurface(PositionInputs posInput, UtsBSDFData bsdfData, Pr
float sdfShadowMask = smoothstep(angle - shadowSmoothLevel, angle + shadowSmoothLevel, sdfTexture.r);
float sdfHighlight = sdfTexture.g * _SDFHighlightStrength;
#endif
float3 diffuseTerm = 0.0;
float3 specularTerm = ComputeSpecularTerm(bsdfData, preLightData, V, L);
@@ -136,22 +142,22 @@ DirectLighting UtsShadeSurface(PositionInputs posInput, UtsBSDFData bsdfData, Pr
#if _SHADING_MODE_STANDARD
float NdotL = dot(bsdfData.normalWS, L);
float halfLambert = 0.5 * NdotL + 0.5;
float3 rampColor = SAMPLE_TEXTURE2D_ARRAY(_ShadingRampMap, s_linear_clamp_sampler, float2(halfLambert * shadow.x, rampMask), _ShadingIndex).rgb;
diffuseTerm = bsdfData.diffuseColor * rampColor;
diffuseTerm = bsdfData.diffuseColor * rampColor * INV_PI;
specularTerm *= saturate(NdotL) * sharpShadow;
#elif _SHADING_MODE_SDF
float3 rampColor = SAMPLE_TEXTURE2D_ARRAY(_ShadingRampMap, s_linear_clamp_sampler, float2(sdfShadowMask * sharpShadow.x, rampMask), _ShadingIndex).rgb;
diffuseTerm = bsdfData.diffuseColor * rampColor;
diffuseTerm = bsdfData.diffuseColor * rampColor * INV_PI;
specularTerm = (specularTerm + sdfHighlight) * sdfShadowMask * sharpShadow;
#endif
#else
#if _SHADING_MODE_STANDARD
float NdotL = dot(bsdfData.normalWS, L);
float halfLambert = 0.5 * NdotL + 0.5;
// float firstColorFeatherForMask = lerp(_1stShadeColorFeather, 0.0, max(_ComposerMaskMode, _FirstShadeOverridden));
float baseShadeMask = saturate((halfLambert - (_1stShadeColorStep - _1stShadeColorFeather)) / (_1stShadeColorStep - (_1stShadeColorStep - _1stShadeColorFeather)));
baseShadeMask *= sharpShadow.x;
@@ -159,30 +165,30 @@ DirectLighting UtsShadeSurface(PositionInputs posInput, UtsBSDFData bsdfData, Pr
// float secondColorFeatherForMask = lerp(_2ndShadeColorFeather, 0.0, max(_SecondShadeOverridden, _ComposerMaskMode));
float firstShadeMask = saturate((halfLambert - (_2ndShadeColorStep - _2ndShadeColorFeather)) / (_2ndShadeColorStep - (_2ndShadeColorStep - _2ndShadeColorFeather)));
diffuseTerm = lerp(lerp(bsdfData.secondShadingDiffuseColor, bsdfData.firstShadingDiffuseColor, firstShadeMask), bsdfData.diffuseColor, baseShadeMask);
diffuseTerm = lerp(lerp(bsdfData.secondShadingDiffuseColor, bsdfData.firstShadingDiffuseColor, firstShadeMask), bsdfData.diffuseColor, baseShadeMask) * INV_PI;
specularTerm *= baseShadeMask;
#elif _SHADING_MODE_SDF
float shadeMask = sdfShadowMask * sdfTexture.b * sharpShadow.x;
diffuseTerm = lerp(bsdfData.firstShadingDiffuseColor, bsdfData.diffuseColor, shadeMask);
diffuseTerm = lerp(bsdfData.firstShadingDiffuseColor, bsdfData.diffuseColor, shadeMask) * INV_PI;
specularTerm = (specularTerm + sdfHighlight) * shadeMask;
#endif
#endif
lighting.diffuse += diffuseTerm * lightColor * diffuseDimmer;
lighting.specular += specularTerm * lightColor * specularDimmer;
#if _LIGHT_BASE_RIM_LIGHT_ON
if (HasFlag(bsdfData.surfaceFeatures, SURFACEFEATURE_RIM_LIGHT))
{
DirectLighting rimLightLighting = UtsEvaluateLighting_RimLight(posInput, bsdfData, preLightData, L, lightColor);
lighting.diffuse += rimLightLighting.diffuse;
lighting.specular += rimLightLighting.specular;
}
#endif
}
return lighting;
}

View File

@@ -23,7 +23,7 @@ float3 SampleSDFTexture(float3 L, float2 uv, out float angle)
float2 lightDirection = normalize(L.xz);
angle = saturate(dot(forwardVector, lightDirection) * -1.0 + _SDFShadowLevel);
bool isRightSide = dot(lightDirection, leftVector) > 0;
return isRightSide ? right_SDFTex : left_SDFTex;
}
@@ -41,11 +41,11 @@ float GetHairShadow(PositionInputs posInput, float3 L)
float2 shadowLength = float2(shadowLengthY * 2.0f, shadowLengthY);
float3 cameraDirOS = normalize(TransformWorldToObject(GetCameraPositionWS()));
float cameraDirFactor = 1 - smoothstep(0.1, 0.9, cameraDirOS.y);
shadowLength.y *= cameraDirFactor;
float cameraDirFactor = 1.0 - smoothstep(0.1, 0.9, cameraDirOS.y);
// shadowLength.y *= cameraDirFactor;
// TODO: sample point is still shifting when fov change.
float2 samplingPoint = (posInput.positionSS + shadowLength * viewLightDir.xy * (_ScreenSize.xy / float2(1920.0f, 1080.0f))) * _ScreenSize.zw; // Use 1080p as the reference resolution to achieve consistent shadow lengths across various screen resolutions.
float2 samplingPoint = (posInput.positionSS + shadowLength * viewLightDir.xy) * _ScreenSize.zw; // Use 1080p as the reference resolution to achieve consistent shadow lengths across various screen resolutions.
float2 scaledUVs = samplingPoint * _RTHandleScale.xy; // We have to including the scaling factor for our shadow map since we are not going to allocate new texture if the rendering resolution changed.
float hairShadow = SAMPLE_TEXTURE2D_SHADOW(_HairShadowTex, s_linear_clamp_compare_sampler, float3(scaledUVs, posInput.deviceDepth + _HairShadowDepthBias)).r;