Files
com.misaki.hdrp-toon/Runtime/Shaders/Includes/Lighting/UtsLightEvaluation.hlsl
Misaki 018300e046 Folder clean up;
Added Emissive;
2025-01-29 12:27:09 +09:00

264 lines
12 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
const float rateR = 0.299;
const float rateG = 0.587;
const float rateB = 0.114;
struct UTSLightData
{
float3 lightDirection;
float3 lightColor;
float diffuseDimmer;
float specularDimmer;
float3 shadowTint;
float penumbraTint;
SHADOW_TYPE shadowValue;
};
float GetColorAttenuation(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;
}
DirectLighting UtsEvaluateBSDF_Directional(LightLoopContext lightLoopContext, PositionInputs posInput, BuiltinData builtinData, DirectionalLightData lightData, UtsBSDFData bsdfData, PreLightData preLightData, float3 V, float2 uv0)
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 L = -lightData.forward;
SHADOW_TYPE shadow = EvaluateShadow_Directional(lightLoopContext, posInput, lightData, builtinData, bsdfData.geomNormalWS);
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 * _Light_Intensity_Multiplier);
UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting = UtsShadeSurface(posInput, bsdfData, preLightData, shadow, lightColor.rgb, V, L, uv0, lightData.diffuseDimmer, lightData.specularDimmer);
}
return lighting;
}
DirectLighting UtsEvaluateBSDF_Punctual(LightLoopContext lightLoopContext, PositionInputs posInput, BuiltinData builtinData, LightData lightData, UtsBSDFData bsdfData, PreLightData preLightData, float3 V, float2 uv0)
{
DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 L;
float4 distances; // {d, d^2, 1/d, d_proj}
GetPunctualLightVectors(posInput.positionWS, lightData, L, distances);
PositionInputs shadowPositionInputs = posInput;
shadowPositionInputs.positionWS = posInput.positionWS + L * _ShadowBias;
SHADOW_TYPE shadow = EvaluateShadow_Punctual(lightLoopContext, shadowPositionInputs, lightData, builtinData, bsdfData.geomNormalWS, L, distances);
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 * _Light_Intensity_Multiplier);
UtsClampRoughness(preLightData, bsdfData, lightData.minRoughness);
lighting = UtsShadeSurface(posInput, bsdfData, preLightData, shadow, lightColor.rgb, V, L, uv0, lightData.diffuseDimmer, lightData.specularDimmer);
}
return lighting;
}
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 UtsEvaluateBSDF_MatCapDiffuse(float3 positionWS, float3 normalWS, inout BuiltinData builtinData)
{
float3 positionVS = mul(UNITY_MATRIX_V, float4(positionWS, 1.0)).xyz;
float3 normalVS = mul(UNITY_MATRIX_V, float4(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, UNITY_SPECCUBE_LOD_STEPS).rgb * GetInverseCurrentExposureMultiplier();
}
IndirectLighting UtsEvaluateBSDF_MatCapSpecular(float3 positionWS, UtsBSDFData bsdfData, PreLightData preLightData)
{
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);
float2 uv = PcrossN.yx;
uv.x *= -1;
uv = uv * 0.5 + 0.5;
lighting.specularReflected = SAMPLE_TEXTURE2D_LOD(_MatCapMap, s_linear_clamp_sampler, uv, PerceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness)).rgb;
lighting.specularReflected *= preLightData.specularFGD * GetInverseCurrentExposureMultiplier();
return lighting;
}
void UtsEvaluateBSDF_Ramp(PositionInputs posInput, UtsBSDFData bsdfData, float3 L, inout BuiltinData builtinData)
{
// TODO
}
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);
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;
}
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 * preLightData.diffuseFGD * _ID_Intensity);
lighting.indirect.specularReflected = ApplyCurrentExposureMultiplier(lighting.indirect.specularReflected * bsdfData.fresnel0 * _IR_Intensity);
lightLoopOutput.diffuseLighting = lighting.direct.diffuse + builtinData.bakeDiffuseLighting;
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);
lightLoopOutput.diffuseLighting += builtinData.emissiveColor;
}
#endif