191 lines
7.3 KiB
HLSL
191 lines
7.3 KiB
HLSL
#ifndef UNIVERSAL_CLUSTER_DEFERRED
|
|
#define UNIVERSAL_CLUSTER_DEFERRED
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferInput.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/DynamicScaling.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
uint vertexID : SV_VertexID;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float3 screenUV : TEXCOORD1;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
Varyings VertexFullScreen(Attributes input)
|
|
{
|
|
Varyings output = (Varyings)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
|
|
|
float3 positionOS = input.positionOS.xyz;
|
|
output.positionCS = float4(positionOS.xy, UNITY_RAW_FAR_CLIP_VALUE, 1.0); // Force triangle to be on zfar
|
|
|
|
output.screenUV = output.positionCS.xyw;
|
|
#if UNITY_UV_STARTS_AT_TOP
|
|
output.screenUV.xy = output.screenUV.xy * float2(0.5, -0.5) + 0.5 * output.screenUV.z;
|
|
#else
|
|
output.screenUV.xy = output.screenUV.xy * 0.5 + 0.5 * output.screenUV.z;
|
|
#endif
|
|
|
|
output.screenUV.xy = DynamicScalingApplyScaleBias(output.screenUV.xy, float4(_RTHandleScale.xy, 0.0f, 0.0f));
|
|
|
|
return output;
|
|
}
|
|
|
|
float4x4 _ScreenToWorld[2];
|
|
|
|
half3 DeferredLightContribution(Light light, InputData inputData, GBufferData gBufferData)
|
|
{
|
|
#if defined(_LIGHT_LAYERS)
|
|
UNITY_BRANCH if (!IsMatchingLightLayer(light.layerMask, gBufferData.meshRenderingLayers))
|
|
return half3(0.0, 0.0, 0.0);
|
|
#endif
|
|
|
|
#if defined(_SIMPLELIT)
|
|
{
|
|
SurfaceData surfaceData = GBufferDataToSurfaceData(gBufferData);
|
|
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
|
|
half3 diffuseColor = LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
|
|
half smoothness = exp2(10 * surfaceData.smoothness + 1);
|
|
half3 specularColor = LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, half4(surfaceData.specular, 1), smoothness);
|
|
|
|
// TODO: if !defined(_SPECGLOSSMAP) && !defined(_SPECULAR_COLOR), force specularColor to 0 in gbuffer code
|
|
return half3(diffuseColor * surfaceData.albedo + specularColor);
|
|
}
|
|
#elif defined(_LIT)
|
|
{
|
|
#if SHADER_API_MOBILE || SHADER_API_SWITCH
|
|
// Specular highlights are still silenced by setting specular to 0.0 during gbuffer pass and GPU timing is still reduced.
|
|
bool materialSpecularHighlightsOff = false;
|
|
#else
|
|
bool materialSpecularHighlightsOff = (gBufferData.materialFlags & kMaterialFlagSpecularHighlightsOff);
|
|
#endif
|
|
|
|
BRDFData brdfData = GBufferDataToBRDFData(gBufferData);
|
|
return half3(LightingPhysicallyBased(brdfData, light, inputData.normalWS, inputData.viewDirectionWS, materialSpecularHighlightsOff));
|
|
}
|
|
#endif
|
|
|
|
return half3(0.0, 0.0, 0.0);
|
|
}
|
|
|
|
half4 DeferredShadingClustered(Varyings input) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
|
|
|
float2 screen_uv = (input.screenUV.xy / input.screenUV.z);
|
|
|
|
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
|
|
float2 undistorted_screen_uv = screen_uv;
|
|
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
|
|
{
|
|
screen_uv = input.positionCS.xy * _ScreenSize.zw;
|
|
}
|
|
#endif
|
|
|
|
GBufferData gBufferData = UnpackGBuffers(input.positionCS.xy);
|
|
|
|
half3 color = 0.0;
|
|
half alpha = 1.0;
|
|
|
|
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
|
|
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
|
|
{
|
|
input.positionCS.xy = undistorted_screen_uv * _ScreenSize.xy;
|
|
}
|
|
#endif
|
|
|
|
float4 posWS = mul(_ScreenToWorld[SLICE_ARRAY_INDEX], float4(input.positionCS.xy, gBufferData.depth, 1.0));
|
|
posWS.xyz *= rcp(posWS.w);
|
|
|
|
InputData inputData = (InputData)0;
|
|
|
|
inputData.positionWS = posWS.xyz;
|
|
inputData.normalWS = gBufferData.normalWS;
|
|
inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(posWS.xyz);
|
|
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);
|
|
|
|
AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(screen_uv);
|
|
|
|
#if defined(_SCREEN_SPACE_OCCLUSION)
|
|
// What we want is really to apply the minimum occlusion value between the baked occlusion from surfaceDataOcclusion and real-time occlusion from SSAO.
|
|
// But we already applied the baked occlusion during gbuffer pass, so we have to cancel it out here.
|
|
// We must also avoid divide-by-0 that the reciprocal can generate.
|
|
half surfaceDataOcclusion = gBufferData.occlusion;
|
|
half occlusion = aoFactor.indirectAmbientOcclusion < surfaceDataOcclusion ? aoFactor.indirectAmbientOcclusion * rcp(surfaceDataOcclusion) : 1.0;
|
|
alpha = occlusion;
|
|
#endif
|
|
|
|
// Main light
|
|
Light mainLight = GetMainLight();
|
|
mainLight.distanceAttenuation = 1.0;
|
|
bool materialReceiveShadowsOff = (gBufferData.materialFlags & kMaterialFlagReceiveShadowsOff) != 0;
|
|
UNITY_BRANCH if (!materialReceiveShadowsOff)
|
|
{
|
|
#if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
|
|
float4 shadowCoord = float4(screen_uv, 0.0, 1.0);
|
|
#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
|
|
float4 shadowCoord = TransformWorldToShadowCoord(posWS.xyz);
|
|
#else
|
|
float4 shadowCoord = float4(0, 0, 0, 0);
|
|
#endif
|
|
mainLight.shadowAttenuation = MainLightShadow(shadowCoord, posWS.xyz, gBufferData.shadowMask, _MainLightOcclusionProbes);
|
|
}
|
|
|
|
#if defined(_LIGHT_COOKIES)
|
|
half3 cookieColor = SampleMainLightCookie(posWS.xyz);
|
|
mainLight.color *= half3(cookieColor);
|
|
#endif
|
|
|
|
#if defined(_SCREEN_SPACE_OCCLUSION)
|
|
mainLight.shadowAttenuation *= aoFactor.directAmbientOcclusion;
|
|
#endif
|
|
|
|
color += DeferredLightContribution(mainLight, inputData, gBufferData);
|
|
|
|
// Additional light loop
|
|
// We do additional directional lights last because otherwise FXC complains...
|
|
uint pixelLightCount = GetAdditionalLightsCount();
|
|
LIGHT_LOOP_BEGIN(pixelLightCount)
|
|
Light light = GetAdditionalLight(lightIndex, inputData, gBufferData.shadowMask, aoFactor);
|
|
|
|
UNITY_BRANCH if (materialReceiveShadowsOff)
|
|
{
|
|
light.shadowAttenuation = 1.0;
|
|
}
|
|
|
|
color += DeferredLightContribution(light, inputData, gBufferData);
|
|
LIGHT_LOOP_END
|
|
|
|
UNITY_LOOP for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++)
|
|
{
|
|
CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK
|
|
Light light = GetAdditionalLight(lightIndex, inputData, gBufferData.shadowMask, aoFactor);
|
|
|
|
UNITY_BRANCH if (materialReceiveShadowsOff)
|
|
{
|
|
light.shadowAttenuation = 1.0;
|
|
}
|
|
|
|
color += DeferredLightContribution(light, inputData, gBufferData);
|
|
}
|
|
|
|
return half4(color, alpha);
|
|
}
|
|
#endif //UNIVERSAL_CLUSTER_DEFERRED
|