Added hair blending support.

This commit is contained in:
2025-05-06 23:39:49 +09:00
parent 10331b93ff
commit 961db806e9
12 changed files with 161 additions and 115 deletions

View File

@@ -45,21 +45,21 @@ DirectLighting UtsEvaluateBSDF_Directional(LightLoopContext lightLoopContext, Po
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 L = -lightData.forward;
SHADOW_TYPE shadow = 1.0;
#if _RECEIVE_LIGHT_SHADOW_ON
shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.geomNormalWS);
#endif
if (lightData.lightDimmer > 0.0)
{
// TODO: Colored shadow will overwrite the first and second shading diffuse color
//float3 shadowColor = ComputeShadowColor(shadow, lightData.shadowTint, lightData.penumbraTint);
float4 lightColor = EvaluateLight_Directional(lightLoopContext, posInput, lightData);
lightColor.rgb = GetLimitedLightColor(lightColor.rgb * lightColor.a * _LightIntensityMultiplier);
UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting = UtsShadeSurface(posInput, bsdfData, preLightData, shadow, lightColor.rgb, V, L, uv0, lightData.diffuseDimmer, lightData.specularDimmer);
@@ -72,28 +72,28 @@ DirectLighting UtsEvaluateBSDF_Punctual(LightLoopContext lightLoopContext, Posit
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 L;
float4 distances; // {d, d^2, 1/d, d_proj}
GetPunctualLightVectors(posInput.positionWS, lightData, L, distances);
SHADOW_TYPE shadow = 1.0;
#if _RECEIVE_LIGHT_SHADOW_ON
shadow = UtsEvaluateShadow_Punctual(lightLoopContext, posInput, lightData, builtinData, UtsGetShadowNormal(bsdfData), L, distances);
#endif
if (lightData.lightDimmer > 0.0)
{
// TODO: Colored shadow will overwrite the first and second shading diffuse color
//float3 shadowColor = ComputeShadowColor(shadow, lightData.shadowTint, lightData.penumbraTint);
float4 lightColor = EvaluateLight_Punctual(lightLoopContext, posInput, lightData, L, distances);
lightColor.rgb = GetLimitedLightColor(lightColor.rgb * lightColor.a * _LightIntensityMultiplier);
UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting = UtsShadeSurface(posInput, bsdfData, preLightData, shadow, lightColor.rgb, V, L, uv0, lightData.diffuseDimmer, lightData.specularDimmer);
}
return lighting;
}
@@ -124,17 +124,17 @@ void UtsEvaluateBSDF_BakeDiffuse(PositionInputs posInput, PreLightData preLightD
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
lightInReflDir = float3(-1, -1, -1); // This variable is used with APV for reflection probe normalization - see code for LIGHTFEATUREFLAGS_ENV
#endif
#if defined(_PBR_MODE_OFF) || defined(_PBR_MODE_TOON)
float3 normalWS = float3(0.0, 0.0, 1.0);
#else
float3 normalWS = bsdfData.normalWS;
#endif
float3 backNormalWS = -normalWS;
// Reflect normal to get lighting for reflection probe tinting
float3 R = reflect(-V, normalWS);
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
if (_EnableProbeVolumes)
{
@@ -150,7 +150,7 @@ void UtsEvaluateBSDF_BakeDiffuse(PositionInputs posInput, PreLightData preLightD
builtinData.backBakeDiffuseLighting = EvaluateAmbientProbe(backNormalWS);
}
#endif
#if !defined(_SURFACE_TYPE_TRANSPARENT) && !defined(SCREEN_SPACE_INDIRECT_DIFFUSE_DISABLED)
if (_IndirectDiffuseMode != INDIRECTDIFFUSEMODE_OFF)
{
@@ -178,7 +178,7 @@ IndirectLighting UtsEvaluateBSDF_MatCapSpecular(float3 positionWS, UtsBSDFData b
{
IndirectLighting lighting;
ZERO_INITIALIZE(IndirectLighting, lighting);
float3 positionVS = mul(UNITY_MATRIX_V, float4(positionWS, 1.0)).xyz;
float3 normalVS = mul(UNITY_MATRIX_V, float4(bsdfData.normalWS, 1.0)).xyz;
float3 pcrossN = cross(normalize(positionVS), normalVS);
@@ -190,7 +190,7 @@ IndirectLighting UtsEvaluateBSDF_MatCapSpecular(float3 positionWS, UtsBSDFData b
float lod = clamp(PerceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness) + _IndirectSpecularMatCapLod, 0.0, 10.0);
lighting.specularReflected = SAMPLE_TEXTURE2D_LOD(_IndirectSpecularMatCapMap, s_trilinear_clamp_sampler, uv, lod).rgb;
lighting.specularReflected *= preLightData.specularFGD * GetInverseCurrentExposureMultiplier();
return lighting;
}
@@ -204,7 +204,7 @@ IndirectLighting UtsEvaluateBSDF_Env(LightLoopContext lightLoopContext, Position
{
IndirectLighting lighting;
ZERO_INITIALIZE(IndirectLighting, lighting);
float3 envLighting;
float3 positionWS = posInput.positionWS;
float weight = 1.0;
@@ -268,13 +268,13 @@ void UtsPostEvaluateBSDF(PositionInputs posInput, PreLightData preLightData, Uts
ApplyAmbientOcclusion(aoFactor, builtinData, lighting);
#endif
AdjustIndirectLighting(preLightData, bsdfData, builtinData, lighting);
// In regular pbr, we need to multiple diffuse color here with direct diffuse lighting. However, in UTS, we have already multiplied it when evaluating the direct diffuse since we need to apply the shading color.
lightLoopOutput.diffuseLighting = lighting.direct.diffuse + builtinData.bakeDiffuseLighting + builtinData.emissiveColor;
lightLoopOutput.specularLighting = lighting.direct.specular + lighting.indirect.specularReflected;
// Rescale the GGX to account for the multiple scattering.
lightLoopOutput.specularLighting *= 1.0 + bsdfData.fresnel0 * preLightData.energyCompensation;
ApplyExposureAdjustment(lightLoopOutput.diffuseLighting);
ApplyExposureAdjustment(lightLoopOutput.specularLighting);
}

View File

@@ -30,27 +30,28 @@ float3 SampleSDFTexture(float3 L, float2 uv, out float angle)
float GetHairShadow(PositionInputs posInput, float3 L)
{
float shadow = 1.0;
// Push the face fragment view space position towards the light for a little bit
float hairShadowOpacity = saturate(Remap(length(posInput.positionWS), float2(_HairShadowFadeOutDistance, _HairShadowFadeInDistance), float2(0, 1)));
if (hairShadowOpacity > 0.0)
{
float3 viewLightDir = TransformWorldToViewDir(L);
float shadowLengthY = _HairShadowDistance * 5.0 * max(0.5, posInput.linearDepth * _HairShadowDistanceScaleFactor) / posInput.linearDepth;
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;
// 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 scaledUVs = samplingPoint * _HairShadowRTHandleScale.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.
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;
shadow = lerp(1.0 - hairShadowOpacity, 1.0, hairShadow);
}
return shadow;
}
@@ -118,4 +119,4 @@ SHADOW_TYPE UtsEvaluateShadow_Punctual(LightLoopContext lightLoopContext, Positi
#endif
}
#endif
#endif

View File

@@ -62,11 +62,11 @@ float _ToonIgnoreExposureMultiplier;
float _Outline_MaxWidth;
float4 _HairShadowRTHandleScale;
float4 _HairBlendingRTHandleScale;
float _HairShadowDistance;
float _HairShadowDistanceScaleFactor;
float _HairShadowDepthBias;
float _HairShadowFadeInDistance;
float _HairShadowFadeOutDistance;
// float2 _HairShadowRTHandleScale;
// float2 _HairBlendingRTHandleScale;

View File

@@ -63,17 +63,16 @@ void Frag(PackedVaryingsToPS packedInput,
#ifdef _DEPTHOFFSET_ON
, out float outputDepth : SV_Depth
#endif
)
)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(packedInput);
FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
float4 objPos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1));
float4 Set_UV0 = input.texCoord0;
// The following temporary definition of unity_AmbientEquator is for HDRP only.
//float4 unity_AmbientEquator = float4(0.05, 0.05, 0.05, 1.0); //Todo.
//v.2.0.9
//float3 envLightSource_GradientEquator = unity_AmbientEquator.rgb > 0.05 ? unity_AmbientEquator.rgb : half3(0.05, 0.05, 0.05);
float3 envLightSource_GradientEquator = ShadeSH9(float4(0, 1, 0, 0));
float3 envLightSource_SkyboxIntensity = max(
@@ -83,9 +82,9 @@ void Frag(PackedVaryingsToPS packedInput,
float3 ambientSkyColor = envLightSource_SkyboxIntensity.rgb > 0.0 ? envLightSource_SkyboxIntensity : envLightSource_GradientEquator;
ambientSkyColor *= GetCurrentExposureMultiplier();
float4 _BlendingTex_var = SAMPLE_TEXTURE2D(_HairBlendingMap, sampler_HairBlendingMap, TRANSFORM_TEX(Set_UV0, _BaseColorMap));
outColor = float4(_BlendingTex_var.rgb * ambientSkyColor, _BlendingTex_var.a);
float4 blendingTex = SAMPLE_TEXTURE2D(_HairBlendingMap, sampler_HairBlendingMap, TRANSFORM_TEX(Set_UV0, _BaseColorMap));
outColor = float4(blendingTex.rgb + ambientSkyColor, blendingTex.a);
#ifdef _DEPTHOFFSET_ON
outputDepth = posInput.deviceDepth;
#endif

View File

@@ -165,9 +165,9 @@ void Frag(PackedVaryingsToPS packedInput,
outColor = float4(finalColor, 1.0);
#if _MATERIAL_TYPE_FRONTHAIR && ENABLE_UTS_HAIR_BLENDING
float2 screenUV = posInput.positionNDC * _HairBlendingRTHandleScale.xy;
float4 hairBlendingMap = LOAD_TEXTURE2D_X(_HairBlendingTex, screenUV);
outColor.rgb = lerp(outColor.rgb, hairBlendingMap.rgb, hairBlendingMap.a * _HairBlendingFactor);
float2 screenUV = posInput.positionSS; // * _HairBlendingRTHandleScale.xy; // Why we don't need to scale? Does unity handle it internally?
float4 hairBlendingTex = LOAD_TEXTURE2D_X(_HairBlendingTex, screenUV);
outColor.rgb = lerp(outColor.rgb, hairBlendingTex.rgb, hairBlendingTex.a * _HairBlendingFactor);
#endif
#if UTS_DEBUG_SHADOWMAP || UTS_DEBUG_SELFSHADOW
@@ -184,7 +184,7 @@ void Frag(PackedVaryingsToPS packedInput,
#endif
#endif // ifdef UTS_DEBUG_SHADOWMAP
#endif // defined(UTS_DEBUG_SHADOWMAP) || defined(UTS_DEBUG_SELFSHADOW)
#ifdef _DEPTHOFFSET_ON
outputDepth = posInput.deviceDepth;
#endif