264 lines
12 KiB
HLSL
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 |