308 lines
14 KiB
HLSL
308 lines
14 KiB
HLSL
#ifndef UTS_LIGHT_EVALUATION
|
|
#define UTS_LIGHT_EVALUATION
|
|
|
|
#if FP_BUFFER
|
|
#define SATURATE_IF_SDR(x) (x)
|
|
#define SATURATE_BASE_COLOR_IF_SDR(x) (x)
|
|
#else
|
|
#define SATURATE_IF_SDR(x) saturate(x)
|
|
#define SATURATE_BASE_COLOR_IF_SDR(x) saturate(x)
|
|
#endif
|
|
|
|
#define APPLY_WEIGHT(x, y, t) lerp(x, x * y, t)
|
|
|
|
// not in materials
|
|
int _ToonLightHiCutFilter;
|
|
int _ToonEvAdjustmentCurve;
|
|
float _ToonEvAdjustmentValueArray[128];
|
|
float _ToonEvAdjustmentValueMin;
|
|
float _ToonEvAdjustmentValueMax;
|
|
float _ToonEvAdjustmentCompensation;
|
|
float _ToonIgnoreExposureMultiplier;
|
|
|
|
struct UTSLightData
|
|
{
|
|
float3 lightDirection;
|
|
float3 lightColor;
|
|
float diffuseDimmer;
|
|
float specularDimmer;
|
|
float3 shadowTint;
|
|
float penumbraTint;
|
|
SHADOW_TYPE shadowValue;
|
|
};
|
|
|
|
float3 ApplyCurrentExposureMultiplier(float3 color)
|
|
{
|
|
return color * lerp(GetCurrentExposureMultiplier(), 1, _ToonIgnoreExposureMultiplier);
|
|
}
|
|
|
|
float3 AccumulateUTSAggregateLighting(AggregateLighting aggregateLighting, UtsBSDFData bsdfData)
|
|
{
|
|
float3 directLighting = aggregateLighting.direct.diffuse + aggregateLighting.direct.specular;
|
|
float3 indirectLighting = ApplyCurrentExposureMultiplier(aggregateLighting.indirect.specularReflected * bsdfData.fresnel0 * _IR_Intensity + aggregateLighting.indirect.specularTransmitted * bsdfData.diffuseColor * _ID_Intensity);
|
|
return SATURATE_IF_SDR(directLighting + indirectLighting);
|
|
}
|
|
|
|
float3 ConvertFromEV100(float3 EV100)
|
|
{
|
|
float3 value = pow(2, EV100) * 2.5f;
|
|
return value;
|
|
}
|
|
|
|
float3 ConvertToEV100(float3 value)
|
|
{
|
|
return log2(value * 0.4f);
|
|
}
|
|
|
|
float WeightSample(PositionInputs positionInput)
|
|
{
|
|
// Center-weighted
|
|
const float2 kCenter = _ScreenParams.xy * 0.5;
|
|
const float weight = pow(length((kCenter.xy - positionInput.positionSS.xy) / _ScreenParams.xy), 1.0);
|
|
return 1.0 - saturate(weight);
|
|
}
|
|
|
|
float3 ApplyCompensation(float3 originalColor)
|
|
{
|
|
float3 ev100_Color = ConvertToEV100(originalColor) + _ToonEvAdjustmentCompensation * 0.5f;
|
|
|
|
|
|
float3 resultColor = max(0, ConvertFromEV100(ev100_Color));
|
|
return resultColor;
|
|
}
|
|
|
|
float3 GetExposureAdjustedColor(float3 originalColor)
|
|
{
|
|
if (_ToonEvAdjustmentCurve != 0)
|
|
{
|
|
|
|
float3 ev100_Color = ConvertToEV100(originalColor);
|
|
ev100_Color = clamp(ev100_Color, _ToonEvAdjustmentValueMin, _ToonEvAdjustmentValueMax);
|
|
float3 ev100_remap = (ev100_Color - _ToonEvAdjustmentValueMin) * (128 - 1) / (_ToonEvAdjustmentValueMax - _ToonEvAdjustmentValueMin);
|
|
ev100_remap = clamp(ev100_remap, 0.0, 127.0);
|
|
int3 ev100_idx = (int3) ev100_remap;
|
|
float3 ev100_lerp = ev100_remap - ev100_idx;
|
|
float3 ev100_remapped;
|
|
|
|
ev100_remapped.r = _ToonEvAdjustmentValueArray[ev100_idx.r] + (_ToonEvAdjustmentValueArray[ev100_idx.r + 1] - _ToonEvAdjustmentValueArray[ev100_idx.r]) * ev100_lerp.r;
|
|
ev100_remapped.g = _ToonEvAdjustmentValueArray[ev100_idx.g] + (_ToonEvAdjustmentValueArray[ev100_idx.g + 1] - _ToonEvAdjustmentValueArray[ev100_idx.g]) * ev100_lerp.g;
|
|
ev100_remapped.b = _ToonEvAdjustmentValueArray[ev100_idx.b] + (_ToonEvAdjustmentValueArray[ev100_idx.b + 1] - _ToonEvAdjustmentValueArray[ev100_idx.b]) * ev100_lerp.b;
|
|
|
|
|
|
float3 resultColor = ConvertFromEV100(ev100_remapped);
|
|
|
|
|
|
return resultColor;
|
|
}
|
|
else // else is neccessary to avoid warrnings.
|
|
{
|
|
return originalColor;
|
|
}
|
|
}
|
|
|
|
float GetLightAttenuation(float3 lightColor)
|
|
{
|
|
float lightAttenuation = rateR * lightColor.r + rateG * lightColor.g + rateB * lightColor.b;
|
|
return lightAttenuation;
|
|
}
|
|
|
|
float3 GetLimitedLightColor(float3 lightColor)
|
|
{
|
|
lightColor = ApplyCurrentExposureMultiplier(lightColor);
|
|
float3 result = lerp(lightColor, saturate(lightColor), _Is_Filter_LightColor);
|
|
|
|
return result;
|
|
}
|
|
|
|
IndirectLighting UtsEvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput, PreLightData preLightData, inout float reflectionHierarchyWeight)
|
|
{
|
|
IndirectLighting lighting;
|
|
ZERO_INITIALIZE(IndirectLighting, lighting);
|
|
|
|
// TODO: this texture is sparse (mostly black). Can we avoid reading every texel? How about using Hi-S?
|
|
float4 ssrLighting = LOAD_TEXTURE2D_X(_SsrLightingTexture, posInput.positionSS);
|
|
InversePreExposeSsrLighting(ssrLighting);
|
|
|
|
// Apply the weight on the ssr contribution (if required)
|
|
ApplyScreenSpaceReflectionWeight(ssrLighting);
|
|
|
|
reflectionHierarchyWeight = ssrLighting.a;
|
|
lighting.specularReflected = ssrLighting.rgb * preLightData.specularFGD;
|
|
|
|
return lighting;
|
|
}
|
|
|
|
void UtsEvaluateBSDF_BakeDiffuse(PositionInputs posInput, PreLightData preLightData, UtsBSDFData bsdfData, float3 V, inout BuiltinData builtinData, out float3 lightInReflDir)
|
|
{
|
|
lightInReflDir = 0.0;
|
|
#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(_SURFACE_TYPE_TRANSPARENT) && !defined(SCREEN_SPACE_INDIRECT_DIFFUSE_DISABLED)
|
|
if (_IndirectDiffuseMode != INDIRECTDIFFUSEMODE_OFF)
|
|
{
|
|
builtinData.bakeDiffuseLighting = LOAD_TEXTURE2D_X(_IndirectDiffuseTexture, posInput.positionSS).xyz * GetInverseCurrentExposureMultiplier();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
|
|
if (_EnableProbeVolumes)
|
|
{
|
|
// Reflect normal to get lighting for reflection probe tinting
|
|
float3 R = reflect(-V, bsdfData.normalWS);
|
|
|
|
#if defined(_PBR_Mode_OFF) || defined(_PBR_Mode_TOON)
|
|
float3 normalWS = 0.0;
|
|
float3 backNormalWS = 0.0;
|
|
#else
|
|
float3 normalWS = bsdfData.normalWS;
|
|
float3 backNormalWS = -bsdfData.normalWS;
|
|
#endif
|
|
EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(posInput.positionWS),
|
|
bsdfData.normalWS, -bsdfData.normalWS,
|
|
R, V,
|
|
posInput.positionSS, builtinData.renderingLayers,
|
|
builtinData.bakeDiffuseLighting, builtinData.backBakeDiffuseLighting, lightInReflDir);
|
|
}
|
|
else // If probe volume is disabled we fallback on the ambient probes
|
|
{
|
|
builtinData.bakeDiffuseLighting = EvaluateAmbientProbe(bsdfData.normalWS);
|
|
builtinData.backBakeDiffuseLighting = EvaluateAmbientProbe(-bsdfData.normalWS);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void UtsEvaluateMatCap(PositionInputs posInput, UtsBSDFData bsdfData, float perceptualRoughness, inout BuiltinData builtinData)
|
|
{
|
|
float3 positionVS = mul(UNITY_MATRIX_V, float4(posInput.positionWS, 1.0)).xyz;
|
|
float3 normalVS = mul(UNITY_MATRIX_V, float4(bsdfData.normalWS, 1.0)).xyz;
|
|
float3 PcrossN = cross(normalize(positionVS), normalVS);
|
|
|
|
float2 uv = PcrossN.yx;
|
|
uv.x *= -1;
|
|
uv = uv * 0.5 + 0.5;
|
|
|
|
builtinData.bakeDiffuseLighting = SAMPLE_TEXTURE2D_LOD(_MatCapMap, s_linear_clamp_sampler, uv, PerceptualRoughnessToMipmapLevel(perceptualRoughness)).rgb * GetInverseCurrentExposureMultiplier();
|
|
}
|
|
|
|
void UtsEvaluateRamp(PositionInputs posInput, UtsBSDFData bsdfData, inout BuiltinData builtinData)
|
|
{
|
|
|
|
}
|
|
|
|
IndirectLighting UtsEvaluateBSDF_Env(LightLoopContext lightLoopContext, PositionInputs posInput, PreLightData preLightData, EnvLightData lightData, UtsBSDFData bsdfData, int influenceShapeType, int GPUImageBasedLightingType, inout float hierarchyWeight)
|
|
{
|
|
IndirectLighting lighting;
|
|
ZERO_INITIALIZE(IndirectLighting, lighting);
|
|
|
|
if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION)
|
|
{
|
|
return lighting;
|
|
}
|
|
|
|
float3 envLighting;
|
|
float3 positionWS = posInput.positionWS;
|
|
float weight = 1.0;
|
|
|
|
float3 R = preLightData.iblR;
|
|
if (!IsEnvIndexTexture2D(lightData.envIndex)) // ENVCACHETYPE_CUBEMAP
|
|
{
|
|
R = GetSpecularDominantDir(bsdfData.normalWS, R, preLightData.iblPerceptualRoughness, ClampNdotV(preLightData.NdotV));
|
|
// When we are rough, we tend to see outward shifting of the reflection when at the boundary of the projection volume
|
|
// Also it appear like more sharp. To avoid these artifact and at the same time get better match to reference we lerp to original unmodified reflection.
|
|
// Formula is empirical.
|
|
float roughness = PerceptualRoughnessToRoughness(preLightData.iblPerceptualRoughness);
|
|
R = lerp(R, preLightData.iblR, saturate(smoothstep(0, 1, roughness * roughness)));
|
|
}
|
|
|
|
// Note: using influenceShapeType and projectionShapeType instead of (lightData|proxyData).shapeType allow to make compiler optimization in case the type is know (like for sky)
|
|
float intersectionDistance = EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, R, weight);
|
|
|
|
// Don't do clear coating for refraction
|
|
float3 coatR = preLightData.coatIblR;
|
|
if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION && HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_CLEAR_COAT))
|
|
{
|
|
float unusedWeight = 0.0;
|
|
EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, coatR, unusedWeight);
|
|
}
|
|
|
|
float3 F = preLightData.specularFGD;
|
|
|
|
float4 preLD = SampleEnvWithDistanceBaseRoughness(lightLoopContext, posInput, lightData, R, preLightData.iblPerceptualRoughness, intersectionDistance);
|
|
weight *= preLD.a; // Used by planar reflection to discard pixel
|
|
|
|
if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION)
|
|
{
|
|
envLighting = F * preLD.rgb;
|
|
// Apply the main lobe weight and update main reflection hierarchyWeight:
|
|
UpdateLightingHierarchyWeights(hierarchyWeight, weight);
|
|
envLighting *= weight;
|
|
}
|
|
|
|
envLighting *= lightData.multiplier;
|
|
|
|
if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFLECTION)
|
|
{
|
|
lighting.specularReflected = envLighting;
|
|
}
|
|
|
|
return lighting;
|
|
}
|
|
|
|
DirectLighting UtsEvaluateShading_Directional(LightLoopContext lightLoopContext, PositionInputs posInput, BuiltinData builtinData, DirectionalLightData lightData, UtsBSDFData bsdfData, float3 V)
|
|
{
|
|
DirectLighting lighting;
|
|
ZERO_INITIALIZE(DirectLighting, lighting);
|
|
|
|
float3 L = - lightData.forward;
|
|
float NdotL = dot(bsdfData.normalWS, L);
|
|
float halfLambert = 0.5 * NdotL + 0.5;
|
|
|
|
SHADOW_TYPE shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.normalWS);
|
|
float systemShadows = saturate(shadow + 0.5f + _Tweak_SystemShadowsLevel > 0.0 ? shadow + 0.5f + _Tweak_SystemShadowsLevel : 0.0);
|
|
float shadingGrade = lerp(halfLambert, halfLambert * systemShadows, _Set_SystemShadowsToBase );
|
|
float firstColorFeatherForMask = lerp(_1st_ShadeColor_Feather, 0.0f, max(_ComposerMaskMode, _FirstShadeOverridden));
|
|
|
|
float finalShadow = saturate((shadingGrade - (_1st_ShadeColor_Step - firstColorFeatherForMask)) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step - firstColorFeatherForMask))); // Base and 1st Shade Mask
|
|
|
|
if (lightData.diffuseDimmer > 0.0 && finalShadow > 0.0)
|
|
{
|
|
float secondColorFeatherForMask = lerp(_2nd_ShadeColor_Feather, 0.0f, max(_SecondShadeOverridden, _ComposerMaskMode));
|
|
float shadeShadow = saturate((halfLambert - (_ShadeColor_Step - secondColorFeatherForMask)) / (_ShadeColor_Step - (_ShadeColor_Step - secondColorFeatherForMask))); // 1st and 2nd Shades Mask
|
|
|
|
float3 diffuseTerm = lerp(lerp(bsdfData.secondShadingDiffuseColor, bsdfData.firstShadingDiffuseColor, shadeShadow), bsdfData.diffuseColor, finalShadow);
|
|
float3 specularTerm = ComputeSpecularTerm(V, L, bsdfData) * finalShadow;
|
|
|
|
float4 lightColor = EvaluateLight_Directional(lightLoopContext, posInput, lightData);
|
|
lightColor.rgb *= ComputeShadowColor(systemShadows, lightData.shadowTint, lightData.penumbraTint) * lightColor.a * _Light_Intensity_Multiplier;
|
|
lightColor.rgb = GetLimitedLightColor(lightColor.rgb);
|
|
|
|
lighting.diffuse = diffuseTerm * lightColor.rgb * lightData.diffuseDimmer;
|
|
lighting.specular += specularTerm * lightColor.rgb * lightData.specularDimmer;
|
|
}
|
|
|
|
return lighting;
|
|
}
|
|
|
|
void UtsPostEvaluateBSDF(PositionInputs posInput, PreLightData preLightData, UtsBSDFData bsdfData, BuiltinData builtinData, AggregateLighting lighting, out LightLoopOutput lightLoopOutput)
|
|
{
|
|
AmbientOcclusionFactor aoFactor;
|
|
GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, preLightData.NdotV, bsdfData.perceptualRoughness, bsdfData.ambientOcclusion, bsdfData.specularOcclusion, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
|
|
builtinData.bakeDiffuseLighting = APPLY_WEIGHT(builtinData.bakeDiffuseLighting, aoFactor.indirectAmbientOcclusion, _AO_Factor);
|
|
lighting.indirect.specularReflected = APPLY_WEIGHT(lighting.indirect.specularReflected, aoFactor.indirectSpecularOcclusion, _AO_Factor);
|
|
lighting.direct.diffuse = APPLY_WEIGHT(lighting.direct.diffuse, aoFactor.directAmbientOcclusion, _AO_Factor);
|
|
lighting.direct.specular = APPLY_WEIGHT(lighting.direct.specular, aoFactor.directSpecularOcclusion, _AO_Factor);
|
|
|
|
builtinData.bakeDiffuseLighting = ApplyCurrentExposureMultiplier(builtinData.bakeDiffuseLighting * bsdfData.diffuseColor * _ID_Intensity);
|
|
lighting.indirect.specularReflected = ApplyCurrentExposureMultiplier(lighting.indirect.specularReflected * bsdfData.fresnel0 * _IR_Intensity);
|
|
|
|
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;
|
|
}
|
|
|
|
#endif |