Adaug proiectul Unity

This commit is contained in:
2026-11-01 23:39:55 +02:00
parent cb14d9d37d
commit 863eac8f2c
23463 changed files with 5412601 additions and 0 deletions
@@ -0,0 +1,71 @@
#ifndef AMBIENT_OCCLUSION_INCLUDED
#define AMBIENT_OCCLUSION_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
// Ambient occlusion
TEXTURE2D_X(_ScreenSpaceOcclusionTexture);
// 2023.3 Deprecated. This is for backwards compatibility. Remove in the future.
#define sampler_ScreenSpaceOcclusionTexture sampler_LinearClamp
struct AmbientOcclusionFactor
{
half indirectAmbientOcclusion;
half directAmbientOcclusion;
};
half SampleAmbientOcclusion(float2 normalizedScreenSpaceUV)
{
float2 uv = UnityStereoTransformScreenSpaceTex(normalizedScreenSpaceUV);
#if defined(UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION)
uv = RemovePretransformRotation(uv, GetScaledScreenParams());
#endif
return half(SAMPLE_TEXTURE2D_X(_ScreenSpaceOcclusionTexture, sampler_LinearClamp, uv).x);
}
AmbientOcclusionFactor GetScreenSpaceAmbientOcclusion(float2 normalizedScreenSpaceUV)
{
AmbientOcclusionFactor aoFactor;
#if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
float ssao = saturate(SampleAmbientOcclusion(normalizedScreenSpaceUV) + (1.0 - _AmbientOcclusionParam.x));
aoFactor.indirectAmbientOcclusion = ssao;
aoFactor.directAmbientOcclusion = lerp(half(1.0), ssao, _AmbientOcclusionParam.w);
#else
aoFactor.directAmbientOcclusion = half(1.0);
aoFactor.indirectAmbientOcclusion = half(1.0);
#endif
#if defined(DEBUG_DISPLAY)
switch(_DebugLightingMode)
{
case DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS:
aoFactor.directAmbientOcclusion = 0.5;
aoFactor.indirectAmbientOcclusion = 0.5;
break;
case DEBUGLIGHTINGMODE_LIGHTING_WITH_NORMAL_MAPS:
aoFactor.directAmbientOcclusion *= 0.5;
aoFactor.indirectAmbientOcclusion *= 0.5;
break;
}
#endif
return aoFactor;
}
AmbientOcclusionFactor CreateAmbientOcclusionFactor(float2 normalizedScreenSpaceUV, half occlusion)
{
AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(normalizedScreenSpaceUV);
aoFactor.indirectAmbientOcclusion = min(aoFactor.indirectAmbientOcclusion, occlusion);
return aoFactor;
}
AmbientOcclusionFactor CreateAmbientOcclusionFactor(InputData inputData, SurfaceData surfaceData)
{
return CreateAmbientOcclusionFactor(inputData.normalizedScreenSpaceUV, surfaceData.occlusion);
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1c0cb2353d9a4debbc61e650002843f4
timeCreated: 1606316022
@@ -0,0 +1,291 @@
#ifndef UNIVERSAL_BRDF_INCLUDED
#define UNIVERSAL_BRDF_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/BSDF.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Deprecated.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
#define kDielectricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
struct BRDFData
{
half3 albedo;
half3 diffuse;
half3 specular;
half reflectivity;
half perceptualRoughness;
half roughness;
half roughness2;
half grazingTerm;
// We save some light invariant BRDF terms so we don't have to recompute
// them in the light loop. Take a look at DirectBRDF function for detailed explaination.
half normalizationTerm; // roughness * 4.0 + 2.0
half roughness2MinusOne; // roughness^2 - 1.0
};
half ReflectivitySpecular(half3 specular)
{
return Max3(specular.r, specular.g, specular.b);
}
half OneMinusReflectivityMetallic(half metallic)
{
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in kDielectricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = kDielectricSpec.a;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
half MetallicFromReflectivity(half reflectivity)
{
half oneMinusDielectricSpec = kDielectricSpec.a;
return (reflectivity - kDielectricSpec.r) / oneMinusDielectricSpec;
}
inline void InitializeBRDFDataDirect(half3 albedo, half3 diffuse, half3 specular, half reflectivity, half oneMinusReflectivity, half smoothness, inout half alpha, out BRDFData outBRDFData)
{
outBRDFData = (BRDFData)0;
outBRDFData.albedo = albedo;
outBRDFData.diffuse = diffuse;
outBRDFData.specular = specular;
outBRDFData.reflectivity = reflectivity;
outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN_SQRT);
outBRDFData.roughness2 = max(outBRDFData.roughness * outBRDFData.roughness, HALF_MIN);
outBRDFData.grazingTerm = saturate(smoothness + reflectivity);
outBRDFData.normalizationTerm = outBRDFData.roughness * half(4.0) + half(2.0);
outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - half(1.0);
// Input is expected to be non-alpha-premultiplied while ROP is set to pre-multiplied blend.
// We use input color for specular, but (pre-)multiply the diffuse with alpha to complete the standard alpha blend equation.
// In shader: Cs' = Cs * As, in ROP: Cs' + Cd(1-As);
// i.e. we only alpha blend the diffuse part to background (transmittance).
#if defined(_ALPHAPREMULTIPLY_ON)
// TODO: would be clearer to multiply this once to accumulated diffuse lighting at end instead of the surface property.
outBRDFData.diffuse *= alpha;
#endif
}
// Legacy: do not call, will not correctly initialize albedo property.
inline void InitializeBRDFDataDirect(half3 diffuse, half3 specular, half reflectivity, half oneMinusReflectivity, half smoothness, inout half alpha, out BRDFData outBRDFData)
{
InitializeBRDFDataDirect(half3(0.0, 0.0, 0.0), diffuse, specular, reflectivity, oneMinusReflectivity, smoothness, alpha, outBRDFData);
}
// Initialize BRDFData for material, managing both specular and metallic setup using shader keyword _SPECULAR_SETUP.
inline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, inout half alpha, out BRDFData outBRDFData)
{
#ifdef _SPECULAR_SETUP
half reflectivity = ReflectivitySpecular(specular);
half oneMinusReflectivity = half(1.0) - reflectivity;
half3 brdfDiffuse = albedo * oneMinusReflectivity;
half3 brdfSpecular = specular;
#else
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
half reflectivity = half(1.0) - oneMinusReflectivity;
half3 brdfDiffuse = albedo * oneMinusReflectivity;
half3 brdfSpecular = lerp(kDielectricSpec.rgb, albedo, metallic);
#endif
InitializeBRDFDataDirect(albedo, brdfDiffuse, brdfSpecular, reflectivity, oneMinusReflectivity, smoothness, alpha, outBRDFData);
}
inline void InitializeBRDFData(inout SurfaceData surfaceData, out BRDFData brdfData)
{
InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData);
}
half3 ConvertF0ForClearCoat15(half3 f0)
{
return ConvertF0ForAirInterfaceToF0ForClearCoat15Fast(f0);
}
inline void InitializeBRDFDataClearCoat(half clearCoatMask, half clearCoatSmoothness, inout BRDFData baseBRDFData, out BRDFData outBRDFData)
{
outBRDFData = (BRDFData)0;
outBRDFData.albedo = half(1.0);
// Calculate Roughness of Clear Coat layer
outBRDFData.diffuse = kDielectricSpec.aaa; // 1 - kDielectricSpec
outBRDFData.specular = kDielectricSpec.rgb;
outBRDFData.reflectivity = kDielectricSpec.r;
outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(clearCoatSmoothness);
outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN_SQRT);
outBRDFData.roughness2 = max(outBRDFData.roughness * outBRDFData.roughness, HALF_MIN);
outBRDFData.normalizationTerm = outBRDFData.roughness * half(4.0) + half(2.0);
outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - half(1.0);
outBRDFData.grazingTerm = saturate(clearCoatSmoothness + kDielectricSpec.x);
// Modify Roughness of base layer using coat IOR
half ieta = lerp(1.0h, CLEAR_COAT_IETA, clearCoatMask);
half coatRoughnessScale = Sq(ieta);
half sigma = RoughnessToVariance(PerceptualRoughnessToRoughness(baseBRDFData.perceptualRoughness));
baseBRDFData.perceptualRoughness = RoughnessToPerceptualRoughness(VarianceToRoughness(sigma * coatRoughnessScale));
// Recompute base material for new roughness, previous computation should be eliminated by the compiler (as it's unused)
baseBRDFData.roughness = max(PerceptualRoughnessToRoughness(baseBRDFData.perceptualRoughness), HALF_MIN_SQRT);
baseBRDFData.roughness2 = max(baseBRDFData.roughness * baseBRDFData.roughness, HALF_MIN);
baseBRDFData.normalizationTerm = baseBRDFData.roughness * 4.0h + 2.0h;
baseBRDFData.roughness2MinusOne = baseBRDFData.roughness2 - 1.0h;
// Darken/saturate base layer using coat to surface reflectance (vs. air to surface)
baseBRDFData.specular = lerp(baseBRDFData.specular, ConvertF0ForClearCoat15(baseBRDFData.specular), clearCoatMask);
// TODO: what about diffuse? at least in specular workflow diffuse should be recalculated as it directly depends on it.
}
BRDFData CreateClearCoatBRDFData(SurfaceData surfaceData, inout BRDFData brdfData)
{
BRDFData brdfDataClearCoat = (BRDFData)0;
#if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
// base brdfData is modified here, rely on the compiler to eliminate dead computation by InitializeBRDFData()
InitializeBRDFDataClearCoat(surfaceData.clearCoatMask, surfaceData.clearCoatSmoothness, brdfData, brdfDataClearCoat);
#endif
return brdfDataClearCoat;
}
// Computes the specular term for EnvironmentBRDF
half3 EnvironmentBRDFSpecular(BRDFData brdfData, half fresnelTerm)
{
#if (UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
half surfaceReduction = half(1.0) / (brdfData.roughness2 + half(1.0));
#else
float surfaceReduction = 1.0 / (brdfData.roughness2 + 1.0);
#endif
return half3(surfaceReduction * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm));
}
half3 EnvironmentBRDF(BRDFData brdfData, half3 indirectDiffuse, half3 indirectSpecular, half fresnelTerm)
{
half3 c = indirectDiffuse * brdfData.diffuse;
c += indirectSpecular * EnvironmentBRDFSpecular(brdfData, fresnelTerm);
return c;
}
// Environment BRDF without diffuse for clear coat
half3 EnvironmentBRDFClearCoat(BRDFData brdfData, half clearCoatMask, half3 indirectSpecular, half fresnelTerm)
{
return indirectSpecular * EnvironmentBRDFSpecular(brdfData, fresnelTerm) * clearCoatMask;
}
// Computes the scalar specular term for Minimalist CookTorrance BRDF
// NOTE: needs to be multiplied with reflectance f0, i.e. specular color to complete
half DirectBRDFSpecular(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
{
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// BRDFspec = (D * V * F) / 4.0
// D = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2
// V * F = 1.0 / ( LoH^2 * (roughness + 0.5) )
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
// https://community.arm.com/events/1155
// Final BRDFspec = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2 * (LoH^2 * (roughness + 0.5) * 4.0)
// We further optimize a few light invariant terms
// brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
#if (UNITY_PLATFORM_META_QUEST) // Platform-specific; performance verified on Meta Quest only
// Derive NoH^2 and LoH^2 from scalar dot products.
// This avoids computing halfDir using SafeNormalize (which has 1 rsqrt EFU and more ALU instructions) and two vec3 dot products.
// Where H = half-direction vector, L = light direction, V = view direction,
// Given H = normalize(L + V):
// NoH^2 = (NdotL + NdotV)^2 / (2 + 2*LdotV)
// LoH^2 = (1 + LdotV) / 2
//
// Skip NoH^2 computation and avoid the rcp(2 + 2*LdotV) EFU.
// Since 2 + 2*LdotV = 4*LoH^2 and we determined that 0.00001 is not necessary, we substitute d = NoH^2 * (roughness^2 - 1) + 1.00001 as:
// dNum = d * 4*LoH^2 = NdotLpV^2 * (roughness^2 - 1) + 4*LoH^2
// d^2 = dNum^2 / (16*LoH^2^2)
//
// Now BRDFspec = roughness^2 * 16 * LoH^2^2 / (dNum^2 * max(0.1,LoH^2) * normalizationTerm)
//
// Approximate LoH^2^2 / max(0.1, LoH^2) as max(0.1, LoH^2) to save 2 multiplications.
// Exact when LoH^2 >= 0.1; below 0.1 (LdotV < -0.8) the numerator is clamped rather
// than tapering to zero. The downstream REAL_IS_HALF clamp bounds any resulting overflow.
//
// This further simplifies BRDFspec = roughness^2 * 16 * max(0.1,LoH^2) / (dNum^2 * normalizationTerm)
half NdotL = dot(normalWS, lightDirectionWS);
half NdotV = dot(normalWS, viewDirectionWS);
half LdotV = dot(lightDirectionWS, viewDirectionWS);
// Clamp the sum, not the individual terms — clamping individually breaks the
// identity N.(L+V) = N.L + N.V when N.V < 0 (normal mapping at grazing angles),
// inflating NdotLpV and allowing dNum to reach zero (division by zero).
half NdotLpV = max(0.0h, NdotL + NdotV);
half FourLoH2 = 2.0h + 2.0h * LdotV;
float dNum = float(NdotLpV * NdotLpV * brdfData.roughness2MinusOne) + float(FourLoH2);
half specularTerm = brdfData.roughness2 * (4.0h * max(0.4h, FourLoH2))
/ (half(dNum * dNum) * brdfData.normalizationTerm);
#else
float3 lightDirectionWSFloat3 = float3(lightDirectionWS);
float3 halfDir = SafeNormalize(lightDirectionWSFloat3 + float3(viewDirectionWS));
float NoH = saturate(dot(float3(normalWS), halfDir));
half LoH = half(saturate(dot(lightDirectionWSFloat3, halfDir)));
float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
half LoH2 = LoH * LoH;
half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
#endif
// On platforms where half actually means something, the denominator has a risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if REAL_IS_HALF
specularTerm = specularTerm - HALF_MIN;
// Update: Conservative bump from 100.0 to 1000.0 to better match the full float specular look.
// Roughly 65504.0 / 32*2 == 1023.5,
// or HALF_MAX / ((mobile) MAX_VISIBLE_LIGHTS * 2),
// to reserve half of the per light range for specular and half for diffuse + indirect + emissive.
specularTerm = clamp(specularTerm, 0.0, 1000.0); // Prevent FP16 overflow on mobiles
#endif
return specularTerm;
}
// Based on Minimalist CookTorrance BRDF
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
//
// * NDF [Modified] GGX
// * Modified Kelemen and Szirmay-Kalos for Visibility term
// * Fresnel approximated with 1/LdotH
half3 DirectBDRF(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS, bool specularHighlightsOff)
{
// Can still do compile-time optimisation.
// If no compile-time optimized, extra overhead if branch taken is around +2.5% on some untethered platforms, -10% if not taken.
[branch] if (!specularHighlightsOff)
{
half specularTerm = DirectBRDFSpecular(brdfData, normalWS, lightDirectionWS, viewDirectionWS);
half3 color = brdfData.diffuse + specularTerm * brdfData.specular;
return color;
}
else
return brdfData.diffuse;
}
// Based on Minimalist CookTorrance BRDF
// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255
//
// * NDF [Modified] GGX
// * Modified Kelemen and Szirmay-Kalos for Visibility term
// * Fresnel approximated with 1/LdotH
half3 DirectBRDF(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
return brdfData.diffuse + DirectBRDFSpecular(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * brdfData.specular;
#else
return brdfData.diffuse;
#endif
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e325eaafb90d419598a94581ba3335a4
timeCreated: 1615473362
@@ -0,0 +1,153 @@
#ifndef UNIVERSAL_CLUSTERING_INCLUDED
#define UNIVERSAL_CLUSTERING_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#if USE_CLUSTER_LIGHT_LOOP
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
#define CLUSTER_HAS_REFLECTION_PROBES !(defined(_ENVIRONMENTREFLECTIONS_OFF) || (defined(_REFLECTION_PROBE_ATLAS_KEYWORD_DECLARED) && !defined(_REFLECTION_PROBE_ATLAS)))
// Debug switches for disabling parts of the algorithm. Not implemented for mobile.
#define URP_FP_DISABLE_ZBINNING 0
#define URP_FP_DISABLE_TILING 0
// internal
struct ClusterIterator
{
uint tileWordsOffset;
uint zBinWordsOffset;
uint tileMask;
// Stores the next light index in first 16 bits, and the max light index in the last 16 bits.
uint entityIndexNextMax;
};
// internal
ClusterIterator ClusterInit(float2 normalizedScreenSpaceUV, float3 positionWS, int headerIndex)
{
ClusterIterator state = (ClusterIterator)0;
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
#if UNITY_UV_STARTS_AT_TOP
// RemapFoveatedRenderingNonUniformToLinear expects the UV coordinate to be non-flipped, so we un-flip it before
// the call, and then flip it back afterwards.
normalizedScreenSpaceUV.y = 1.0 - normalizedScreenSpaceUV.y;
#endif
normalizedScreenSpaceUV = RemapFoveatedRenderingNonUniformToLinear(normalizedScreenSpaceUV);
#if UNITY_UV_STARTS_AT_TOP
normalizedScreenSpaceUV.y = 1.0 - normalizedScreenSpaceUV.y;
#endif
}
#endif // SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER
uint2 tileCoord = uint2(normalizedScreenSpaceUV * URP_FP_TILE_SCALE);
uint tileIndex = tileCoord.y * URP_FP_TILE_COUNT_X + tileCoord.x;
#if defined(USING_STEREO_MATRICES)
tileIndex += URP_FP_TILE_COUNT * unity_StereoEyeIndex;
#endif
state.tileWordsOffset = tileIndex * URP_FP_WORDS_PER_TILE;
float viewZ = dot(GetViewForwardDir(), positionWS - GetCameraPositionWS());
uint zBinIndex = (uint)((IsPerspectiveProjection() ? log2(viewZ) : viewZ) * URP_FP_ZBIN_SCALE + URP_FP_ZBIN_OFFSET);
#if defined(USING_STEREO_MATRICES)
zBinIndex += URP_FP_ZBIN_COUNT * unity_StereoEyeIndex;
#endif
// The Zbin buffer is laid out in the following manner:
// ZBin 0 ZBin 1
// .-------------------------^------------------------. .----------------^-------
// | header0 | header1 | word 1 | word 2 | ... | word N | header0 | header 1 | ...
// `----------------v--------------'
// URP_FP_WORDS_PER_TILE
//
// `zBinOffset` should always point to the `header 0` of a ZBin. In the case of
// 'viewZ' lying very close to the far-plane, we need to avoid out-of-bounds indexing
// of the ZBin buffer by clamping to the last ZBin index.
uint zBinLastIndex = URP_FP_ZBIN_COUNT - 1;
#if defined(USING_STEREO_MATRICES)
zBinLastIndex += URP_FP_ZBIN_COUNT * unity_StereoEyeIndex;
#endif
uint zBinStride = (2 + URP_FP_WORDS_PER_TILE);
uint zBinOffset = min(zBinIndex, zBinLastIndex) * zBinStride;
uint zBinHeaderIndex = zBinOffset + headerIndex;
state.zBinWordsOffset = zBinOffset + 2;
#if !URP_FP_DISABLE_ZBINNING
uint header = Select4(asuint(urp_ZBins[zBinHeaderIndex / 4]), zBinHeaderIndex % 4);
#else
uint header;
if (headerIndex == 0)
{
// If URP_FP_PROBES_BEGIN is 0, set the header to an invalid header that skips iteration
header = (int(URP_FP_PROBES_BEGIN) - 1) < 0 ? 0x0000FFFFu : ((URP_FP_PROBES_BEGIN - 1) << 16);
}
else
{
header = (((URP_FP_WORDS_PER_TILE * 32 - 1) << 16) | URP_FP_PROBES_BEGIN);
}
#endif
#if MAX_LIGHTS_PER_TILE > 32 || CLUSTER_HAS_REFLECTION_PROBES
state.entityIndexNextMax = header;
#else
uint tileWordIndex = state.tileWordsOffset;
uint zBinWordIndex = state.zBinWordsOffset;
if (URP_FP_WORDS_PER_TILE > 0)
{
state.tileMask =
#if !URP_FP_DISABLE_TILING
Select4(asuint(urp_Tiles[tileWordIndex / 4]), tileWordIndex % 4) &
#endif
#if !URP_FP_DISABLE_ZBINNING
Select4(asuint(urp_ZBins[zBinWordIndex / 4]), zBinWordIndex % 4) &
#endif
(0xFFFFFFFFu << (header & 0x1F)) & (0xFFFFFFFFu >> (31 - (header >> 16)));
}
#endif
return state;
}
// internal
bool ClusterNext(inout ClusterIterator it, out uint entityIndex)
{
#if MAX_LIGHTS_PER_TILE > 32 || CLUSTER_HAS_REFLECTION_PROBES
uint maxIndex = it.entityIndexNextMax >> 16;
[loop] while (it.tileMask == 0 && (it.entityIndexNextMax & 0xFFFF) <= maxIndex)
{
// Extract the lower 16 bits and shift by 5 to divide by 32.
uint wordIndex = ((it.entityIndexNextMax & 0xFFFF) >> 5);
uint tileWordIndex = it.tileWordsOffset + wordIndex;
uint zBinWordIndex = it.zBinWordsOffset + wordIndex;
it.tileMask =
#if !URP_FP_DISABLE_TILING
Select4(asuint(urp_Tiles[tileWordIndex / 4]), tileWordIndex % 4) &
#endif
#if !URP_FP_DISABLE_ZBINNING
Select4(asuint(urp_ZBins[zBinWordIndex / 4]), zBinWordIndex % 4) &
#endif
// Mask out the beginning and end of the word.
(0xFFFFFFFFu << (it.entityIndexNextMax & 0x1F)) & (0xFFFFFFFFu >> (31 - min(31, maxIndex - wordIndex * 32)));
// The light index can start at a non-multiple of 32, but the following iterations should always be multiples of 32.
// So we add 32 and mask out the lower bits.
it.entityIndexNextMax = (it.entityIndexNextMax + 32) & ~31;
}
#endif
bool hasNext = it.tileMask != 0;
uint bitIndex = firstbitlow(it.tileMask);
it.tileMask ^= (1u << bitIndex);
#if MAX_LIGHTS_PER_TILE > 32 || CLUSTER_HAS_REFLECTION_PROBES
// Subtract 32 because it stores the index of the _next_ word to fetch, but we want the current.
// The upper 16 bits and bits representing values < 32 are masked out. The latter is due to the fact that it will be
// included in what firstbitlow returns.
entityIndex = (((it.entityIndexNextMax - 32) & (0xFFFFu & ~31))) + bitIndex;
#else
entityIndex = bitIndex;
#endif
return hasNext;
}
#endif // USE_CLUSTER_LIGHT_LOOP
#endif // UNIVERSAL_CLUSTERING_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5c52f3d26791c415b9e887442bfc817c
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,669 @@
#ifndef UNIVERSAL_SSR_INCLUDED
#define UNIVERSAL_SSR_INCLUDED
// Includes
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ScreenSpaceReflectionCommon.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
// Textures & Samplers
TEXTURE2D_X(_CameraColorTexture);
SAMPLER(sampler_CameraColorTexture);
TEXTURE2D_X(_SmoothnessTexture);
SAMPLER(sampler_SmoothnessTexture);
TEXTURE2D_X(_MotionVectorColorTexture);
SAMPLER(sampler_MotionVectorColorTexture);
TEXTURE2D_X(_LastFrameCameraDepthTexture);
SAMPLER(sampler_BlitTexture);
// Params
float4x4 _CameraViewProjections[2];
float4x4 _CameraInverseViewProjections[2];
float4x4 _CameraProjections[2];
float4x4 _CameraInverseProjections[2];
float4x4 _CameraViews[2];
float4 _CameraDeltaJitterOffset;
float4 _SourceSize;
TYPED_TEXTURE2D_X(float, _DepthPyramid);
float4 _DepthPyramidMipLevelOffsets[15];
int _SsrDepthPyramidMaxMip;
// SSR Settings
float4 _MaxRayLength;
int _MaxRaySteps;
uint _Downsample;
int _HiZTrace;
int _HitRefinementSteps;
float4 _ThicknessScaleAndBias;
float4 _SmoothnessAndStrengthAndClamp;
float4 _ScreenEdgeFadeAndViewConeDot;
int _ReflectSky;
float GetMaxRayLength()
{
return _MaxRayLength.x;
}
float GetRayLengthFadeStart()
{
return _MaxRayLength.y;
}
float GetThicknessScale()
{
return _ThicknessScaleAndBias.x;
}
float GetThicknessBias()
{
return _ThicknessScaleAndBias.y;
}
float GetThicknessScaleFine()
{
return _ThicknessScaleAndBias.z;
}
float GetThicknessBiasFine()
{
return _ThicknessScaleAndBias.w;
}
float GetViewConeDot()
{
return _ScreenEdgeFadeAndViewConeDot.z;
}
float2 GetScreenEdgeFade()
{
return _ScreenEdgeFadeAndViewConeDot.xy;
}
float GetMinimumSmoothness()
{
return _SmoothnessAndStrengthAndClamp.x;
}
float GetStrength()
{
return _SmoothnessAndStrengthAndClamp.z;
}
float GetClampValue()
{
return _SmoothnessAndStrengthAndClamp.w * GetCurrentExposureMultiplier();
}
#if defined(USING_STEREO_MATRICES)
#define unity_eyeIndex unity_StereoEyeIndex
#else
#define unity_eyeIndex 0
#endif
// Constants
#define SSR_TRACE_EPS 0.000488281f
// ------------------------------------------------------------------
// Screen Space Marching
// ------------------------------------------------------------------
bool TraceScreenSpaceRay(
float2 startPosSS,
float startZ,
float2 endPosSS,
float endZ,
float4 screenSizeWithInverse,
out float3 rayHitPosNDC,
out int iterCount)
{
// Calculate the step to take each iteration, and the total step count
float rayScreenDeltaX = endPosSS.x - startPosSS.x;
float rayScreenDeltaY = endPosSS.y - startPosSS.y;
float rayScreenDeltaZ = endZ - startZ;
float useDeltaX = abs(rayScreenDeltaX) >= abs(rayScreenDeltaY) ? 1.0 : 0.0;
float rayScreenDelta = min(lerp(abs(rayScreenDeltaY), abs(rayScreenDeltaX), useDeltaX), _MaxRaySteps);
float3 rayStep = float3(rayScreenDeltaX, rayScreenDeltaY, rayScreenDeltaZ) / max(rayScreenDelta, 0.001);
// March against depth buffer with coarse steps
float3 rayPosSS = float3(startPosSS, startZ);
float rayHitT = 0;
rayHitPosNDC = 0;
float prevT = 0;
bool hitCoarse = false;
float rawSceneDepth = startZ;
for (iterCount = 0; iterCount < rayScreenDelta; iterCount++)
{
rayPosSS += rayStep;
// We went offscreen, so stop
if (rayPosSS.x < 0 || rayPosSS.x > screenSizeWithInverse.z || rayPosSS.y < 0 || rayPosSS.y > screenSizeWithInverse.w)
return false;
// How far along the ray are we in [0; 1]?
rayHitT = lerp((rayPosSS.y - startPosSS.y) / rayScreenDeltaY, (rayPosSS.x - startPosSS.x) / rayScreenDeltaX, useDeltaX);
// Get current depth of scene at the ray position.
rawSceneDepth = LoadSceneDepth(rayPosSS.xy * _Downsample);
// Check if we've hit something
bool aboveBase = !COMPARE_DEVICE_DEPTH_CLOSER(rayPosSS.z, rawSceneDepth);
bool belowFloor = COMPARE_DEVICE_DEPTH_CLOSER(rayPosSS.z, rawSceneDepth * GetThicknessScale() + GetThicknessBias());
if (aboveBase && belowFloor)
{
hitCoarse = true;
break;
}
prevT = rayHitT;
}
rayHitPosNDC = float3(rayPosSS.xy * screenSizeWithInverse.xy, rayPosSS.z);
#ifdef _REFINE_DEPTH
if (hitCoarse)
{
// Refine depth by testing intersections at points between the last 2 coarse positions,
// using a smaller thickness value.
float t0 = prevT;
float t1 = 2.0 * rayHitT - t0;
int step = 0;
bool hitFine = false;
for (; step < _HitRefinementSteps; step++)
{
float t = t0 + (t1 - t0) * 0.5;
float2 candidateHitPosSS = lerp(startPosSS, endPosSS, t);
candidateHitPosSS = round(candidateHitPosSS - 0.5) + 0.5; // round to nearest texel center
float rayDepth = lerp(startZ, endZ, t);
float rawSceneDepthFine = LoadSceneDepth(candidateHitPosSS * _Downsample);
bool aboveBase = !COMPARE_DEVICE_DEPTH_CLOSER(rayDepth, rawSceneDepthFine);
bool belowFloor = COMPARE_DEVICE_DEPTH_CLOSER(rayDepth, rawSceneDepthFine * GetThicknessScale() + GetThicknessBias());
[branch]
if (aboveBase && belowFloor)
{
hitFine = COMPARE_DEVICE_DEPTH_CLOSER(rayDepth, rawSceneDepthFine * GetThicknessScaleFine() + GetThicknessBiasFine());
rayHitPosNDC = float3(candidateHitPosSS * screenSizeWithInverse.xy, rayDepth);
t1 = t;
}
else
{
t0 = t;
}
}
iterCount += step;
if (!hitFine)
return false;
}
#endif
// If we have a hit, we are done.
if (hitCoarse)
return true;
// If we hit no geometry, and the depth is at the far plane, we have hit the skybox.
// Treat it as a valid hit if _ReflectSky is enabled, otherwise return false.
UNITY_BRANCH
if (_ReflectSky)
{
rayHitPosNDC.z = UNITY_RAW_FAR_CLIP_VALUE;
return rawSceneDepth == UNITY_RAW_FAR_CLIP_VALUE;
}
return false;
}
bool TraceScreenSpaceRayHiZ(
float2 startPosSS,
float startZ,
float2 endPosSS,
float endZ,
float2 screenSize,
out float3 rayHitPosNDC,
out int iterCount)
{
// We start tracing from the center of the current pixel, and do so up to the far plane.
float3 rayOrigin = float3(startPosSS, startZ);
float3 rayDir = float3(endPosSS, endZ) - rayOrigin;
float3 rcpRayDir = rcp(rayDir);
int2 rayStep = int2(rcpRayDir.x >= 0 ? 1 : 0,
rcpRayDir.y >= 0 ? 1 : 0);
float3 raySign = float3(rcpRayDir.x >= 0 ? 1 : -1,
rcpRayDir.y >= 0 ? 1 : -1,
rcpRayDir.z >= 0 ? 1 : -1);
bool rayTowardsEye = COMPARE_DEVICE_DEPTH_CLOSEREQUAL(rcpRayDir.z, 0);
// Extend and clip the end point to the frustum.
float tMax;
{
// Shrink the frustum by half a texel for efficiency reasons.
const float halfTexel = 0.5;
float3 bounds;
bounds.x = (rcpRayDir.x >= 0) ? screenSize.x - halfTexel : halfTexel;
bounds.y = (rcpRayDir.y >= 0) ? screenSize.y - halfTexel : halfTexel;
// If we do not want to intersect the skybox, it is more efficient to not trace too far.
float maxDepth = (_ReflectSky != 0) ? -0.00000024 : 0.00000024; // 2^-22
#if !defined(UNITY_REVERSED_Z)
maxDepth = 1.0-maxDepth;
#endif
bounds.z = rayTowardsEye ? (1.0-UNITY_RAW_FAR_CLIP_VALUE) : maxDepth;
float3 dist = bounds * rcpRayDir - (rayOrigin * rcpRayDir);
tMax = Min3(dist.x, dist.y, dist.z);
}
// Clamp the MIP level to give the compiler more information to optimize.
const int maxMipLevel = min(_SsrDepthPyramidMaxMip, 14);
// Start ray marching from the next texel to avoid self-intersections.
float t;
{
// 'rayOrigin' is the exact texel center.
float2 dist = abs(0.5 * rcpRayDir.xy);
t = min(dist.x, dist.y);
}
float3 rayPos;
int mipLevel = 0;
iterCount = 0;
bool hit = false;
bool miss = false;
bool belowMip0 = false; // This value is set prior to entering the cell
while (!(hit || miss) && (t <= tMax) && (iterCount < _MaxRaySteps))
{
rayPos = rayOrigin + t * rayDir;
// Ray position often ends up on the edge. To determine (and look up) the right cell,
// we need to bias the position by a small epsilon in the direction of the ray.
float2 sgnEdgeDist = round(rayPos.xy) - rayPos.xy;
float2 satEdgeDist = clamp(raySign.xy * sgnEdgeDist + SSR_TRACE_EPS, 0, SSR_TRACE_EPS);
rayPos.xy += raySign.xy * satEdgeDist;
int2 mipCoord = (int2)rayPos.xy >> mipLevel;
int2 mipOffset = int2(_DepthPyramidMipLevelOffsets[mipLevel].xy);
// Bounds define 4 faces of a cube:
// 2 walls in front of the ray, and a floor and a base below it.
float4 bounds;
bounds.xy = (mipCoord + rayStep) << mipLevel;
bounds.z = LOAD_TEXTURE2D_X_LOD(_DepthPyramid, int2(mipOffset + mipCoord), 0).r;
// We define the depth of the base as the depth value as:
// b = DeviceDepth((1 + thickness) * LinearDepth(d))
// b = ((f - n) * d + n * (1 - (1 + thickness))) / ((f - n) * (1 + thickness))
// b = ((f - n) * d - n * thickness) / ((f - n) * (1 + thickness))
// b = d / (1 + thickness) - n / (f - n) * (thickness / (1 + thickness))
// b = d * k_s + k_b
bounds.w = bounds.z * GetThicknessScale() + GetThicknessBias();
float4 dist = bounds * rcpRayDir.xyzz - (rayOrigin.xyzz * rcpRayDir.xyzz);
float distWall = min(dist.x, dist.y);
float distFloor = dist.z;
float distBase = dist.w;
// Note: 'rayPos' given by 't' can correspond to one of several depth values:
// - above or exactly on the floor
// - inside the floor (between the floor and the base)
// - below the base
bool belowFloor = !COMPARE_DEVICE_DEPTH_CLOSER(rayPos.z, bounds.z);
bool aboveBase = COMPARE_DEVICE_DEPTH_CLOSEREQUAL(rayPos.z, bounds.w);
bool insideFloor = belowFloor && aboveBase;
bool hitFloor = (t <= distFloor) && (distFloor <= distWall);
// Game rules:
// * if the closest intersection is with the wall of the cell, switch to the coarser MIP, and advance the ray.
// * if the closest intersection is with the heightmap below, switch to the finer MIP, and advance the ray.
// * if the closest intersection is with the heightmap above, switch to the finer MIP, and do NOT advance the ray.
// Victory conditions:
// * See below. Do NOT reorder the statements!
miss = belowMip0 && insideFloor;
hit = (mipLevel == 0) && (hitFloor || insideFloor);
belowMip0 = (mipLevel == 0) && belowFloor;
// 'distFloor' can be smaller than the current distance 't'.
// We can also safely ignore 'distBase'.
// If we hit the floor, it's always safe to jump there.
// If we are at (mipLevel != 0) and we are below the floor, we should not move.
t = hitFloor ? distFloor : (((mipLevel != 0) && belowFloor) ? t : distWall);
rayPos.z = bounds.z; // Retain the depth of the potential intersection
// Warning: both rays towards the eye, and tracing behind objects has linear
// rather than logarithmic complexity! This is due to the fact that we only store
// the maximum value of depth, and not the min-max.
mipLevel += (hitFloor || belowFloor || rayTowardsEye) ? -1 : 1;
mipLevel = clamp(mipLevel, 0, maxMipLevel);
// mipLevel = 0;
iterCount++;
}
// Treat intersections with the sky as misses.
miss = miss || ((_ReflectSky == 0) && (rayPos.z == UNITY_RAW_FAR_CLIP_VALUE));
hit = hit && !miss;
rayHitPosNDC = float3(floor(rayPos.xy) / screenSize + (0.5 / screenSize), rayPos.z);
return hit;
}
float2 SampleMotionVector(float2 uv)
{
return SAMPLE_TEXTURE2D_X(_MotionVectorColorTexture, sampler_MotionVectorColorTexture, uv).xy;
}
float SampleSmoothness(float2 uv)
{
return SAMPLE_TEXTURE2D_X(_SmoothnessTexture, sampler_SmoothnessTexture, uv).a;
}
float3 ClampColor(float3 color)
{
float maxChannel = Max3(color.r, color.g, color.b);
float scale = maxChannel > GetClampValue() ? GetClampValue() / maxChannel : 1;
return scale * color;
}
float4 ComputeSSR(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 positionNDC = input.texcoord;
float2 positionSS = input.positionCS.xy;
float deviceDepth = LoadSceneDepth(uint2(positionSS) * _Downsample).r;
// If the smoothness is below our minimum, don't do any raymarching
float perceptualSmoothness = SampleSmoothness(positionNDC);
UNITY_BRANCH if (perceptualSmoothness <= GetMinimumSmoothness())
{
// Output the framebuffer color ->
// avoids bleeding black/uninitialized texels into reflections when blurring.
// If the pixel is showing skybox, output 0 alpha ->
// avoids bleeding the skybox color into reflections when blurring, which would cause haloing.
// If the pixel is showing an object, output 1 alpha ->
// avoids bleeding 0 alpha into reflections when blurring, which would cause peter-panning.
float alpha = deviceDepth != UNITY_RAW_FAR_CLIP_VALUE;
return float4(ClampColor(SAMPLE_TEXTURE2D_X_LOD(_CameraColorTexture, sampler_CameraColorTexture, positionNDC, 0).rgb), alpha);
}
// Calculate ray origin and direction in world space
float3 normalWS = SampleSceneNormals(positionNDC);
float3 positionWS = ComputeWorldSpacePosition(positionNDC, deviceDepth, _CameraInverseViewProjections[unity_eyeIndex]);
float3 positionToCamWS = GetWorldSpaceNormalizeViewDir(positionWS);
float3 rayDirWS = reflect(-positionToCamWS, normalWS);
// Apply normal bias with the magnitude dependent on the distance from the camera.
float3 camPosWS = GetCurrentViewPosition();
positionWS = camPosWS + (positionWS - camPosWS) * (1 - 0.001 * _Downsample * rcp(max(dot(normalWS, positionToCamWS), FLT_EPS)));
deviceDepth = ComputeNormalizedDeviceCoordinatesWithZ(positionWS, _CameraViewProjections[unity_eyeIndex]).z;
// Transform ray origin and direction to view space.
float3 positionVS = mul(_CameraViews[unity_eyeIndex], float4(positionWS, 1)).xyz;
float3 rayDirVS = SafeNormalize(mul(_CameraViews[unity_eyeIndex], float4(rayDirWS, 0)).xyz);
// Clamp ray length such that the end point is in front of the camera.
float maxRayLength = 1;
#ifndef _HIZ_TRACE
maxRayLength = GetMaxRayLength();
#endif
float rayLength = rayDirVS.z > 0 ? min(maxRayLength, -positionVS.z / rayDirVS.z * 0.999) : maxRayLength;
// Calculate ray end position in view space and screen space
float3 endPosVS = positionVS + rayDirVS * rayLength;
float3 startPosNDC = float3(positionNDC, deviceDepth);
float3 endPosNDC = ComputeNormalizedDeviceCoordinatesWithZ(endPosVS, _CameraProjections[unity_eyeIndex]);
#ifndef _HIZ_TRACE
// Clamp ray length such that the end point is within the view frustum.
// Not needed for Hi-Z path as there is no end point, only a direction.
float3 rayDeltaNDC = endPosNDC - startPosNDC;
float rayLengthNDC = length(rayDeltaNDC);
float3 rayDirNDC = rayDeltaNDC * rcp(rayLengthNDC);
float3 maxDistanceNDC = rayDirNDC >= 0 ? (1 - startPosNDC) / rayDirNDC : -startPosNDC / rayDirNDC;
endPosNDC = startPosNDC + rayDirNDC * min(rayLengthNDC, min(maxDistanceNDC.x, min(maxDistanceNDC.y, maxDistanceNDC.z)));
#endif
float4 screenSizeWithInverse = _BlitTexture_TexelSize;
float2 endPosSS = endPosNDC.xy * screenSizeWithInverse.zw;
float3 rayHitPosNDC;
int iterCount;
bool hit;
#ifdef _HIZ_TRACE
hit = TraceScreenSpaceRayHiZ(positionSS, deviceDepth, endPosSS.xy, endPosNDC.z, screenSizeWithInverse.zw, rayHitPosNDC, iterCount);
#else
hit = TraceScreenSpaceRay(positionSS, deviceDepth, endPosSS.xy, endPosNDC.z, screenSizeWithInverse, rayHitPosNDC, iterCount);
#endif
UNITY_BRANCH if (hit)
{
const bool hitIsSky = rayHitPosNDC.z == UNITY_RAW_FAR_CLIP_VALUE;
#ifdef _USE_MOTION_VECTORS
// Reproject position
rayHitPosNDC.xy -= SampleMotionVector(rayHitPosNDC.xy);
// Compensate for jittering
rayHitPosNDC.xy -= _CameraDeltaJitterOffset.xy;
const float2 downsampledScreenSize = screenSizeWithInverse.zw * _Downsample;
const int2 topLeftReprojectedPixelPos = int2(rayHitPosNDC.xy * downsampledScreenSize - 0.5);
// Manually apply bilinear filter at the reprojected position
float3 hitColor = 0;
float weightSum = 0;
for (int dx = 0; dx < 2; dx++)
{
for (int dy = 0; dy < 2; dy++)
{
const int2 samplePixelPos = topLeftReprojectedPixelPos + int2(dx, dy);
const float2 samplePixelCenter = float2(samplePixelPos) + 0.5;
// Reject samples that are off-screen
const bool isInView = all(0 <= samplePixelPos && samplePixelPos < downsampledScreenSize);
if (!isInView)
continue;
// We are either reflecting the sky or not, never mix sky and non-sky hits.
const float sampleDeviceDepth = LOAD_TEXTURE2D_X_LOD(_LastFrameCameraDepthTexture, samplePixelPos, 0).x;
const bool sampleIsSky = sampleDeviceDepth == UNITY_RAW_FAR_CLIP_VALUE;
if (sampleIsSky != hitIsSky)
continue;
// Calculate bilinear weight and accumulate
const float weight =
(1.0f - abs(rayHitPosNDC.x * downsampledScreenSize.x - samplePixelCenter.x)) *
(1.0f - abs(rayHitPosNDC.y * downsampledScreenSize.y - samplePixelCenter.y));
const float3 sampleColor = LOAD_TEXTURE2D_X_LOD(_CameraColorTexture, samplePixelPos, 0).rgb;
hitColor += weight * sampleColor;
weightSum += weight;
}
}
// If we got no valid samples, just return the existing framebuffer color. The sample is invalid if the total
// sum of weights is 0 but due to precision issues if the total weight is extremely low (which can lead
// to wrongly high color values, once divided by it) we check if the total weight is under an epsilon
// value instead.
const float k_MinimumWeight = 1e-3;
if (weightSum < k_MinimumWeight)
return float4(ClampColor(SAMPLE_TEXTURE2D_X_LOD(_CameraColorTexture, sampler_CameraColorTexture, positionNDC, 0).rgb), 0);
else
hitColor /= weightSum;
#else
float3 hitColor = SAMPLE_TEXTURE2D_X_LOD(_CameraColorTexture, sampler_CameraColorTexture, rayHitPosNDC.xy, 0).rgb;
#endif
// Fade rays pointing toward camera.
float viewDotRay = dot(SafeNormalize(positionVS), rayDirVS);
float viewConeDot = GetViewConeDot();
const float normalFadeFactor = 0.1;
float fade = smoothstep(viewConeDot, viewConeDot + normalFadeFactor, viewDotRay);
// Fade rays hitting near the max distance, if we aren't reflecting the sky.
#ifndef _HIZ_TRACE
if (!hitIsSky)
{
float4 rayHitPosCS = ComputeClipSpacePosition(rayHitPosNDC.xy, rayHitPosNDC.z);
float4 rayHitPosVS = mul(_CameraInverseProjections[unity_eyeIndex], rayHitPosCS);
rayHitPosVS.xyz /= rayHitPosVS.w;
fade *= smoothstep(maxRayLength, GetRayLengthFadeStart(), distance(positionVS, rayHitPosVS.xyz));
}
#endif
// Fade rays reaching near the edge of the screen, to avoid a harsh discontinuity.
float2 edgeDist = smoothstep(0, GetScreenEdgeFade().x, rayHitPosNDC.xy) * smoothstep(1, GetScreenEdgeFade().y, rayHitPosNDC.xy);
fade *= edgeDist.x * edgeDist.y;
// Scale the SSR contribution by the user-defined strength.
fade *= GetStrength();
return float4(ClampColor(hitColor), fade);
}
// Even if we hit nothing, we output the framebuffer color (but with 0 weight).
// This provides the blur/upscale kernel with data needed to avoid blurring black into
// the reflections, which leads to ugly borders.
return float4(ClampColor(SAMPLE_TEXTURE2D_X_LOD(_CameraColorTexture, sampler_CameraColorTexture, positionNDC, 0).rgb), 0);
}
// ------------------------------------------------------------------
// Compositing for AfterOpaque mode
// ------------------------------------------------------------------
float4 CompositeSSRAfterOpaque(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord;
// Reconstruct world position
float2 positionNDC = uv;
float deviceDepth = SampleSceneDepth(uv).r;
float3 positionWS = ComputeWorldSpacePosition(positionNDC, deviceDepth, _CameraInverseViewProjections[unity_eyeIndex]);
float perceptualSmoothness = SAMPLE_TEXTURE2D_X(_SmoothnessTexture, sampler_SmoothnessTexture, uv).a;
float perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(perceptualSmoothness);
// Map roughness to mip level to get blur.
float mipLevel = GetSSRMipLevelFromPerceptualRoughness(positionWS, perceptualRoughness);
float4 reflColor = SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_TrilinearClamp, uv, mipLevel);
// Fade out reflections with smoothness.
// Not physically correct, but we can't do much better without more data.
float fadeStart = _ScreenSpaceReflectionParam.y;
float fadeEnd = _ScreenSpaceReflectionParam.z;
reflColor.a *= smoothstep(fadeStart, fadeEnd, perceptualSmoothness);
return reflColor;
}
// ------------------------------------------------------------------
// Upscaling
// ------------------------------------------------------------------
float4 BilinearUpscale(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, input.texcoord);
}
float CompareNormal(float3 d1, float3 d2)
{
return smoothstep(0.8, 1.0, dot(d1, d2));
}
float4 BilateralUpscale(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float4 texelSize = _BlitTexture_TexelSize;
float2 uv = input.texcoord;
// Position of texel, [0; LowResTextureSize]
float2 texelPos = uv * texelSize.zw - 0.5;
// Position of top-left texel center in bilinear neighborhood, [0; LowResTextureSize]
float2 topLeftTexelPos = floor(texelPos) + 0.5;
// Offset in texel, [0; 1]
float2 offsetInTexel = frac(texelPos);
float3 normalRef = SampleSceneNormals(uv);
float4 result = 0;
float weightSum = 0;
for (int dx = 0; dx < 2; dx++)
{
for (int dy = 0; dy < 2; dy++)
{
// Reject off-screen samples.
float2 sampleTexelPos = topLeftTexelPos + float2(dx, dy);
const bool isInView = all(0 <= sampleTexelPos && sampleTexelPos < texelSize.zw);
if (!isInView)
continue;
// Sample color and normal from bilinear neighborhood.
float2 sampleUvPos = sampleTexelPos * texelSize.xy;
float4 sampleColor = LOAD_TEXTURE2D_X(_BlitTexture, sampleTexelPos);
float3 sampleNormal = SampleSceneNormals(sampleUvPos);
// Bilinear weight.
float weight =
(dx ? offsetInTexel.x : 1.0 - offsetInTexel.x) *
(dy ? offsetInTexel.y : 1.0 - offsetInTexel.y);
// Bilateral weight. Clamped to prevent division by 0, and also to ensure we get a
// reasonable value when none of the samples pass the normal comparison condition.
const float k_MinWeight = 0.01;
weight *= max(k_MinWeight, CompareNormal(normalRef, sampleNormal));
result += sampleColor * weight;
weightSum += weight;
}
}
return result * rcp(weightSum);
}
// ------------------------------------------------------------------
// Temporal Filtering
// ------------------------------------------------------------------
TEXTURE2D_X(_ReflectionHistoryTexture);
float _BaseBlendFactor;
float4 SSRTemporalFiltering(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
// Reproject pixel position, get current and last frame color
int2 pixelCoord = input.positionCS.xy;
float2 reprojectedUv = input.texcoord - SampleMotionVector(input.texcoord);
float4 current = LOAD_TEXTURE2D_X(_BlitTexture, pixelCoord);
float4 history = SAMPLE_TEXTURE2D_X(_ReflectionHistoryTexture, sampler_LinearClamp, reprojectedUv);
// Take 4 taps around center in a cross pattern
float4 nb0 = LOAD_TEXTURE2D_X(_BlitTexture, pixelCoord + int2( 0, 1));
float4 nb1 = LOAD_TEXTURE2D_X(_BlitTexture, pixelCoord + int2( 0, -1));
float4 nb2 = LOAD_TEXTURE2D_X(_BlitTexture, pixelCoord + int2( 1, 0));
float4 nb3 = LOAD_TEXTURE2D_X(_BlitTexture, pixelCoord + int2(-1, 0));
// Neighborhood clamping
float4 boxMin = min(min(min(min(current, nb0), nb1), nb2), nb3);
float4 boxMax = max(max(max(max(current, nb0), nb1), nb2), nb3);
history = clamp(history, boxMin, boxMax);
// If outside screen, ignore history
float blendFactor = _BaseBlendFactor;
if (any(reprojectedUv < 0) || any(reprojectedUv > 1))
blendFactor = 0.0;
return lerp(current, history, blendFactor);
}
#endif //UNIVERSAL_SSR_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3ea3b96bfb18c244d807bea74fe8a9d5
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,277 @@
#ifndef UNIVERSAL_PIPELINE_CORE_INCLUDED
#define UNIVERSAL_PIPELINE_CORE_INCLUDED
// VT is not supported in URP (for now) this ensures any shaders using the VT
// node work by falling to regular texture sampling.
#define FORCE_VIRTUAL_TEXTURING_OFF 1
// _FORWARD_PLUS keyword deprecated in 6.1
// We will emit a warning and define _CLUSTER_LIGHT_LOOP for backwards compatibility.
// This block will be removed in a future release.
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ForwardPlusKeyword.deprecated.hlsl"
#if defined(_CLUSTER_LIGHT_LOOP)
#define USE_CLUSTER_LIGHT_LOOP 1
#else
#define USE_CLUSTER_LIGHT_LOOP 0
#endif
#if USE_CLUSTER_LIGHT_LOOP
#define _ADDITIONAL_LIGHTS 1
#undef _ADDITIONAL_LIGHTS_VERTEX
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#if UNITY_REVERSED_Z
// TODO: workaround. There's a bug where SHADER_API_GL_CORE gets erroneously defined on switch.
#if (defined(SHADER_API_GLCORE) && !defined(SHADER_API_SWITCH) && !defined(SHADER_API_SWITCH2)) || defined(SHADER_API_GLES3)
//GL with reversed z => z clip range is [near, -far] -> remapping to [0, far]
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max((coord - _ProjectionParams.y)/(-_ProjectionParams.z-_ProjectionParams.y)*_ProjectionParams.z, 0)
#else
//D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far]
//max is required to protect ourselves from near plane not being correct/meaningful in case of oblique matrices.
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0)
#endif
#elif UNITY_UV_STARTS_AT_TOP
//D3d without reversed z => z clip range is [0, far] -> nothing to do
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#else
//Opengl => z clip range is [-near, far] -> remapping to [0, far]
#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((coord + _ProjectionParams.y)/(_ProjectionParams.z+_ProjectionParams.y))*_ProjectionParams.z, 0)
#endif
// Stereo-related bits
#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#define SLICE_ARRAY_INDEX unity_StereoEyeIndex
#define TEXTURE2D_X(textureName) TEXTURE2D_ARRAY(textureName)
#define TYPED_TEXTURE2D_X(type, textureName) TYPED_TEXTURE2D_ARRAY(type, textureName)
#define TEXTURE2D_X_PARAM(textureName, samplerName) TEXTURE2D_ARRAY_PARAM(textureName, samplerName)
#define TEXTURE2D_X_ARGS(textureName, samplerName) TEXTURE2D_ARRAY_ARGS(textureName, samplerName)
#define TEXTURE2D_X_HALF(textureName) TEXTURE2D_ARRAY_HALF(textureName)
#define TEXTURE2D_X_FLOAT(textureName) TEXTURE2D_ARRAY_FLOAT(textureName)
// We need to redeclare these macros for XR reasons to actually utilise the Texture2DArrays
// TODO: add MSAA support, which is not being used anywhere in URP at the moment
#undef FRAMEBUFFER_INPUT_X_HALF
#undef FRAMEBUFFER_INPUT_X_FLOAT
#undef FRAMEBUFFER_INPUT_X_INT
#undef FRAMEBUFFER_INPUT_X_UINT
#undef LOAD_FRAMEBUFFER_X_INPUT
#undef LOAD_FRAMEBUFFER_INPUT_X
#undef FRAMEBUFFER_INPUT_X_HALF_MS
#undef FRAMEBUFFER_INPUT_X_FLOAT_MS
#undef FRAMEBUFFER_INPUT_X_INT_MS
#undef FRAMEBUFFER_INPUT_X_UINT_MS
#undef LOAD_FRAMEBUFFER_INPUT_X_MS
#if defined(SHADER_API_METAL) && defined(UNITY_NEEDS_RENDERPASS_FBFETCH_FALLBACK)
#define RENDERPASS_DECLARE_FALLBACK_X(T, idx) \
Texture2DArray<T> _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize; \
inline T ReadFBInput_##idx(bool var, uint2 coord) { \
[branch]if(var) { return hlslcc_fbinput_##idx; } \
else { return _UnityFBInput##idx.Load(uint4(coord, SLICE_ARRAY_INDEX, 0)); } \
}
#define FRAMEBUFFER_INPUT_X_HALF(idx) cbuffer hlslcc_SubpassInput_f_##idx { half4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_X(half4, idx)
#define FRAMEBUFFER_INPUT_X_FLOAT(idx) cbuffer hlslcc_SubpassInput_f_##idx { float4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_X(float4, idx)
#define FRAMEBUFFER_INPUT_X_INT(idx) cbuffer hlslcc_SubpassInput_f_##idx { int4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_X(int4, idx)
#define FRAMEBUFFER_INPUT_X_UINT(idx) cbuffer hlslcc_SubpassInput_f_##idx { uint4 hlslcc_fbinput_##idx; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_X(uint4, idx)
#define LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname) ReadFBInput_##idx(hlslcc_fbfetch_##idx, uint2(v2fname.xy))
#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname)
#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) cbuffer hlslcc_SubpassInput_F_##idx { float4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_MS_X(float4, idx)
#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) cbuffer hlslcc_SubpassInput_H_##idx { half4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_MS_X(half4, idx)
#define FRAMEBUFFER_INPUT_X_INT_MS(idx) cbuffer hlslcc_SubpassInput_I_##idx { int4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_MS_X(int4, idx)
#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) cbuffer hlslcc_SubpassInput_U_##idx { uint4 hlslcc_fbinput_##idx[8]; bool hlslcc_fbfetch_##idx; }; \
RENDERPASS_DECLARE_FALLBACK_MS(uint4, idx)
#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fname) ReadFBInput_##idx(hlslcc_fbfetch_##idx, uint2(v2fname.xy), sampleIdx)
#elif !defined(PLATFORM_SUPPORTS_NATIVE_RENDERPASS)
#define FRAMEBUFFER_INPUT_X_HALF(idx) TEXTURE2D_X_HALF(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize
#define FRAMEBUFFER_INPUT_X_FLOAT(idx) TEXTURE2D_X_FLOAT(_UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize
#define FRAMEBUFFER_INPUT_X_INT(idx) TYPED_TEXTURE2D_X(int4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize
#define FRAMEBUFFER_INPUT_X_UINT(idx) TYPED_TEXTURE2D_X(uint4, _UnityFBInput##idx); float4 _UnityFBInput##idx##_TexelSize
#define LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname) LOAD_TEXTURE2D_ARRAY(_UnityFBInput##idx, v2fname.xy, SLICE_ARRAY_INDEX)
#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname)
#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) Texture2DMSArray<float4> _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize
#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) Texture2DMSArray<float4> _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize
#define FRAMEBUFFER_INPUT_X_INT_MS(idx) Texture2DMSArray<int4> _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize
#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) Texture2DMSArray<uint4> _UnityFBInput##idx; float4 _UnityFBInput##idx##_TexelSize
#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fname) LOAD_TEXTURE2D_ARRAY_MSAA(_UnityFBInput##idx, v2fname.xy, SLICE_ARRAY_INDEX, sampleIdx)
#else
#define FRAMEBUFFER_INPUT_X_HALF(idx) FRAMEBUFFER_INPUT_HALF(idx)
#define FRAMEBUFFER_INPUT_X_FLOAT(idx) FRAMEBUFFER_INPUT_FLOAT(idx)
#define FRAMEBUFFER_INPUT_X_INT(idx) FRAMEBUFFER_INPUT_INT(idx)
#define FRAMEBUFFER_INPUT_X_UINT(idx) FRAMEBUFFER_INPUT_UINT(idx)
#define LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname) LOAD_FRAMEBUFFER_INPUT(idx, v2fname)
#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname)
#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) FRAMEBUFFER_INPUT_HALF_MS(idx)
#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) FRAMEBUFFER_INPUT_FLOAT_MS(idx)
#define FRAMEBUFFER_INPUT_X_INT_MS(idx) FRAMEBUFFER_INPUT_INT_MS(idx)
#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) FRAMEBUFFER_INPUT_UINT_MS(idx)
#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fname) LOAD_FRAMEBUFFER_INPUT_MS(idx, sampleIdx, v2fname)
#endif
#define LOAD_TEXTURE2D_X(textureName, unCoord2) LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, SLICE_ARRAY_INDEX)
#define LOAD_TEXTURE2D_X_MSAA(textureName, unCoord2, sampleIndex) LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, SLICE_ARRAY_INDEX, sampleIndex)
#define LOAD_TEXTURE2D_X_LOD(textureName, unCoord2, lod) LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, SLICE_ARRAY_INDEX, lod)
#define SAMPLE_TEXTURE2D_X(textureName, samplerName, coord2) SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, SLICE_ARRAY_INDEX)
#define SAMPLE_TEXTURE2D_X_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, SLICE_ARRAY_INDEX, lod)
#define GATHER_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, SLICE_ARRAY_INDEX)
#define GATHER_RED_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_RED_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX))
#define GATHER_GREEN_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_GREEN_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX))
#define GATHER_BLUE_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_BLUE_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX))
#define GATHER_ALPHA_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_ALPHA_TEXTURE2D(textureName, samplerName, float3(coord2, SLICE_ARRAY_INDEX))
#else
#define SLICE_ARRAY_INDEX 0
#define TEXTURE2D_X(textureName) TEXTURE2D(textureName)
#define TYPED_TEXTURE2D_X(type, textureName) TYPED_TEXTURE2D(type, textureName)
#define TEXTURE2D_X_PARAM(textureName, samplerName) TEXTURE2D_PARAM(textureName, samplerName)
#define TEXTURE2D_X_ARGS(textureName, samplerName) TEXTURE2D_ARGS(textureName, samplerName)
#define TEXTURE2D_X_HALF(textureName) TEXTURE2D_HALF(textureName)
#define TEXTURE2D_X_FLOAT(textureName) TEXTURE2D_FLOAT(textureName)
#define FRAMEBUFFER_INPUT_X_HALF(idx) FRAMEBUFFER_INPUT_HALF(idx)
#define FRAMEBUFFER_INPUT_X_FLOAT(idx) FRAMEBUFFER_INPUT_FLOAT(idx)
#define FRAMEBUFFER_INPUT_X_INT(idx) FRAMEBUFFER_INPUT_INT(idx)
#define FRAMEBUFFER_INPUT_X_UINT(idx) FRAMEBUFFER_INPUT_UINT(idx)
#define LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname) LOAD_FRAMEBUFFER_INPUT(idx, v2fname)
#define LOAD_FRAMEBUFFER_INPUT_X(idx, v2fname) LOAD_FRAMEBUFFER_X_INPUT(idx, v2fname)
#define FRAMEBUFFER_INPUT_X_HALF_MS(idx) FRAMEBUFFER_INPUT_HALF_MS(idx)
#define FRAMEBUFFER_INPUT_X_FLOAT_MS(idx) FRAMEBUFFER_INPUT_FLOAT_MS(idx)
#define FRAMEBUFFER_INPUT_X_INT_MS(idx) FRAMEBUFFER_INPUT_INT_MS(idx)
#define FRAMEBUFFER_INPUT_X_UINT_MS(idx) FRAMEBUFFER_INPUT_UINT_MS(idx)
#define LOAD_FRAMEBUFFER_INPUT_X_MS(idx, sampleIdx, v2fname) LOAD_FRAMEBUFFER_INPUT_MS(idx, sampleIdx, v2fname)
#define LOAD_TEXTURE2D_X(textureName, unCoord2) LOAD_TEXTURE2D(textureName, unCoord2)
#define LOAD_TEXTURE2D_X_MSAA(textureName, unCoord2, sampleIndex) LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_X_LOD(textureName, unCoord2, lod) LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod)
#define SAMPLE_TEXTURE2D_X(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_X_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod)
#define GATHER_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_TEXTURE2D(textureName, samplerName, coord2)
#define GATHER_RED_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_RED_TEXTURE2D(textureName, samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D_X(textureName, samplerName, coord2) GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2)
#endif
///
/// Texture Sampling Macro Overrides for Scaling
///
/// When mip bias is supported by the underlying platform, the following section redefines all 2d texturing operations to support a global mip bias feature.
/// This feature is used to improve rendering quality when image scaling is active. It achieves this by adding a bias value to the standard mip lod calculation
/// which allows us to select the mip level based on the final image resolution rather than the current rendering resolution.
#ifdef PLATFORM_SAMPLE_TEXTURE2D_BIAS
#ifdef SAMPLE_TEXTURE2D
#undef SAMPLE_TEXTURE2D
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) \
PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, _GlobalMipBias.x)
#endif
#ifdef SAMPLE_TEXTURE2D_BIAS
#undef SAMPLE_TEXTURE2D_BIAS
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) \
PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, (bias + _GlobalMipBias.x))
#endif
#endif
#ifdef PLATFORM_SAMPLE_TEXTURE2D_GRAD
#ifdef SAMPLE_TEXTURE2D_GRAD
#undef SAMPLE_TEXTURE2D_GRAD
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) \
PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, (dpdx * _GlobalMipBias.y), (dpdy * _GlobalMipBias.y))
#endif
#endif
#ifdef PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS
#ifdef SAMPLE_TEXTURE2D_ARRAY
#undef SAMPLE_TEXTURE2D_ARRAY
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) \
PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, _GlobalMipBias.x)
#endif
#ifdef SAMPLE_TEXTURE2D_ARRAY_BIAS
#undef SAMPLE_TEXTURE2D_ARRAY_BIAS
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) \
PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, (bias + _GlobalMipBias.x))
#endif
#endif
#ifdef PLATFORM_SAMPLE_TEXTURECUBE_BIAS
#ifdef SAMPLE_TEXTURECUBE
#undef SAMPLE_TEXTURECUBE
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) \
PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, _GlobalMipBias.x)
#endif
#ifdef SAMPLE_TEXTURECUBE_BIAS
#undef SAMPLE_TEXTURECUBE_BIAS
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) \
PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, (bias + _GlobalMipBias.x))
#endif
#endif
#ifdef PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS
#ifdef SAMPLE_TEXTURECUBE_ARRAY
#undef SAMPLE_TEXTURECUBE_ARRAY
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index)\
PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, _GlobalMipBias.x)
#endif
#ifdef SAMPLE_TEXTURECUBE_ARRAY_BIAS
#undef SAMPLE_TEXTURECUBE_ARRAY_BIAS
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)\
PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, (bias + _GlobalMipBias.x))
#endif
#endif
#define VT_GLOBAL_MIP_BIAS_MULTIPLIER (_GlobalMipBias.y)
// Structs
struct VertexPositionInputs
{
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
float4 positionNDC;// Homogeneous normalized device coordinates
};
struct VertexNormalInputs
{
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Deprecated.hlsl"
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 53686bf58189656459fca4c6ab04ebe5
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,213 @@
#ifndef UNIVERSAL_DBUFFER_INCLUDED
#define UNIVERSAL_DBUFFER_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DecalInput.hlsl"
#if (defined(_DBUFFER_MRT1) || defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)) && !defined(_SURFACE_TYPE_TRANSPARENT)
#define _DBUFFER
#endif
#define DBufferType0 half4
#define DBufferType1 half4
#define DBufferType2 half4
#if defined(_DBUFFER_MRT3)
#define OUTPUT_DBUFFER(NAME) \
out DBufferType0 MERGE_NAME(NAME, 0) : SV_Target0, \
out DBufferType1 MERGE_NAME(NAME, 1) : SV_Target1, \
out DBufferType2 MERGE_NAME(NAME, 2) : SV_Target2
#define DECLARE_DBUFFER_TEXTURE(NAME) \
TEXTURE2D_X_HALF(MERGE_NAME(NAME, 0)); \
TEXTURE2D_X_HALF(MERGE_NAME(NAME, 1)); \
TEXTURE2D_X_HALF(MERGE_NAME(NAME, 2));
#define FETCH_DBUFFER(NAME, TEX, unCoord2) \
DBufferType0 MERGE_NAME(NAME, 0) = LOAD_TEXTURE2D_X(MERGE_NAME(TEX, 0), unCoord2); \
DBufferType1 MERGE_NAME(NAME, 1) = LOAD_TEXTURE2D_X(MERGE_NAME(TEX, 1), unCoord2); \
DBufferType2 MERGE_NAME(NAME, 2) = LOAD_TEXTURE2D_X(MERGE_NAME(TEX, 2), unCoord2);
#define ENCODE_INTO_DBUFFER(DECAL_SURFACE_DATA, NAME) EncodeIntoDBuffer(DECAL_SURFACE_DATA, MERGE_NAME(NAME,0), MERGE_NAME(NAME,1), MERGE_NAME(NAME,2))
#define DECODE_FROM_DBUFFER(NAME, DECAL_SURFACE_DATA) DecodeFromDBuffer(MERGE_NAME(NAME,0), MERGE_NAME(NAME,1), MERGE_NAME(NAME,2), DECAL_SURFACE_DATA)
#elif defined(_DBUFFER_MRT2)
#define OUTPUT_DBUFFER(NAME) \
out DBufferType0 MERGE_NAME(NAME, 0) : SV_Target0, \
out DBufferType1 MERGE_NAME(NAME, 1) : SV_Target1
#define DECLARE_DBUFFER_TEXTURE(NAME) \
TEXTURE2D_X_HALF(MERGE_NAME(NAME, 0)); \
TEXTURE2D_X_HALF(MERGE_NAME(NAME, 1));
#define FETCH_DBUFFER(NAME, TEX, unCoord2) \
DBufferType0 MERGE_NAME(NAME, 0) = LOAD_TEXTURE2D_X(MERGE_NAME(TEX, 0), unCoord2); \
DBufferType1 MERGE_NAME(NAME, 1) = LOAD_TEXTURE2D_X(MERGE_NAME(TEX, 1), unCoord2);
#define ENCODE_INTO_DBUFFER(DECAL_SURFACE_DATA, NAME) EncodeIntoDBuffer(DECAL_SURFACE_DATA, MERGE_NAME(NAME,0), MERGE_NAME(NAME,1))
#define DECODE_FROM_DBUFFER(NAME, DECAL_SURFACE_DATA) DecodeFromDBuffer(MERGE_NAME(NAME,0), MERGE_NAME(NAME,1), DECAL_SURFACE_DATA)
#else
#define OUTPUT_DBUFFER(NAME) \
out DBufferType0 MERGE_NAME(NAME, 0) : SV_Target0
#define DECLARE_DBUFFER_TEXTURE(NAME) \
TEXTURE2D_X_HALF(MERGE_NAME(NAME, 0));
#define FETCH_DBUFFER(NAME, TEX, unCoord2) \
DBufferType0 MERGE_NAME(NAME, 0) = LOAD_TEXTURE2D_X(MERGE_NAME(TEX, 0), unCoord2);
#define ENCODE_INTO_DBUFFER(DECAL_SURFACE_DATA, NAME) EncodeIntoDBuffer(DECAL_SURFACE_DATA, MERGE_NAME(NAME,0))
#define DECODE_FROM_DBUFFER(NAME, DECAL_SURFACE_DATA) DecodeFromDBuffer(MERGE_NAME(NAME,0), DECAL_SURFACE_DATA)
#endif
void EncodeIntoDBuffer(DecalSurfaceData surfaceData
, out DBufferType0 outDBuffer0
#if defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)
, out DBufferType1 outDBuffer1
#endif
#if defined(_DBUFFER_MRT3)
, out DBufferType2 outDBuffer2
#endif
)
{
outDBuffer0 = surfaceData.baseColor;
#if defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)
outDBuffer1 = half4(surfaceData.normalWS.xyz * 0.5 + 0.5, surfaceData.normalWS.w);
#endif
#if defined(_DBUFFER_MRT3)
outDBuffer2 = half4(surfaceData.metallic, surfaceData.occlusion, surfaceData.smoothness, surfaceData.MAOSAlpha);
#endif
}
void DecodeFromDBuffer(
DBufferType0 inDBuffer0
#if defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)
, DBufferType1 inDBuffer1
#endif
#if defined(_DBUFFER_MRT3) || defined(DECALS_4RT)
, DBufferType2 inDBuffer2
#endif
, out DecalSurfaceData surfaceData
)
{
ZERO_INITIALIZE(DecalSurfaceData, surfaceData);
surfaceData.baseColor = inDBuffer0;
#if defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)
// Use (254.0 / 255.0) instead of 0.5 to allow to encode 0 perfectly (encode as 127)
// Range goes from -0.99607 to 1.0039
surfaceData.normalWS.xyz = inDBuffer1.xyz * 2.0 - (254.0 / 255.0);
surfaceData.normalWS.w = inDBuffer1.w;
#endif
#if defined(_DBUFFER_MRT3)
surfaceData.metallic = inDBuffer2.x;
surfaceData.occlusion = inDBuffer2.y;
surfaceData.smoothness = inDBuffer2.z;
surfaceData.MAOSAlpha = inDBuffer2.w;
#endif
}
DECLARE_DBUFFER_TEXTURE(_DBufferTexture);
void ApplyDecal(float4 positionCS,
inout half3 baseColor,
inout half3 specularColor,
inout half3 normalWS,
inout half metallic,
inout half occlusion,
inout half smoothness)
{
FETCH_DBUFFER(DBuffer, _DBufferTexture, int2(positionCS.xy));
DecalSurfaceData decalSurfaceData;
DECODE_FROM_DBUFFER(DBuffer, decalSurfaceData);
// using alpha compositing https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html, mean weight of 1 is neutral
// Note: We only test weight (i.e decalSurfaceData.xxx.w is < 1.0) if it can save something
baseColor.xyz = baseColor.xyz * decalSurfaceData.baseColor.w + decalSurfaceData.baseColor.xyz;
#if defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)
// Always test the normal as we can have decompression artifact
if (decalSurfaceData.normalWS.w < 1.0)
{
normalWS.xyz = SafeNormalize(normalWS.xyz * decalSurfaceData.normalWS.w + decalSurfaceData.normalWS.xyz);
}
#endif
#if defined(_DBUFFER_MRT3)
#ifdef _SPECULAR_SETUP
if (decalSurfaceData.MAOSAlpha.x < 1.0)
{
half3 decalSpecularColor = ComputeFresnel0((decalSurfaceData.baseColor.w < 1.0) ? decalSurfaceData.baseColor.xyz : half3(1.0, 1.0, 1.0), decalSurfaceData.metallic, DEFAULT_SPECULAR_VALUE);
specularColor = specularColor * decalSurfaceData.MAOSAlpha + decalSpecularColor * (1.0f - decalSurfaceData.MAOSAlpha);
}
#else
metallic = metallic * decalSurfaceData.MAOSAlpha + decalSurfaceData.metallic;
#endif
occlusion = occlusion * decalSurfaceData.MAOSAlpha + decalSurfaceData.occlusion;
smoothness = smoothness * decalSurfaceData.MAOSAlpha + decalSurfaceData.smoothness;
#endif
}
void ApplyDecalToBaseColor(float4 positionCS, inout half3 baseColor)
{
FETCH_DBUFFER(DBuffer, _DBufferTexture, int2(positionCS.xy));
DecalSurfaceData decalSurfaceData;
DECODE_FROM_DBUFFER(DBuffer, decalSurfaceData);
// using alpha compositing https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html, mean weight of 1 is neutral
// Note: We only test weight (i.e decalSurfaceData.xxx.w is < 1.0) if it can save something
baseColor.xyz = baseColor.xyz * decalSurfaceData.baseColor.w + decalSurfaceData.baseColor.xyz;
}
void ApplyDecalToBaseColorAndNormal(float4 positionCS, inout half3 baseColor, inout half3 normalWS)
{
half3 specular = 0;
half metallic = 0;
half occlusion = 0;
half smoothness = 0;
ApplyDecal(positionCS,
baseColor,
specular,
normalWS,
metallic,
occlusion,
smoothness);
}
void ApplyDecalToSurfaceData(float4 positionCS, inout SurfaceData surfaceData, inout InputData inputData)
{
#ifdef _SPECULAR_SETUP
half metallic = 0;
ApplyDecal(positionCS,
surfaceData.albedo,
surfaceData.specular,
inputData.normalWS,
metallic,
surfaceData.occlusion,
surfaceData.smoothness);
#else
half3 specular = 0;
ApplyDecal(positionCS,
surfaceData.albedo,
specular,
inputData.normalWS,
surfaceData.metallic,
surfaceData.occlusion,
surfaceData.smoothness);
#endif
}
#endif // UNIVERSAL_DBUFFER_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9041fd6e0797cf74a8f08340e6157c0d
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
#ifndef UNIVERSAL_DOTS_PRAGMAS_INCLUDED
#define UNIVERSAL_DOTS_PRAGMAS_INCLUDED
#ifndef HAVE_VFX_MODIFICATION
#pragma multi_compile _ DOTS_INSTANCING_ON
#if UNITY_PLATFORM_ANDROID || (UNITY_PLATFORM_WEBGL && !SHADER_API_WEBGPU) || UNITY_PLATFORM_UWP
#pragma target 3.5 DOTS_INSTANCING_ON
#else
#pragma target 4.5 DOTS_INSTANCING_ON
#endif
#endif // HAVE_VFX_MODIFICATION
#endif // UNIVERSAL_DOTS_PRAGMAS_INCLUDED
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 71338c4661f9c40249e1fdb27df62e92
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9f4aa226a5594efa99614cb0158c2f59
timeCreated: 1614676341
@@ -0,0 +1,333 @@
using System;
namespace UnityEngine.Rendering.Universal
{
#region Material Settings
/// <summary>
/// Debug material modes.
/// </summary>
[GenerateHLSL]
public enum DebugMaterialMode
{
/// <summary>No material debug.</summary>
None,
/// <summary>Display material albedo.</summary>
Albedo,
/// <summary>Display material specular.</summary>
Specular,
/// <summary>Display material alpha.</summary>
Alpha,
/// <summary>Display material smoothness.</summary>
Smoothness,
/// <summary>Display material ambient occlusion.</summary>
AmbientOcclusion,
/// <summary>Display material emission.</summary>
Emission,
/// <summary>Display material normal (world space).</summary>
NormalWorldSpace,
/// <summary>Display material normal (tangent space).</summary>
NormalTangentSpace,
/// <summary>Display evaluated lighting complexity.</summary>
LightingComplexity,
/// <summary>Display material metallic.</summary>
Metallic,
/// <summary>Display material sprite mask.</summary>
SpriteMask,
/// <summary>Display rendering layer masks.</summary>
RenderingLayerMasks,
}
/// <summary>
/// Debug mode for displaying vertex attributes interpolated from vertex to pixel shader.
/// </summary>
[GenerateHLSL]
public enum DebugVertexAttributeMode
{
/// <summary>No vertex attribute debug.</summary>
None,
/// <summary>Display texture coordinate 0.</summary>
Texcoord0,
/// <summary>Display texture coordinate 1.</summary>
Texcoord1,
/// <summary>Display texture coordinate 2.</summary>
Texcoord2,
/// <summary>Display texture coordinate 3.</summary>
Texcoord3,
/// <summary>Display texture coordinate 4.</summary>
Texcoord4,
/// <summary>Display texture coordinate 5.</summary>
Texcoord5,
/// <summary>Display texture coordinate 6.</summary>
Texcoord6,
/// <summary>Display texture coordinate 7.</summary>
Texcoord7,
/// <summary>Display vertex color.</summary>
Color,
/// <summary>Display tangent.</summary>
Tangent,
/// <summary>Display normal.</summary>
Normal,
}
/// <summary>
/// Debug mode for validating out-of-range values of different material channels.
/// </summary>
[GenerateHLSL]
public enum DebugMaterialValidationMode
{
/// <summary>No material debug validation override.</summary>
None,
/// <summary>Validate albedo values according to validation settings.</summary>
Albedo,
/// <summary>Validate metallic values according to validation settings.</summary>
Metallic
}
#endregion
#region Rendering Settings
/// <summary>
/// Debug mode for displaying intermediate render targets.
/// </summary>
[GenerateHLSL]
public enum DebugFullScreenMode
{
/// <summary>No intermediate render target displayed.</summary>
None,
/// <summary>Display depth buffer contents.</summary>
Depth,
// NOTE: we could also add (dir, mag) format.
/// <summary>Display depth buffer contents.</summary>
[InspectorName("Motion Vector (100x, normalized)")]
MotionVector,
/// <summary>Display the shadow map from additional lights.</summary>
AdditionalLightsShadowMap,
/// <summary>Display the main shadow map.</summary>
MainLightShadowMap,
/// <summary> Display the light cookie atlas for additional lights.</summary>
AdditionalLightsCookieAtlas,
/// <summary>
/// Display the reflection probe atlas used for the Forward+ rendering path.
/// </summary>
ReflectionProbeAtlas,
/// <summary>
/// Displays the active STP debug view.
/// </summary>
STP,
}
/// <summary>
/// Debug mode that overrides how the renderer behaves.
/// </summary>
[GenerateHLSL]
public enum DebugSceneOverrideMode
{
/// <summary>No debug override.</summary>
None,
/// <summary>Visualize overdraw by drawing geometry using a semitransparent material. Areas that look opaque contain more overdraw.</summary>
Overdraw,
/// <summary>Render using wireframe only.</summary>
Wireframe,
/// <summary>Render using a constant fill color and wireframe.</summary>
SolidWireframe,
/// <summary>Render shaded geometry in addition to wireframe.</summary>
ShadedWireframe,
}
/// <summary>
/// Debug mode of the overdraw
/// </summary>
public enum DebugOverdrawMode
{
/// <summary>No overdraw debug mode.</summary>
None,
/// <summary>Debug overdraw of opaque only.</summary>
Opaque,
/// <summary>Debug overdraw of transparent only.</summary>
Transparent,
/// <summary>Debug overdraw of everything only.</summary>
All
}
/// <summary>
/// Debug mode for texture mipmap streaming.
/// </summary>
// Keep in sync with DebugMipMapMode in HDRP's Runtime/Debug/MipMapDebug.cs
[GenerateHLSL]
public enum DebugMipInfoMode
{
/// <summary>No mipmap debug.</summary>
None,
/// <summary>Display savings and shortage due to streaming.</summary>
MipStreamingPerformance,
/// <summary>Display the streaming status of materials and textures.</summary>
MipStreamingStatus,
/// <summary>Highlight recently streamed data.</summary>
MipStreamingActivity,
/// <summary>Display streaming priorities as set up when importing.</summary>
MipStreamingPriority,
/// <summary>Display the amount of uploaded mip levels.</summary>
MipCount,
/// <summary>Visualize the pixel density for the highest-resolution uploaded mip level from the camera's point-of-view.</summary>
MipRatio,
}
/// <summary>
/// Aggregation mode for texture mipmap streaming debugging information.
/// </summary>
// Keep in sync with DebugMipMapStatusMode in HDRP's Runtime/Debug/MipMapDebug.cs
[GenerateHLSL]
public enum DebugMipMapStatusMode
{
/// <summary>Show debug information aggregated per material.</summary>
Material,
/// <summary>Show debug information for the selected texture slot.</summary>
Texture,
}
/// <summary>
/// Terrain layer for texture mipmap streaming debugging.
/// </summary>
[GenerateHLSL]
public enum DebugMipMapModeTerrainTexture
{
/// <summary>Control texture debug.</summary>
Control,
/// <summary>Layer 0 diffuse texture debug.</summary>
[InspectorName("Layer 0 - Diffuse")] Layer0,
/// <summary>Layer 1 diffuse texture debug.</summary>
[InspectorName("Layer 1 - Diffuse")] Layer1,
/// <summary>Layer 2 diffuse texture debug.</summary>
[InspectorName("Layer 2 - Diffuse")] Layer2,
/// <summary>Layer 3 diffuse texture debug.</summary>
[InspectorName("Layer 3 - Diffuse")] Layer3,
}
/// <summary>
/// Mode that controls if post-processing is allowed.
/// </summary>
/// <remarks>
/// When "Auto" is used, post-processing can be either on or off, depending on other active debug modes.
/// </remarks>
[GenerateHLSL]
public enum DebugPostProcessingMode
{
/// <summary>Post-processing disabled.</summary>
Disabled,
/// <summary>Post-processing is either on or off, depending on other debug modes.</summary>
Auto,
/// <summary>Post-processing enabled.</summary>
Enabled
};
/// <summary>
/// Debug modes for validating illegal output values.
/// </summary>
[GenerateHLSL]
public enum DebugValidationMode
{
/// <summary>No validation.</summary>
None,
/// <summary>Highlight all pixels containing NaN (not a number), infinite or negative values.</summary>
[InspectorName("Highlight NaN, Inf and Negative Values")]
HighlightNanInfNegative,
/// <summary>Highlight all pixels with values outside the specified range.</summary>
[InspectorName("Highlight Values Outside Range")]
HighlightOutsideOfRange
}
/// <summary>
/// The channels used by DebugValidationMode.HighlightOutsideOfRange.
/// </summary>
/// <remarks>
/// When "RGB" is used, the pixel's RGB value is first converted to a luminance value.
/// Individual channels (R, G, B, and A) are tested individually against the range.
/// </remarks>
[GenerateHLSL]
public enum PixelValidationChannels
{
/// <summary>Use luminance calculated from RGB channels as the value to validate.</summary>
RGB,
/// <summary>Validate the red channel value.</summary>
R,
/// <summary>Validate the green channel value.</summary>
G,
/// <summary>Validate the blue channel value.</summary>
B,
/// <summary>Validate the alpha channel value.</summary>
A
}
#endregion
#region Lighting settings
/// <summary>
/// Debug modes for lighting.
/// </summary>
[GenerateHLSL]
public enum DebugLightingMode
{
/// <summary>No lighting debug mode.</summary>
None,
/// <summary>Display shadow cascades using different colors.</summary>
ShadowCascades,
/// <summary>Display lighting result without applying normal maps.</summary>
LightingWithoutNormalMaps,
/// <summary>Display lighting result (including normal maps).</summary>
LightingWithNormalMaps,
/// <summary>Display only reflections.</summary>
Reflections,
/// <summary>Display only reflections with smoothness.</summary>
ReflectionsWithSmoothness,
/// <summary>Display the indirect irradiance</summary>
GlobalIllumination,
}
/// <summary>
/// HDR debug mode.
/// </summary>
[GenerateHLSL]
public enum HDRDebugMode
{
/// <summary>No HDR debugging.</summary>
None,
/// <summary>Gamut view: show the gamuts and what part of the gamut the image shows.</summary>
GamutView,
/// <summary>Gamut clip: show what part of the Scene is covered by the Rec709 gamut and which parts are in the Rec2020 gamut.</summary>
GamutClip,
/// <summary>If the luminance value exceeds the paper white value, show the exceeding value in colors between yellow and red. Shows luminance values otherwise.</summary>
ValuesAbovePaperWhite
}
/// <summary>
/// Debug mode that allows selective disabling of individual lighting components.
/// </summary>
[GenerateHLSL, Flags]
public enum DebugLightingFeatureFlags
{
/// <summary>The debug mode is not active.</summary>
None,
/// <summary>Display contribution from global illumination.</summary>
GlobalIllumination = 0x1,
/// <summary>Display contribution from the main light.</summary>
MainLight = 0x2,
/// <summary>Display contribution from additional lights.</summary>
AdditionalLights = 0x4,
/// <summary>Display contribution from vertex lighting.</summary>
VertexLighting = 0x8,
/// <summary>Display contribution from emissive objects.</summary>
Emission = 0x10,
/// <summary>Display contribution from ambient occlusion.</summary>
AmbientOcclusion = 0x20,
}
#endregion
}
@@ -0,0 +1,148 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef DEBUGVIEWENUMS_CS_HLSL
#define DEBUGVIEWENUMS_CS_HLSL
//
// UnityEngine.Rendering.Universal.DebugFullScreenMode: static fields
//
#define DEBUGFULLSCREENMODE_NONE (0)
#define DEBUGFULLSCREENMODE_DEPTH (1)
#define DEBUGFULLSCREENMODE_MOTION_VECTOR (2)
#define DEBUGFULLSCREENMODE_ADDITIONAL_LIGHTS_SHADOW_MAP (3)
#define DEBUGFULLSCREENMODE_MAIN_LIGHT_SHADOW_MAP (4)
#define DEBUGFULLSCREENMODE_ADDITIONAL_LIGHTS_COOKIE_ATLAS (5)
#define DEBUGFULLSCREENMODE_REFLECTION_PROBE_ATLAS (6)
#define DEBUGFULLSCREENMODE_STP (7)
//
// UnityEngine.Rendering.Universal.DebugLightingFeatureFlags: static fields
//
#define DEBUGLIGHTINGFEATUREFLAGS_NONE (0)
#define DEBUGLIGHTINGFEATUREFLAGS_GLOBAL_ILLUMINATION (1)
#define DEBUGLIGHTINGFEATUREFLAGS_MAIN_LIGHT (2)
#define DEBUGLIGHTINGFEATUREFLAGS_ADDITIONAL_LIGHTS (4)
#define DEBUGLIGHTINGFEATUREFLAGS_VERTEX_LIGHTING (8)
#define DEBUGLIGHTINGFEATUREFLAGS_EMISSION (16)
#define DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION (32)
//
// UnityEngine.Rendering.Universal.DebugLightingMode: static fields
//
#define DEBUGLIGHTINGMODE_NONE (0)
#define DEBUGLIGHTINGMODE_SHADOW_CASCADES (1)
#define DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS (2)
#define DEBUGLIGHTINGMODE_LIGHTING_WITH_NORMAL_MAPS (3)
#define DEBUGLIGHTINGMODE_REFLECTIONS (4)
#define DEBUGLIGHTINGMODE_REFLECTIONS_WITH_SMOOTHNESS (5)
#define DEBUGLIGHTINGMODE_GLOBAL_ILLUMINATION (6)
//
// UnityEngine.Rendering.Universal.DebugMaterialMode: static fields
//
#define DEBUGMATERIALMODE_NONE (0)
#define DEBUGMATERIALMODE_ALBEDO (1)
#define DEBUGMATERIALMODE_SPECULAR (2)
#define DEBUGMATERIALMODE_ALPHA (3)
#define DEBUGMATERIALMODE_SMOOTHNESS (4)
#define DEBUGMATERIALMODE_AMBIENT_OCCLUSION (5)
#define DEBUGMATERIALMODE_EMISSION (6)
#define DEBUGMATERIALMODE_NORMAL_WORLD_SPACE (7)
#define DEBUGMATERIALMODE_NORMAL_TANGENT_SPACE (8)
#define DEBUGMATERIALMODE_LIGHTING_COMPLEXITY (9)
#define DEBUGMATERIALMODE_METALLIC (10)
#define DEBUGMATERIALMODE_SPRITE_MASK (11)
#define DEBUGMATERIALMODE_RENDERING_LAYER_MASKS (12)
//
// UnityEngine.Rendering.Universal.DebugMaterialValidationMode: static fields
//
#define DEBUGMATERIALVALIDATIONMODE_NONE (0)
#define DEBUGMATERIALVALIDATIONMODE_ALBEDO (1)
#define DEBUGMATERIALVALIDATIONMODE_METALLIC (2)
//
// UnityEngine.Rendering.Universal.DebugMipInfoMode: static fields
//
#define DEBUGMIPINFOMODE_NONE (0)
#define DEBUGMIPINFOMODE_MIP_STREAMING_PERFORMANCE (1)
#define DEBUGMIPINFOMODE_MIP_STREAMING_STATUS (2)
#define DEBUGMIPINFOMODE_MIP_STREAMING_ACTIVITY (3)
#define DEBUGMIPINFOMODE_MIP_STREAMING_PRIORITY (4)
#define DEBUGMIPINFOMODE_MIP_COUNT (5)
#define DEBUGMIPINFOMODE_MIP_RATIO (6)
//
// UnityEngine.Rendering.Universal.DebugMipMapModeTerrainTexture: static fields
//
#define DEBUGMIPMAPMODETERRAINTEXTURE_CONTROL (0)
#define DEBUGMIPMAPMODETERRAINTEXTURE_LAYER0 (1)
#define DEBUGMIPMAPMODETERRAINTEXTURE_LAYER1 (2)
#define DEBUGMIPMAPMODETERRAINTEXTURE_LAYER2 (3)
#define DEBUGMIPMAPMODETERRAINTEXTURE_LAYER3 (4)
//
// UnityEngine.Rendering.Universal.DebugMipMapStatusMode: static fields
//
#define DEBUGMIPMAPSTATUSMODE_MATERIAL (0)
#define DEBUGMIPMAPSTATUSMODE_TEXTURE (1)
//
// UnityEngine.Rendering.Universal.DebugPostProcessingMode: static fields
//
#define DEBUGPOSTPROCESSINGMODE_DISABLED (0)
#define DEBUGPOSTPROCESSINGMODE_AUTO (1)
#define DEBUGPOSTPROCESSINGMODE_ENABLED (2)
//
// UnityEngine.Rendering.Universal.DebugSceneOverrideMode: static fields
//
#define DEBUGSCENEOVERRIDEMODE_NONE (0)
#define DEBUGSCENEOVERRIDEMODE_OVERDRAW (1)
#define DEBUGSCENEOVERRIDEMODE_WIREFRAME (2)
#define DEBUGSCENEOVERRIDEMODE_SOLID_WIREFRAME (3)
#define DEBUGSCENEOVERRIDEMODE_SHADED_WIREFRAME (4)
//
// UnityEngine.Rendering.Universal.DebugValidationMode: static fields
//
#define DEBUGVALIDATIONMODE_NONE (0)
#define DEBUGVALIDATIONMODE_HIGHLIGHT_NAN_INF_NEGATIVE (1)
#define DEBUGVALIDATIONMODE_HIGHLIGHT_OUTSIDE_OF_RANGE (2)
//
// UnityEngine.Rendering.Universal.DebugVertexAttributeMode: static fields
//
#define DEBUGVERTEXATTRIBUTEMODE_NONE (0)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD0 (1)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD1 (2)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD2 (3)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD3 (4)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD4 (5)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD5 (6)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD6 (7)
#define DEBUGVERTEXATTRIBUTEMODE_TEXCOORD7 (8)
#define DEBUGVERTEXATTRIBUTEMODE_COLOR (9)
#define DEBUGVERTEXATTRIBUTEMODE_TANGENT (10)
#define DEBUGVERTEXATTRIBUTEMODE_NORMAL (11)
//
// UnityEngine.Rendering.Universal.HDRDebugMode: static fields
//
#define HDRDEBUGMODE_NONE (0)
#define HDRDEBUGMODE_GAMUT_VIEW (1)
#define HDRDEBUGMODE_GAMUT_CLIP (2)
#define HDRDEBUGMODE_VALUES_ABOVE_PAPER_WHITE (3)
//
// UnityEngine.Rendering.Universal.PixelValidationChannels: static fields
//
#define PIXELVALIDATIONCHANNELS_RGB (0)
#define PIXELVALIDATIONCHANNELS_R (1)
#define PIXELVALIDATIONCHANNELS_G (2)
#define PIXELVALIDATIONCHANNELS_B (3)
#define PIXELVALIDATIONCHANNELS_A (4)
#endif
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 448811f26ae38ae4cbb2edb0d2b9186c
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef707b0a4fc04a4fb4501a4dec1c376d
timeCreated: 1608022896
@@ -0,0 +1,164 @@
#ifndef UNIVERSAL_DEBUGGING2D_INCLUDED
#define UNIVERSAL_DEBUGGING2D_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/InputData2D.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/SurfaceData2D.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/DebuggingCommon.hlsl"
#if defined(DEBUG_DISPLAY)
#define SETUP_DEBUG_TEXTURE_DATA_2D_NO_TS(inputData, positionWS, positionCS, texture) SetupDebugDataTexture(inputData, positionWS, positionCS, float4(0.1, 0.1, 1.0, 1.0), texture##_MipInfo, texture##_StreamInfo, GetMipCount(TEXTURE2D_ARGS(texture, sampler##texture)))
#define SETUP_DEBUG_DATA_2D(inputData, positionWS, positionCS) SetupDebugData(inputData, positionWS, positionCS)
void SetupDebugData(inout InputData2D inputData, float3 positionWS, float4 positionCS)
{
inputData.positionWS = positionWS;
inputData.positionCS = positionCS;
}
void SetupDebugDataTexture(inout InputData2D inputData, float3 positionWS, float4 positionCS, float4 texelSize, float4 mipInfo, float4 streamInfo, uint mipCount)
{
SetupDebugData(inputData, positionWS, positionCS);
inputData.texelSize = texelSize;
inputData.mipInfo = mipInfo;
inputData.streamInfo = streamInfo;
inputData.mipCount = mipCount;
}
bool CalculateDebugColorMaterialSettings(in SurfaceData2D surfaceData, in InputData2D inputData, inout half4 debugColor)
{
switch(_DebugMaterialMode)
{
case DEBUGMATERIALMODE_NONE:
{
return false;
}
case DEBUGMATERIALMODE_ALBEDO:
{
debugColor = half4(surfaceData.albedo, surfaceData.alpha);
return true;
}
case DEBUGMATERIALMODE_ALPHA:
{
debugColor = half4(surfaceData.alpha.rrr, 1);
return true;
}
case DEBUGMATERIALMODE_SPRITE_MASK:
{
debugColor = surfaceData.mask;
return true;
}
case DEBUGMATERIALMODE_NORMAL_WORLD_SPACE:
{
debugColor = half4(surfaceData.normalWS * 0.5 + 0.5, surfaceData.alpha);
return true;
}
case DEBUGMATERIALMODE_NORMAL_TANGENT_SPACE:
{
debugColor = half4(surfaceData.normalTS * 0.5 + 0.5, surfaceData.alpha);
return true;
}
default:
{
return TryGetDebugColorInvalidMode(debugColor);
}
}
}
bool CalculateColorForDebugMipmapStreaming(in SurfaceData2D surfaceData, in InputData2D inputData, inout half4 debugColor)
{
return CalculateColorForDebugMipmapStreaming(inputData.mipCount, uint2(inputData.positionCS.xy), inputData.texelSize, inputData.uv, inputData.mipInfo, inputData.streamInfo, surfaceData.albedo, debugColor);
}
bool CalculateDebugColorForRenderingSettings(in SurfaceData2D surfaceData, in InputData2D inputData, inout half4 debugColor)
{
if (CalculateColorForDebugSceneOverride(debugColor))
{
return true;
}
else if (CalculateColorForDebugMipmapStreaming(surfaceData, inputData, debugColor))
{
return true;
}
return false;
}
bool CalculateDebugColorLightingSettings(inout SurfaceData2D surfaceData, inout InputData2D inputData, inout half4 debugColor)
{
switch(_DebugLightingMode)
{
case DEBUGLIGHTINGMODE_NONE:
{
return false;
}
case DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS:
case DEBUGLIGHTINGMODE_LIGHTING_WITH_NORMAL_MAPS:
{
surfaceData.albedo = 1;
return false;
}
default:
{
return TryGetDebugColorInvalidMode(debugColor);
}
} // End of switch.
}
bool CalculateDebugColorValidationSettings(in SurfaceData2D surfaceData, in InputData2D inputData, inout half4 debugColor)
{
switch(_DebugMaterialValidationMode)
{
case DEBUGMATERIALVALIDATIONMODE_NONE:
return false;
case DEBUGMATERIALVALIDATIONMODE_ALBEDO:
return CalculateValidationAlbedo(surfaceData.albedo, debugColor);
default:
return TryGetDebugColorInvalidMode(debugColor);
}
}
bool CanDebugOverrideOutputColor(inout SurfaceData2D surfaceData, inout InputData2D inputData, inout half4 debugColor)
{
if (CalculateDebugColorMaterialSettings(surfaceData, inputData, debugColor))
{
return _DebugMaterialMode != DEBUGMATERIALMODE_SPRITE_MASK;
}
else if (CalculateDebugColorForRenderingSettings(surfaceData, inputData, debugColor))
{
return true;
}
else if (CalculateDebugColorLightingSettings(surfaceData, inputData, debugColor))
{
return true;
}
else if (CalculateDebugColorValidationSettings(surfaceData, inputData, debugColor))
{
return true;
}
else
{
return false;
}
}
#else
#define SETUP_DEBUG_TEXTURE_DATA_2D_NO_TS(inputData, positionWS, positionCS, texture)
#define SETUP_DEBUG_TEXTURE_DATA_2D(inputData, positionWS, positionCS, texture)
#define SETUP_DEBUG_DATA_2D(inputData, positionWS, positionCS)
#endif
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4ee4501622ea4008903e313980a6b1b2
timeCreated: 1613562288
@@ -0,0 +1,396 @@
#ifndef UNIVERSAL_DEBUGGING3D_INCLUDED
#define UNIVERSAL_DEBUGGING3D_INCLUDED
// Ensure that we always include "DebuggingCommon.hlsl" even if we don't use it - saves extraneous includes elsewhere...
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/DebuggingCommon.hlsl"
#if defined(DEBUG_DISPLAY)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GlobalIllumination.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
#define TERRAIN_STREAM_INFO float4(0.0f, 0.0f, float(6 | (4 << 4)), 0.0f) // 0-15 are reserved for per-texture codes (use "6" to indicate terrain); per-material code "4" signifies "warnings/issues"
#define SETUP_DEBUG_TEXTURE_DATA(inputData, uv) SetupDebugDataTexture(inputData, TRANSFORM_TEX(uv.xy, unity_MipmapStreaming_DebugTex), unity_MipmapStreaming_DebugTex_TexelSize, unity_MipmapStreaming_DebugTex_MipInfo, unity_MipmapStreaming_DebugTex_StreamInfo, unity_MipmapStreaming_DebugTex)
#define SETUP_DEBUG_TEXTURE_DATA_NO_UV(inputData) SetupDebugDataTexture(inputData, float2(0.0f, 0.0f), unity_MipmapStreaming_DebugTex_TexelSize, unity_MipmapStreaming_DebugTex_MipInfo, unity_MipmapStreaming_DebugTex_StreamInfo, unity_MipmapStreaming_DebugTex)
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TEX(inputData, uv, texture) SetupDebugDataTexture(inputData, uv, texture##_TexelSize, texture##_MipInfo, texture##_StreamInfo, texture)
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TERRAIN(inputData) SetupDebugDataTerrain(inputData)
void SetupDebugDataTexture(inout InputData inputData, float2 uv, float4 texelSize, float4 mipInfo, float4 streamInfo, TEXTURE2D(tex))
{
inputData.uv = uv;
inputData.texelSize = texelSize;
inputData.mipInfo = mipInfo;
inputData.streamInfo = streamInfo;
inputData.mipCount = GetMipCount(TEXTURE2D_ARGS(tex, sampler_PointClamp));
inputData.originalColor = 0.0f;
if (_DebugMipInfoMode != DEBUGMIPINFOMODE_NONE)
{
inputData.originalColor = SAMPLE_TEXTURE2D(tex, sampler_LinearRepeat, uv).xyz;
}
}
void SetupDebugDataBrdf(inout InputData inputData, half3 brdfDiffuse, half3 brdfSpecular)
{
inputData.brdfDiffuse = brdfDiffuse;
inputData.brdfSpecular = brdfSpecular;
}
void SetupDebugDataTerrain(inout InputData inputData)
{
// TERRAIN_STREAM_INFO: no streamInfo will have been set (no MeshRenderer); set status to "6" to reflect in the debug status that this is a terrain
// also, set the per-material status to "4" to indicate warnings
inputData.streamInfo = TERRAIN_STREAM_INFO;
}
bool UpdateSurfaceAndInputDataForDebug(inout SurfaceData surfaceData, inout InputData inputData)
{
bool changed = false;
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS || _DebugLightingMode == DEBUGLIGHTINGMODE_LIGHTING_WITH_NORMAL_MAPS)
{
surfaceData.albedo = 1;
surfaceData.emission = 0;
surfaceData.specular = 0;
surfaceData.occlusion = 1;
surfaceData.clearCoatMask = 0;
surfaceData.clearCoatSmoothness = 1;
surfaceData.metallic = 0;
surfaceData.smoothness = 0;
changed = true;
}
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS || _DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS_WITH_SMOOTHNESS)
{
surfaceData.albedo = 0;
surfaceData.emission = 0;
surfaceData.occlusion = 1;
surfaceData.clearCoatMask = 0;
surfaceData.clearCoatSmoothness = 1;
surfaceData.specular = 1;
surfaceData.metallic = 0;
if (_DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS)
{
surfaceData.smoothness = 1;
}
changed = true;
}
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS || _DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS)
{
const half3 normalTS = half3(0, 0, 1);
#if defined(_NORMALMAP)
inputData.normalWS = TransformTangentToWorld(normalTS, inputData.tangentToWorld);
#else
inputData.normalWS = inputData.normalWS;
#endif
surfaceData.normalTS = normalTS;
changed = true;
}
return changed;
}
bool CalculateValidationMetallic(half3 albedo, half metallic, inout half4 debugColor)
{
if (metallic < _DebugValidateMetallicMinValue)
{
debugColor = _DebugValidateBelowMinThresholdColor;
}
else if (metallic > _DebugValidateMetallicMaxValue)
{
debugColor = _DebugValidateAboveMaxThresholdColor;
}
else
{
half luminance = Luminance(albedo);
debugColor = half4(luminance, luminance, luminance, 1);
}
return true;
}
bool CalculateValidationColorForDebug(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
{
switch(_DebugMaterialValidationMode)
{
case DEBUGMATERIALVALIDATIONMODE_NONE:
return false;
case DEBUGMATERIALVALIDATIONMODE_ALBEDO:
return CalculateValidationAlbedo(surfaceData.albedo, debugColor);
case DEBUGMATERIALVALIDATIONMODE_METALLIC:
return CalculateValidationMetallic(surfaceData.albedo, surfaceData.metallic, debugColor);
default:
return TryGetDebugColorInvalidMode(debugColor);
}
}
float3 GetRenderingLayerMasksDebugColor(float4 positionCS, float3 normalWS)
{
uint stripeSize = 8;
int renderingLayers = GetMeshRenderingLayer() & _DebugRenderingLayerMask;
uint layerId = 0, layerCount = countbits(renderingLayers);
float4 debugColor = float4(1, 1, 1, 1);
for (uint i = 0; (i < 32) && (layerId < layerCount); i++)
{
if (renderingLayers & (1U << i))
{
uint t = (positionCS.y / stripeSize) % layerCount;
if (t == layerId)
debugColor.rgb = _DebugRenderingLayerMaskColors[i].rgb;
layerId++;
}
}
float shading = saturate(dot(normalWS, TransformViewToWorldDir(float3(0.0f, 0.0f, 1.0f), true)));
shading = Remap(0.0f, 1.0f, 0.6, 1.0f, shading);
return shading * debugColor.xyz;
}
bool CalculateColorForDebugMaterial(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
{
// Debug materials...
switch(_DebugMaterialMode)
{
case DEBUGMATERIALMODE_NONE:
return false;
case DEBUGMATERIALMODE_ALBEDO:
debugColor = half4(surfaceData.albedo, 1);
return true;
case DEBUGMATERIALMODE_SPECULAR:
debugColor = half4(surfaceData.specular, 1);
return true;
case DEBUGMATERIALMODE_ALPHA:
debugColor = half4(surfaceData.alpha.rrr, 1);
return true;
case DEBUGMATERIALMODE_SMOOTHNESS:
debugColor = half4(surfaceData.smoothness.rrr, 1);
return true;
case DEBUGMATERIALMODE_AMBIENT_OCCLUSION:
debugColor = half4(surfaceData.occlusion.rrr, 1);
return true;
case DEBUGMATERIALMODE_EMISSION:
debugColor = half4(surfaceData.emission, 1);
return true;
case DEBUGMATERIALMODE_NORMAL_WORLD_SPACE:
debugColor = half4(inputData.normalWS.xyz * 0.5 + 0.5, 1);
return true;
case DEBUGMATERIALMODE_NORMAL_TANGENT_SPACE:
debugColor = half4(surfaceData.normalTS.xyz * 0.5 + 0.5, 1);
return true;
case DEBUGMATERIALMODE_METALLIC:
debugColor = half4(surfaceData.metallic.rrr, 1);
return true;
case DEBUGMATERIALMODE_RENDERING_LAYER_MASKS:
debugColor.xyz = GetRenderingLayerMasksDebugColor(inputData.positionCS, inputData.normalWS).xyz;
return true;
default:
return TryGetDebugColorInvalidMode(debugColor);
}
}
bool CalculateColorForDebugMipmapStreaming(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
{
return CalculateColorForDebugMipmapStreaming(inputData.mipCount, inputData.positionCS.xy, inputData.texelSize, inputData.uv, inputData.mipInfo, inputData.streamInfo, inputData.originalColor, debugColor);
}
bool CalculateColorForDebug(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
{
if (CalculateColorForDebugSceneOverride(debugColor))
{
return true;
}
else if (CalculateColorForDebugMipmapStreaming(inputData, surfaceData, debugColor))
{
return true;
}
else if (CalculateColorForDebugMaterial(inputData, surfaceData, debugColor))
{
return true;
}
else if (CalculateValidationColorForDebug(inputData, surfaceData, debugColor))
{
return true;
}
else
{
return false;
}
}
half3 CalculateDebugShadowCascadeColor(in InputData inputData)
{
float3 positionWS = inputData.positionWS;
half cascadeIndex = ComputeCascadeIndex(positionWS);
switch (uint(cascadeIndex))
{
case 0: return kDebugColorShadowCascade0.rgb;
case 1: return kDebugColorShadowCascade1.rgb;
case 2: return kDebugColorShadowCascade2.rgb;
case 3: return kDebugColorShadowCascade3.rgb;
default: return kDebugColorBlack.rgb;
}
}
half4 CalculateDebugLightingComplexityColor(in InputData inputData, in SurfaceData surfaceData)
{
#if USE_CLUSTER_LIGHT_LOOP
int numLights = URP_FP_DIRECTIONAL_LIGHTS_COUNT;
uint entityIndex;
ClusterIterator it = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 0);
[loop] while (ClusterNext(it, entityIndex))
{
numLights++;
}
it = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 1);
[loop] while (ClusterNext(it, entityIndex))
{
numLights++;
}
#else
// Assume a main light and add 1 to the additional lights.
int numLights = GetAdditionalLightsCount() + 1;
#endif
const uint2 tileSize = uint2(32,32);
const uint maxLights = 9;
const float opacity = 0.8f;
uint2 pixelCoord = uint2(inputData.normalizedScreenSpaceUV * _ScreenParams.xy);
half3 base = surfaceData.albedo;
half4 overlay = half4(OverlayHeatMap(pixelCoord, tileSize, numLights, maxLights, opacity));
uint2 tileCoord = (float2)pixelCoord / tileSize;
uint2 offsetInTile = pixelCoord - tileCoord * tileSize;
bool border = any(offsetInTile == 0 || offsetInTile == tileSize.x - 1);
if (border)
overlay = half4(1, 1, 1, 0.4f);
return half4(lerp(base.rgb, overlay.rgb, overlay.a), 1);
}
bool CanDebugOverrideOutputColor(inout InputData inputData, inout SurfaceData surfaceData, inout BRDFData brdfData, inout half4 debugColor)
{
if (_DebugMaterialMode == DEBUGMATERIALMODE_LIGHTING_COMPLEXITY)
{
debugColor = CalculateDebugLightingComplexityColor(inputData, surfaceData);
return true;
}
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_GLOBAL_ILLUMINATION)
{
debugColor = half4(inputData.bakedGI, surfaceData.alpha);
return true;
}
else
{
debugColor = half4(0, 0, 0, 1);
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SHADOW_CASCADES)
{
surfaceData.albedo = CalculateDebugShadowCascadeColor(inputData);
}
else
{
if (UpdateSurfaceAndInputDataForDebug(surfaceData, inputData))
{
// If we've modified any data we'll need to re-sample the GI to ensure that everything works correctly...
#if defined(_SCREEN_SPACE_IRRADIANCE)
// In screen space irradiance mode the final pixel values have already been resolved so we cannot reevaluate here.
#elif defined(DYNAMICLIGHTMAP_ON)
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.dynamicLightmapUV.xy, inputData.vertexSH, inputData.normalWS);
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
inputData.bakedGI = SAMPLE_GI(inputData.vertexSH,
GetAbsolutePositionWS(inputData.positionWS),
inputData.normalWS,
inputData.viewDirectionWS,
inputData.positionCS.xy,
inputData.probeOcclusion,
inputData.shadowMask);
#else
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.vertexSH, inputData.normalWS);
#endif
}
}
// Update the BRDF data following any changes to the input/surface above...
InitializeBRDFData(surfaceData, brdfData);
return CalculateColorForDebug(inputData, surfaceData, debugColor);
}
}
bool CanDebugOverrideOutputColor(inout InputData inputData, inout SurfaceData surfaceData, inout half4 debugColor)
{
if (_DebugMaterialMode == DEBUGMATERIALMODE_LIGHTING_COMPLEXITY)
{
debugColor = CalculateDebugLightingComplexityColor(inputData, surfaceData);
return true;
}
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_GLOBAL_ILLUMINATION)
{
debugColor = half4(inputData.bakedGI, surfaceData.alpha);
return true;
}
else
{
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SHADOW_CASCADES)
{
surfaceData.albedo = CalculateDebugShadowCascadeColor(inputData);
}
else
{
if (UpdateSurfaceAndInputDataForDebug(surfaceData, inputData))
{
// If we've modified any data we'll need to re-sample the GI to ensure that everything works correctly...
#if defined(_SCREEN_SPACE_IRRADIANCE)
// In screen space irradiance mode the final pixel values have already been resolved so we cannot reevaluate here.
#elif defined(DYNAMICLIGHTMAP_ON)
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.dynamicLightmapUV.xy, inputData.vertexSH, inputData.normalWS);
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
inputData.bakedGI = SAMPLE_GI(inputData.vertexSH,
GetAbsolutePositionWS(inputData.positionWS),
inputData.normalWS,
inputData.viewDirectionWS,
inputData.positionCS.xy,
inputData.probeOcclusion,
inputData.shadowMask);
#else
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.vertexSH, inputData.normalWS);
#endif
}
}
return CalculateColorForDebug(inputData, surfaceData, debugColor);
}
}
#else
// When "DEBUG_DISPLAY" isn't defined this macro does nothing - there's no debug-data to set-up...
#define SETUP_DEBUG_TEXTURE_DATA(inputData, uv)
#define SETUP_DEBUG_TEXTURE_DATA_NO_UV(inputData)
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TEX(inputData, uv, texture)
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TERRAIN(inputData)
#endif
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d8ae717b647341719f2a89f20faaf51b
timeCreated: 1613560270
@@ -0,0 +1,300 @@
#ifndef UNIVERSAL_DEBUGGING_COMMON_INCLUDED
#define UNIVERSAL_DEBUGGING_COMMON_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/DebugViewEnums.cs.hlsl"
#if defined(DEBUG_DISPLAY)
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/DebugMipmapStreaming.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Debug.hlsl"
// Material settings...
int _DebugMaterialMode;
int _DebugVertexAttributeMode;
int _DebugMaterialValidationMode;
// Rendering settings...
int _DebugFullScreenMode;
int _DebugSceneOverrideMode;
int _DebugMipInfoMode;
int _DebugMipMapStatusMode;
int _DebugMipMapShowStatusCode;
half _DebugMipMapOpacity;
half _DebugMipMapRecentlyUpdatedCooldown;
int _DebugMipMapTerrainTextureMode;
int _DebugValidationMode;
// Lighting settings...
int _DebugLightingMode;
int _DebugLightingFeatureFlags;
half _DebugValidateAlbedoMinLuminance = 0.01;
half _DebugValidateAlbedoMaxLuminance = 0.90;
half _DebugValidateAlbedoSaturationTolerance = 0.214;
half _DebugValidateAlbedoHueTolerance = 0.104;
half3 _DebugValidateAlbedoCompareColor = half3(0.5, 0.5, 0.5);
uint _DebugRenderingLayerMask = 0;
CBUFFER_START(_DebugDisplayConstant)
float4 _DebugRenderingLayerMaskColors [32];
CBUFFER_END
half _DebugValidateMetallicMinValue = 0;
half _DebugValidateMetallicMaxValue = 0.9;
float4 _DebugColor;
float4 _DebugColorInvalidMode;
float4 _DebugValidateBelowMinThresholdColor;
float4 _DebugValidateAboveMaxThresholdColor;
// Not particular to any settings; used by MipMap debugging because we don't have reliable access to _Time.y
float _DebugCurrentRealTime;
// We commonly need to undo a previous TRANSFORM_TEX to get UV0s back, followed by a TRANSFORM_TEX with the UV0s / _ST of the StreamingDebugTex... hence, this macro.
#define UNDO_TRANSFORM_TEX(uv, undoTex) ((uv - undoTex##_ST.zw) / undoTex##_ST.xy)
half3 GetDebugColor(uint index)
{
uint clampedIndex = clamp(index, 0, DEBUG_COLORS_COUNT-1);
return kDebugColorGradient[clampedIndex].rgb;
}
bool TryGetDebugColorInvalidMode(out half4 debugColor)
{
// Depending upon how we want to deal with invalid modes, this code may need to change,
// for now we'll simply make each pixel use "_DebugColorInvalidMode"...
debugColor = _DebugColorInvalidMode;
return true;
}
uint GetMipMapLevel(float2 nonNormalizedUVCoordinate)
{
// The OpenGL Graphics System: A Specification 4.2
// - chapter 3.9.11, equation 3.21
float2 dx_vtc = ddx(nonNormalizedUVCoordinate);
float2 dy_vtc = ddy(nonNormalizedUVCoordinate);
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
return (uint)(0.5 * log2(delta_max_sqr));
}
bool CalculateValidationAlbedo(half3 albedo, out half4 color)
{
half luminance = Luminance(albedo);
if (luminance < _DebugValidateAlbedoMinLuminance)
{
color = _DebugValidateBelowMinThresholdColor;
}
else if (luminance > _DebugValidateAlbedoMaxLuminance)
{
color = _DebugValidateAboveMaxThresholdColor;
}
else
{
half3 hsv = RgbToHsv(albedo);
half hue = hsv.r;
half sat = hsv.g;
half3 compHSV = RgbToHsv(_DebugValidateAlbedoCompareColor.rgb);
half compHue = compHSV.r;
half compSat = compHSV.g;
if ((compSat - _DebugValidateAlbedoSaturationTolerance > sat) || ((compHue - _DebugValidateAlbedoHueTolerance > hue) && (compHue - _DebugValidateAlbedoHueTolerance + 1.0 > hue)))
{
color = _DebugValidateBelowMinThresholdColor;
}
else if ((sat > compSat + _DebugValidateAlbedoSaturationTolerance) || ((hue > compHue + _DebugValidateAlbedoHueTolerance) && (hue > compHue + _DebugValidateAlbedoHueTolerance - 1.0)))
{
color = _DebugValidateAboveMaxThresholdColor;
}
else
{
color = half4(luminance, luminance, luminance, 1.0);
}
}
return true;
}
bool CalculateColorForDebugSceneOverride(out half4 color)
{
if (_DebugSceneOverrideMode == DEBUGSCENEOVERRIDEMODE_NONE)
{
color = 0;
return false;
}
else
{
color = _DebugColor;
return true;
}
}
half4 BlitScreenSpaceDigit(half4 originalColor, uint2 screenSpaceCoords, int digit, uint spacing, bool invertColors)
{
half4 outColor = originalColor;
const uint2 pixCoord = screenSpaceCoords / 2;
const uint2 tileSize = uint2(spacing, spacing);
const int2 coord = (pixCoord & (tileSize - 1)) - int2(tileSize.x/4+1, tileSize.y/3-3);
UNITY_LOOP for (int i = 0; i <= 1; ++i)
{
// 0 == shadow, 1 == text
if (SampleDebugFontNumber2Digits(coord + i, digit))
{
outColor = (i == 0)
? (invertColors ? half4(1, 1, 1, 1) : half4(0, 0, 0, 1))
: (invertColors ? half4(0, 0, 0, 1) : half4(1, 1, 1, 1));
}
}
return outColor;
}
void GetHatchedColor(uint2 screenSpaceCoords, half4 hatchingColor, inout half4 debugColor)
{
const uint spacing = 16; // increase spacing compared to the legend (easier on the eyes)
const uint thickness = 3;
if((screenSpaceCoords.x + screenSpaceCoords.y) % spacing < thickness)
debugColor = hatchingColor;
}
void GetHatchedColor(uint2 screenSpaceCoords, inout half4 debugColor)
{
GetHatchedColor(screenSpaceCoords, half4(0.1, 0.1, 0.1, 1), debugColor);
}
// Keep in sync with GetTextureDataDebug in HDRP's Runtime/Debug/DebugDisplay.hlsl
bool CalculateColorForDebugMipmapStreaming(in uint mipCount, uint2 screenSpaceCoords, in float4 texelSize, in float2 uv, in float4 mipInfo, in float4 streamInfo, in half3 originalColor, inout half4 debugColor)
{
bool hasDebugColor = false;
bool needsHatching;
switch (_DebugMipInfoMode)
{
case DEBUGMIPINFOMODE_NONE:
hasDebugColor = false;
break;
case DEBUGMIPINFOMODE_MIP_COUNT:
debugColor = half4(GetDebugMipCountColor(mipCount, needsHatching), 1);
if (needsHatching)
{
half4 hatchingColor = half4(GetDebugMipCountHatchingColor(mipCount), 1);
GetHatchedColor(screenSpaceCoords, hatchingColor, debugColor);
}
if (mipCount > 0 && mipCount <= 14)
debugColor = BlitScreenSpaceDigit(debugColor, screenSpaceCoords, mipCount, 32, true);
hasDebugColor = true;
break;
case DEBUGMIPINFOMODE_MIP_RATIO:
debugColor = half4(GetDebugMipColorIncludingMipReduction(originalColor, mipCount, texelSize, uv, mipInfo), 1);
hasDebugColor = true;
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_PERFORMANCE:
debugColor = half4(GetDebugStreamingMipColor(mipCount, mipInfo, streamInfo, needsHatching), 1);
if (needsHatching)
GetHatchedColor(screenSpaceCoords, debugColor);
hasDebugColor = true;
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_STATUS:
if(_DebugMipMapStatusMode == DEBUGMIPMAPSTATUSMODE_TEXTURE)
debugColor = half4(GetDebugStreamingStatusColor(streamInfo, needsHatching), 1);
else
debugColor = half4(GetDebugPerMaterialStreamingStatusColor(streamInfo, needsHatching), 1);
if (needsHatching)
GetHatchedColor(screenSpaceCoords, debugColor);
if (_DebugMipMapShowStatusCode && _DebugMipMapStatusMode == DEBUGMIPMAPSTATUSMODE_TEXTURE && !IsStreaming(streamInfo))
{
if (GetStatusCode(streamInfo, false) != kMipmapDebugStatusCodeNotSet && GetStatusCode(streamInfo, false) != kMipmapDebugStatusCodeNoTexture) // we're ignoring these because there's just one status anyway (so the color itself is enough)
debugColor = BlitScreenSpaceDigit(debugColor, screenSpaceCoords, GetStatusCode(streamInfo, false), 16, false);
}
hasDebugColor = true;
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_PRIORITY:
debugColor = half4(GetDebugStreamingPriorityColor(streamInfo), 1);
hasDebugColor = true;
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_ACTIVITY:
debugColor = half4(GetDebugStreamingRecentlyUpdatedColor(_DebugCurrentRealTime, _DebugMipMapRecentlyUpdatedCooldown, _DebugMipMapStatusMode == DEBUGMIPMAPSTATUSMODE_MATERIAL, streamInfo), 1);
hasDebugColor = true;
break;
default:
hasDebugColor = TryGetDebugColorInvalidMode(debugColor);
break;
}
// Blend the original color with the debug color
if(hasDebugColor)
debugColor = lerp(half4(originalColor, 1), debugColor, _DebugMipMapOpacity);
return hasDebugColor;
}
#else
// When "DEBUG_DISPLAY" isn't defined this macro just returns the original UVs.
#define UNDO_TRANSFORM_TEX(uv, undoTex) uv
#endif
bool IsAlphaDiscardEnabled()
{
#if defined(DEBUG_DISPLAY)
return (_DebugSceneOverrideMode == DEBUGSCENEOVERRIDEMODE_NONE);
#else
return true;
#endif
}
bool IsFogEnabled()
{
#if defined(DEBUG_DISPLAY)
return (_DebugMaterialMode == DEBUGMATERIALMODE_NONE) &&
(_DebugVertexAttributeMode == DEBUGVERTEXATTRIBUTEMODE_NONE) &&
(_DebugMaterialValidationMode == DEBUGMATERIALVALIDATIONMODE_NONE) &&
(_DebugSceneOverrideMode == DEBUGSCENEOVERRIDEMODE_NONE) &&
(_DebugMipInfoMode == DEBUGMIPINFOMODE_NONE) &&
(_DebugLightingMode == DEBUGLIGHTINGMODE_NONE) &&
(_DebugLightingFeatureFlags == 0) &&
(_DebugValidationMode == DEBUGVALIDATIONMODE_NONE);
#else
return true;
#endif
}
bool IsLightingFeatureEnabled(uint bitMask)
{
#if defined(DEBUG_DISPLAY)
return (_DebugLightingFeatureFlags == 0) || ((_DebugLightingFeatureFlags & bitMask) != 0);
#else
return true;
#endif
}
bool IsOnlyAOLightingFeatureEnabled()
{
#if defined(DEBUG_DISPLAY)
return _DebugLightingFeatureFlags == DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION;
#else
return false;
#endif
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a419d344c87843af8e1ce2e8c571fcb6
timeCreated: 1613560313
@@ -0,0 +1,214 @@
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/DebuggingCommon.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Debug.hlsl"
#if defined(DEBUG_DISPLAY)
int _DebugMaxPixelCost;
int _ValidationChannels;
float _RangeMinimum;
float _RangeMaximum;
TEXTURE2D_X(_DebugTexture);
TEXTURE2D(_DebugTextureNoStereo);
// 2023.3 Deprecated. This is for backwards compatibility. Remove in the future.
#define sampler_DebugTexture sampler_PointClamp
half4 _DebugTextureDisplayRect;
int _DebugRenderTargetSupportsStereo;
float4 _DebugRenderTargetRangeRemap;
// CPU parametrized, non-clamping, range remap. (RangeRemap in common.hlsl saturates!)
half4 RemapSourceRange(half4 source)
{
float4 r = _DebugRenderTargetRangeRemap;
float4 s = source;
// Remap(float origFrom, float origTo, float targetFrom, float targetTo, float value)
s.r = Remap(r.x, r.y, r.z, r.w, s.r);
s.g = Remap(r.x, r.y, r.z, r.w, s.g);
s.b = Remap(r.x, r.y, r.z, r.w, s.b);
s.a = Remap(r.x, r.y, r.z, r.w, s.a);
return half4(s);
}
bool CalculateDebugColorRenderingSettings(half4 color, float2 uv, inout half4 debugColor)
{
if (_DebugSceneOverrideMode == DEBUGSCENEOVERRIDEMODE_OVERDRAW)
{
// color.r is (Number of overdraw / Max displayed overdraw count)
debugColor.rgb = GetOverdrawColor(color.r * _DebugMaxPixelCost, _DebugMaxPixelCost).rgb;
DrawOverdrawLegend(uv, _DebugMaxPixelCost, _ScreenSize, debugColor.rgb);
return true;
}
if (_DebugMipInfoMode != DEBUGMIPINFOMODE_NONE)
{
debugColor = color; // just passing through
// draw legend
switch(_DebugMipInfoMode)
{
case DEBUGMIPINFOMODE_MIP_COUNT:
DrawMipCountLegend(uv, _ScreenSize, debugColor.rgb);
break;
case DEBUGMIPINFOMODE_MIP_RATIO:
DrawMipRatioLegend(uv, _ScreenSize, debugColor.rgb);
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_STATUS:
if (_DebugMipMapStatusMode == DEBUGMIPMAPSTATUSMODE_TEXTURE)
DrawMipStreamingStatusLegend(uv, _ScreenSize, _DebugMipMapShowStatusCode, debugColor.rgb);
else
DrawMipStreamingStatusPerMaterialLegend(uv, _ScreenSize, debugColor.rgb);
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_PERFORMANCE:
DrawTextureStreamingPerformanceLegend(uv, _ScreenSize, debugColor.rgb);
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_PRIORITY:
DrawMipPriorityLegend(uv, _ScreenSize, debugColor.rgb);
break;
case DEBUGMIPINFOMODE_MIP_STREAMING_ACTIVITY:
DrawMipRecentlyUpdatedLegend(uv, _ScreenSize, _DebugMipMapStatusMode == DEBUGMIPMAPSTATUSMODE_MATERIAL, debugColor.rgb);
break;
}
return true;
}
switch(_DebugFullScreenMode)
{
case DEBUGFULLSCREENMODE_DEPTH:
case DEBUGFULLSCREENMODE_MOTION_VECTOR:
case DEBUGFULLSCREENMODE_MAIN_LIGHT_SHADOW_MAP:
case DEBUGFULLSCREENMODE_ADDITIONAL_LIGHTS_SHADOW_MAP:
case DEBUGFULLSCREENMODE_ADDITIONAL_LIGHTS_COOKIE_ATLAS:
case DEBUGFULLSCREENMODE_REFLECTION_PROBE_ATLAS:
case DEBUGFULLSCREENMODE_STP:
{
float2 uvOffset = half2(uv.x - _DebugTextureDisplayRect.x, uv.y - _DebugTextureDisplayRect.y);
if ((uvOffset.x >= 0) && (uvOffset.x < _DebugTextureDisplayRect.z) &&
(uvOffset.y >= 0) && (uvOffset.y < _DebugTextureDisplayRect.w))
{
float2 debugTextureUv = float2(uvOffset.x / _DebugTextureDisplayRect.z, uvOffset.y / _DebugTextureDisplayRect.w);
half4 sampleColor = (half4)0;
if (_DebugRenderTargetSupportsStereo == 1)
sampleColor = SAMPLE_TEXTURE2D_X(_DebugTexture, sampler_DebugTexture, debugTextureUv);
else
sampleColor = SAMPLE_TEXTURE2D(_DebugTextureNoStereo, sampler_DebugTexture, debugTextureUv);
// Optionally remap source to valid visualization range.
if(any(_DebugRenderTargetRangeRemap != 0))
{
sampleColor.rgb = RemapSourceRange(sampleColor).rgb;
}
if (_DebugFullScreenMode == DEBUGFULLSCREENMODE_DEPTH)
{
debugColor = half4(sampleColor.rrr, 1);
}
else if (_DebugFullScreenMode == DEBUGFULLSCREENMODE_MOTION_VECTOR)
{
// Motion vector is RG only.
debugColor = half4(sampleColor.rg, 0, 1);
}
else if (_DebugFullScreenMode == DEBUGFULLSCREENMODE_STP)
{
// This is encoded in gamma 2.0 (so the square is needed to get it back to linear).
debugColor = sampleColor * sampleColor;
}
else
{
debugColor = sampleColor;
}
return true;
}
else
{
return false;
}
}
default:
{
return false;
}
} // End of switch.
}
bool CalculateDebugColorValidationSettings(half4 color, float2 uv, inout half4 debugColor)
{
switch(_DebugValidationMode)
{
case DEBUGVALIDATIONMODE_HIGHLIGHT_NAN_INF_NEGATIVE:
{
if (AnyIsNaN(color))
{
debugColor = half4(1, 0, 0, 1);
}
else if (AnyIsInf(color))
{
debugColor = half4(0, 1, 0, 1);
}
else if (color.r < 0 || color.g < 0 || color.b < 0 || color.a < 0)
{
debugColor = half4(0, 0, 1, 1);
}
else
{
debugColor = half4(Luminance(color).rrr, 1);
}
return true;
}
case DEBUGVALIDATIONMODE_HIGHLIGHT_OUTSIDE_OF_RANGE:
{
float val;
if (_ValidationChannels == PIXELVALIDATIONCHANNELS_RGB)
{
val = Luminance(color.rgb);
}
else if (_ValidationChannels == PIXELVALIDATIONCHANNELS_R)
{
val = color.r;
}
else if (_ValidationChannels == PIXELVALIDATIONCHANNELS_G)
{
val = color.g;
}
else if (_ValidationChannels == PIXELVALIDATIONCHANNELS_B)
{
val = color.b;
}
else if (_ValidationChannels == PIXELVALIDATIONCHANNELS_A)
{
val = color.a;
}
if (val < _RangeMinimum)
debugColor = _DebugValidateBelowMinThresholdColor;
else if (val > _RangeMaximum)
debugColor = _DebugValidateAboveMaxThresholdColor;
else
debugColor = half4(Luminance(color.rgb).rrr, 1);
return true;
}
default:
{
return false;
}
} // End of switch.
}
bool CanDebugOverrideOutputColor(half4 color, float2 uv, inout half4 debugColor)
{
return CalculateDebugColorRenderingSettings(color, uv, debugColor) ||
CalculateDebugColorValidationSettings(color, uv, debugColor);
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4203f0a40f114a18a614d8fa38c29be9
timeCreated: 1614358421
@@ -0,0 +1,14 @@
#ifndef UNIVERSAL_DECAL_INPUT_INCLUDED
#define UNIVERSAL_DECAL_INPUT_INCLUDED
struct DecalSurfaceData
{
half4 baseColor;
half4 normalWS;
half3 emissive;
half metallic;
half occlusion;
half smoothness;
half MAOSAlpha;
};
#endif // UNIVERSAL_DECAL_INPUT_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3e4be2c2c37a850478a159473b68a63f
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,46 @@
#ifndef UNITY_DECLARE_DEPTH_TEXTURE_INCLUDED
#define UNITY_DECLARE_DEPTH_TEXTURE_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/DynamicScalingClamping.hlsl"
TEXTURE2D_X_FLOAT(_CameraDepthTexture);
float4 _CameraDepthTexture_TexelSize;
// 2023.3 Deprecated. This is for backwards compatibility. Remove in the future.
#define sampler_CameraDepthTexture sampler_PointClamp
// Framebuffer fetch API for depth input attachment
#if defined(_DEPTH_AS_INPUT_ATTACHMENT)
FRAMEBUFFER_INPUT_X_FLOAT(0);
float FetchSceneDepth(float2 fragCoord)
{
float depth = LOAD_FRAMEBUFFER_INPUT_X(0, fragCoord).r;
return depth;
}
#elif defined(_DEPTH_AS_INPUT_ATTACHMENT_MSAA)
FRAMEBUFFER_INPUT_X_FLOAT_MS(0);
float FetchSceneDepth(float2 fragCoord, int sampleIndx)
{
float depth = LOAD_FRAMEBUFFER_INPUT_X_MS(0, sampleIndx, fragCoord).r;
return depth;
}
#endif
float SampleSceneDepth(float2 uv)
{
uv = UnityStereoTransformScreenSpaceTex(uv);
#if defined(UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION)
uv = RemovePretransformRotation(uv, GetScaledScreenParams());
#endif
uv = ClampAndScaleUVForBilinear(uv, _CameraDepthTexture_TexelSize.xy);
uint2 pixelCoord = uint2(uv * _ScreenSize.xy);
return LOAD_TEXTURE2D_X(_CameraDepthTexture, pixelCoord).r;
}
float LoadSceneDepth(uint2 pixelCoords)
{
return LOAD_TEXTURE2D_X(_CameraDepthTexture, pixelCoords).r;
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ff20ba0133cd2904ebf470aedb16e9a2
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
#ifndef UNITY_DECLARE_NORMALS_TEXTURE_INCLUDED
#define UNITY_DECLARE_NORMALS_TEXTURE_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/DynamicScalingClamping.hlsl"
TEXTURE2D_X_FLOAT(_CameraNormalsTexture);
float4 _CameraNormalsTexture_TexelSize;
// 2023.3 Deprecated. This is for backwards compatibility. Remove in the future.
#define sampler_CameraNormalsTexture sampler_PointClamp
float3 SampleSceneNormals(float2 uv, SAMPLER(samplerParam))
{
uv = UnityStereoTransformScreenSpaceTex(uv);
#if defined(UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION)
uv = RemovePretransformRotation(uv, GetScaledScreenParams());
#endif
uv = ClampAndScaleUVForBilinear(uv, _CameraNormalsTexture_TexelSize.xy);
// The camera normals texture has no mipmaps, so read an explicit LOD 0 to avoid an unnecessary gradient instruction.
float3 normal = SAMPLE_TEXTURE2D_X_LOD(_CameraNormalsTexture, samplerParam, uv, 0).xyz;
#if defined(_GBUFFER_NORMALS_OCT)
float2 remappedOctNormalWS = Unpack888ToFloat2(normal); // values between [ 0, 1]
float2 octNormalWS = remappedOctNormalWS.xy * 2.0 - 1.0; // values between [-1, +1]
normal = UnpackNormalOctQuadEncode(octNormalWS);
#endif
return normal;
}
float3 SampleSceneNormals(float2 uv)
{
return SampleSceneNormals(uv, sampler_PointClamp);
}
float3 LoadSceneNormals(uint2 pixelCoords)
{
float3 normal = LOAD_TEXTURE2D_X(_CameraNormalsTexture, pixelCoords).xyz;
#if defined(_GBUFFER_NORMALS_OCT)
float2 remappedOctNormalWS = Unpack888ToFloat2(normal); // values between [ 0, 1]
float2 octNormalWS = remappedOctNormalWS.xy * 2.0 - 1.0; // values between [-1, +1]
normal = UnpackNormalOctQuadEncode(octNormalWS);
#endif
return normal;
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 92a8a2733f9d18a44aad998449c6ee51
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,20 @@
#ifndef UNITY_DECLARE_OPAQUE_TEXTURE_INCLUDED
#define UNITY_DECLARE_OPAQUE_TEXTURE_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/DynamicScalingClamping.hlsl"
TEXTURE2D_X(_CameraOpaqueTexture);
SAMPLER(sampler_CameraOpaqueTexture); //NOTE: Configured at runtime by copy color, can be point or bilinear.
float4 _CameraOpaqueTexture_TexelSize;
float3 SampleSceneColor(float2 uv)
{
uv = ClampAndScaleUVForBilinear(UnityStereoTransformScreenSpaceTex(uv), _CameraOpaqueTexture_TexelSize.xy);
return SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, uv).rgb;
}
float3 LoadSceneColor(uint2 uv)
{
return LOAD_TEXTURE2D_X(_CameraOpaqueTexture, uv).rgb;
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 29619926ce55c944aa978fe5e07cc3db
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
#ifndef UNITY_DECLARE_RENDERING_LAYER_TEXTURE_INCLUDED
#define UNITY_DECLARE_RENDERING_LAYER_TEXTURE_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
TYPED_TEXTURE2D_X(uint4, _CameraRenderingLayersTexture);
uint LoadSceneRenderingLayer(uint2 uvCoord)
{
return LOAD_TEXTURE2D_X(_CameraRenderingLayersTexture, uvCoord).r;
}
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6db8433897838284fa5c7571f3088db8
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
// This file should be used as a container for things on its
// way to being deprecated and removed in future releases
using System;
namespace UnityEngine.Rendering.Universal
{
public static partial class ShaderInput
{
// Even when RenderingUtils.useStructuredBuffer is true we do not this structure anymore, because in shader side worldToShadowMatrix and shadowParams must be stored in arrays of different sizes
// To specify shader-side shadow matrices and shadow parameters, see code in AdditionalLightsShadowCasterPass.SetupAdditionalLightsShadowReceiverConstants
/// <summary>
/// This has been deprecated.
/// Shadow slice matrices and per-light shadow parameters are now passed to the GPU using entries in buffers m_AdditionalLightsWorldToShadow_SSBO and m_AdditionalShadowParams_SSBO.
/// </summary>
[Obsolete("ShaderInput.ShadowData was deprecated. Shadow slice matrices and per-light shadow parameters are now passed to the GPU using entries in buffers m_AdditionalLightsWorldToShadow_SSBO and m_AdditionalShadowParams_SSBO. #from(2021.1) #breakingFrom(2023.1)", true)]
public struct ShadowData
{
/// <summary>
/// The world to shadow matrix.
/// </summary>
public Matrix4x4 worldToShadowMatrix;
/// <summary>
/// The shadow parameters.
/// </summary>
public Vector4 shadowParams;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d84e8804a1d7b884fadfe260acd3935c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
#ifndef UNIVERSAL_DEPRECATED_INCLUDED
#define UNIVERSAL_DEPRECATED_INCLUDED
// Remove in 2023.2.
// Deprecated define that was used in shadows.hlsl to set the array size of _AdditionalLightsWorldToShadow.
#define MAX_PUNCTUAL_LIGHT_SHADOW_SLICES_IN_UBO (MAX_VISIBLE_LIGHTS)
#endif // UNIVERSAL_DEPRECATED_INCLUDED
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 9802e36ef1c38064d9bcd7bf2e01cccb
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
#pragma once
#include "Packages/com.unity.render-pipelines.universal-config/Runtime/ShaderConfig.cs.hlsl"
#if USE_DYNAMIC_BRANCH_FOG_KEYWORD
#pragma dynamic_branch _ FOG_LINEAR FOG_EXP FOG_EXP2
#else
#pragma multi_compile_fog
#endif
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 31a96610f8f1dce418026fb1dec1be06
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,24 @@
#ifndef UNIVERSAL_FORWARD_PLUS_KEYWORD_DEPRECATED_INCLUDED
#define UNIVERSAL_FORWARD_PLUS_KEYWORD_DEPRECATED_INCLUDED
// _FORWARD_PLUS keyword deprecated in 6.1
// We will emit a warning and define deprecated macros for backwards compatibility.
// This file will be removed in a future release.
// To upgrade custom shaders, replace all instances of the deprecated macros (left) with the new macros (right):
// _FORWARD_PLUS _CLUSTER_LIGHT_LOOP
// USE_FORWARD_PLUS USE_CLUSTER_LIGHT_LOOP
// FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK
#if defined(_FORWARD_PLUS_KEYWORD_DECLARED) || defined(_FORWARD_PLUS)
#warning _FORWARD_PLUS shader keyword has been deprecated. Please update your shaders to use _CLUSTER_LIGHT_LOOP shader keyword instead, otherwise shader compilation times may be negatively affected.
#endif
#if defined(_FORWARD_PLUS)
#define USE_FORWARD_PLUS USE_CLUSTER_LIGHT_LOOP
#define FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK
#if !defined(_CLUSTER_LIGHT_LOOP)
#define _CLUSTER_LIGHT_LOOP 1
#endif
#endif
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e363e809b854c74b30d5945820534d4
timeCreated: 1732640206
@@ -0,0 +1,144 @@
// This file contains common functionality used for URP GBuffer passes.
// This should not be included directly, instead include GBufferInput.hlsl or GBufferOutput.hlsl.
#ifndef UNIVERSAL_GBUFFERCOMMON_INCLUDED
#define UNIVERSAL_GBUFFERCOMMON_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
// Material flags:
#define kMaterialFlagReceiveShadowsOff 1 // Does not receive dynamic shadows
#define kMaterialFlagSpecularHighlightsOff 2 // Does not receive specular
#define kMaterialFlagSubtractiveMixedLighting 4 // The geometry uses subtractive mixed lighting
#define kMaterialFlagSpecularSetup 8 // Lit material use specular setup instead of metallic setup
// GBuffer feature macros. Deduced from active keywords:
#if defined(_RENDER_PASS_ENABLED)
#define GBUFFER_FBFETCH_AVAILABLE 1
#endif
#if defined(GBUFFER_FBFETCH_AVAILABLE)
#define GBUFFER_FEATURE_DEPTH 1
#endif
#if defined(SHADOWS_SHADOWMASK)
#define GBUFFER_FEATURE_SHADOWMASK 1
#elif !defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
#define GBUFFER_FEATURE_SHADOWMASK 1
#elif defined(_DEFERRED_MIXED_LIGHTING)
#define GBUFFER_FEATURE_SHADOWMASK 1
#endif
#if (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
#define GBUFFER_FEATURE_RENDERING_LAYERS 1
#endif
// Setup static GBuffer index macros:
#define GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS 0
#define GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION 1
#define GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS 2
// Helper macro to get GBuffer index + 1
#define GBUFFER_IDX_AFTER(x) GBUFFER_IDX_AFTER_ ## x
#define GBUFFER_IDX_AFTER_0 1
#define GBUFFER_IDX_AFTER_1 2
#define GBUFFER_IDX_AFTER_2 3
#define GBUFFER_IDX_AFTER_3 4
#define GBUFFER_IDX_AFTER_4 5
#define GBUFFER_IDX_AFTER_5 6
#define GBUFFER_IDX_AFTER_6 7
#define GBUFFER_IDX_AFTER_7 8
// Setup dynamic GBuffer index macros.
// These are extra GBuffers that may be used depending on which features are enabled.
// Index is dynamically assigned for each combination of enabled/disabled features.
// Possible features: [GBUFFER_FEATURE_DEPTH, GBUFFER_FEATURE_RENDERING_LAYERS, GBUFFER_FEATURE_SHADOWMASK]
#if defined(GBUFFER_FEATURE_DEPTH)
// [1, 0, 0]
#define GBUFFER_IDX_R_DEPTH GBUFFER_IDX_AFTER(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS)
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
// [1, 1, 0]
#define GBUFFER_IDX_R_RENDERING_LAYERS GBUFFER_IDX_AFTER(GBUFFER_IDX_R_DEPTH)
#if defined(GBUFFER_FEATURE_SHADOWMASK)
// [1, 1, 1]
#define GBUFFER_IDX_RGBA_SHADOWMASK GBUFFER_IDX_AFTER(GBUFFER_IDX_R_RENDERING_LAYERS)
#endif
#elif defined(GBUFFER_FEATURE_SHADOWMASK)
// [1, 0, 1]
#define GBUFFER_IDX_RGBA_SHADOWMASK GBUFFER_IDX_AFTER(GBUFFER_IDX_R_DEPTH)
#endif
#elif defined(GBUFFER_FEATURE_RENDERING_LAYERS)
// [0, 1, 0]
#define GBUFFER_IDX_R_RENDERING_LAYERS GBUFFER_IDX_AFTER(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS)
#if defined(GBUFFER_FEATURE_SHADOWMASK)
// [0, 1, 1]
#define GBUFFER_IDX_RGBA_SHADOWMASK GBUFFER_IDX_AFTER(GBUFFER_IDX_R_RENDERING_LAYERS)
#endif
#elif defined(GBUFFER_FEATURE_SHADOWMASK)
// [0, 0, 1]
#define GBUFFER_IDX_RGBA_SHADOWMASK GBUFFER_IDX_AFTER(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS)
#endif
// Unpacked URP GBuffer data.
struct GBufferData
{
half3 baseColor;
half smoothness;
// For Lit materials, if !(materialFlags & kMaterialFlagSpecularSetup) then specularColor.r contains metallic.
half3 specularColor;
half occlusion;
float3 normalWS;
uint materialFlags;
float depth;
// Only assigned if GBUFFER_FEATURE_SHADOWMASK is defined!
// Otherwise, defaults to (1, 1, 1, 1)
half4 shadowMask;
// Only assigned if GBUFFER_FEATURE_RENDERING_LAYERS is defined!
// Otherwise, defaults to 0xFFFF (Everything)
uint meshRenderingLayers;
};
// GBuffer utility functions:
float PackGBufferMaterialFlags(uint materialFlags)
{
return materialFlags * (half(1.0) / half(255.0));
}
uint UnpackGBufferMaterialFlags(float packedMaterialFlags)
{
return uint((packedMaterialFlags * half(255.0)) + half(0.5));
}
#if defined(_GBUFFER_NORMALS_OCT)
half3 PackGBufferNormal(half3 normalWS)
{
float2 octNormalWS = PackNormalOctQuadEncode(normalWS); // values between [-1, +1], must use fp32 on some platforms.
float2 remappedOctNormalWS = saturate(octNormalWS * 0.5 + 0.5); // values between [ 0, +1]
return half3(PackFloat2To888(remappedOctNormalWS)); // values between [ 0, +1]
}
half3 UnpackGBufferNormal(half3 packedNormalWS)
{
half2 remappedOctNormalWS = half2(Unpack888ToFloat2(packedNormalWS));// values between [ 0, +1]
half2 octNormalWS = remappedOctNormalWS.xy * half(2.0) - half(1.0); // values between [-1, +1]
return half3(UnpackNormalOctQuadEncode(octNormalWS)); // values between [-1, +1]
}
#else
half3 PackGBufferNormal(half3 normalWS)
{ return normalWS; } // values between [-1, +1]
half3 UnpackGBufferNormal(half3 packedNormalWS)
{ return packedNormalWS; } // values between [-1, +1]
#endif
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bc7fdf95b149455c88d444108d74601c
timeCreated: 1730904473
@@ -0,0 +1,191 @@
// This file contains functionality for reading the contents of URP GBuffers.
// Shaders using these functions must execute after the GBuffer pass, or else GBuffers will be invalid.
#ifndef UNIVERSAL_GBUFFERINPUT_INCLUDED
#define UNIVERSAL_GBUFFERINPUT_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferCommon.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
#if defined(GBUFFER_FBFETCH_AVAILABLE)
// Native render pass / framebuffer fetch available!
// Use framebuffer input.
// Static index GBuffers:
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS);
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION);
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS);
FRAMEBUFFER_INPUT_X_FLOAT(GBUFFER_IDX_R_DEPTH);
// Dynamic index GBuffer: Shadow mask
#if defined(GBUFFER_FEATURE_SHADOWMASK)
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGBA_SHADOWMASK);
#endif
// Dynamic index GBuffer: Rendering layers
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
FRAMEBUFFER_INPUT_X_UINT(GBUFFER_IDX_R_RENDERING_LAYERS);
#endif
#else
// Native render pass / framebuffer fetch is not available.
// Fall back to regular texture bindings.
// Helper macro to convert GBuffer index macro to texture slot name.
#define GBUFFER_TEX2D_NAME(index) _GBuffer##index
// Static index GBuffers:
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS));
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION));
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS));
// We never bind GBUFFER_TEX2D_NAME(GBUFFER_IDX_R_DEPTH), instead we expect the depth to be bound to the _CameraDepthTexture slot.
TEXTURE2D_X_FLOAT(_CameraDepthTexture);
// Dynamic index GBuffer: Shadow mask
#if defined(GBUFFER_FEATURE_SHADOWMASK)
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_RGBA_SHADOWMASK)));
#endif
// Dynamic index GBuffer: Rendering layers
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
TYPED_TEXTURE2D_X(uint4, GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_R_RENDERING_LAYERS)));
#endif
#endif
// Load raw GBuffer data.
// Use this if overriding data in the GBuffers, otherwise use UnpackGBuffers().
// If shadow mask is not used, shadowMask defaults to (1, 1, 1, 1).
// If rendering layers is not used, renderingLayers defaults to 0xffff.
// Note that unCoord2 is in pixel coordinates, not screen UVs.
void LoadGBuffers(uint2 unCoord2, out half4 gBuffer0, out half4 gBuffer1, out half4 gBuffer2, out float depth,
out uint renderingLayers, out half4 shadowMask)
{
renderingLayers = 0xFFFFFFFF;
shadowMask = half4(1, 1, 1, 1);
#if defined(GBUFFER_FBFETCH_AVAILABLE)
depth = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_R_DEPTH, unCoord2).x;
gBuffer0 = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS, unCoord2);
gBuffer1 = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION, unCoord2);
gBuffer2 = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS, unCoord2);
#if defined(GBUFFER_FEATURE_SHADOWMASK)
shadowMask = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGBA_SHADOWMASK, unCoord2);
#endif
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
renderingLayers = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_R_RENDERING_LAYERS, unCoord2).x;
#endif
#else
depth = LOAD_TEXTURE2D_X(_CameraDepthTexture, unCoord2).x;
gBuffer0 = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS), unCoord2);
gBuffer1 = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION), unCoord2);
gBuffer2 = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS), unCoord2);
#if defined(GBUFFER_FEATURE_SHADOWMASK)
shadowMask = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_RGBA_SHADOWMASK)), unCoord2);
#endif
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
renderingLayers = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_R_RENDERING_LAYERS)), unCoord2).x;
#endif
#endif
}
// Load raw GBuffer content and unpack into GBufferData.
// Note that unCoord2 is in pixel coordinates, not screen UVs.
GBufferData UnpackGBuffers(uint2 unCoord2)
{
half4 gBuffer0;
half4 gBuffer1;
half4 gBuffer2;
float depth;
uint renderingLayers;
half4 shadowMask;
LoadGBuffers(unCoord2, gBuffer0, gBuffer1, gBuffer2, depth, renderingLayers, shadowMask);
GBufferData gBufferData;
ZERO_INITIALIZE(GBufferData, gBufferData);
gBufferData.baseColor = gBuffer0.rgb;
gBufferData.materialFlags = UnpackGBufferMaterialFlags(gBuffer0.a);
gBufferData.specularColor = gBuffer1.rgb;
gBufferData.occlusion = gBuffer1.a;
gBufferData.normalWS = normalize(UnpackGBufferNormal(gBuffer2.rgb));
gBufferData.smoothness = gBuffer2.a;
gBufferData.depth = depth;
gBufferData.shadowMask = shadowMask;
gBufferData.meshRenderingLayers = renderingLayers;
return gBufferData;
}
// Interpret SurfaceData from GBufferData.
// Used by SimpleLit materials.
SurfaceData GBufferDataToSurfaceData(GBufferData gBufferData)
{
SurfaceData surfaceData = (SurfaceData)0;
surfaceData.albedo = gBufferData.baseColor;
surfaceData.occlusion = 0.0;
surfaceData.specular = gBufferData.specularColor;
surfaceData.metallic = 0.0; // Not used by SimpleLit material.
surfaceData.alpha = 1.0; // GBuffer only contains opaque materials
surfaceData.smoothness = gBufferData.smoothness;
return surfaceData;
}
// Interpret BRDFData from GBufferData.
// Used by Lit materials.
BRDFData GBufferDataToBRDFData(GBufferData gBufferData)
{
half3 albedo = gBufferData.baseColor;
half3 specular = gBufferData.specularColor;
uint materialFlags = gBufferData.materialFlags;
half smoothness = gBufferData.smoothness;
BRDFData brdfData = (BRDFData)0;
half alpha = half(1.0); // NOTE: alpha can get modfied, forward writes it out (_ALPHAPREMULTIPLY_ON).
half3 brdfDiffuse;
half3 brdfSpecular;
half reflectivity;
half oneMinusReflectivity;
UNITY_BRANCH if ((materialFlags & kMaterialFlagSpecularSetup) != 0)
{
// Specular setup
reflectivity = ReflectivitySpecular(specular);
oneMinusReflectivity = half(1.0) - reflectivity;
brdfDiffuse = albedo * oneMinusReflectivity;
brdfSpecular = specular;
}
else
{
// Metallic setup
reflectivity = specular.r;
oneMinusReflectivity = 1.0 - reflectivity;
half metallic = MetallicFromReflectivity(reflectivity);
brdfDiffuse = albedo * oneMinusReflectivity;
brdfSpecular = lerp(kDielectricSpec.rgb, albedo, metallic);
}
InitializeBRDFDataDirect(albedo, brdfDiffuse, brdfSpecular, reflectivity, oneMinusReflectivity, smoothness, alpha, brdfData);
return brdfData;
}
#ifdef GBUFFER_TEX2D_NAME
#undef GBUFFER_TEX2D_NAME
#endif
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2b30f99b47dd40adaf41fd8e6573daa4
timeCreated: 1731066745
@@ -0,0 +1,129 @@
// This file contains functionality for writing contents of URP GBuffers.
// The functionality provided here is intended to be used during in the material GBuffer pass.
#ifndef UNIVERSAL_GBUFFEROUTPUT_INCLUDED
#define UNIVERSAL_GBUFFEROUTPUT_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferCommon.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#define DECL_SV_TARGET(idx) SV_Target##idx
#define DECL_OPT_GBUFFER_TARGET(type, name, idx) type name : DECL_SV_TARGET(GBUFFER_IDX_AFTER(idx))
// URP GBuffer pass fragment shader output struct.
struct GBufferFragOutput
{
half4 gBuffer0 : SV_Target0;
half4 gBuffer1 : SV_Target1;
half4 gBuffer2 : SV_Target2;
half4 color : SV_Target3; // Camera color attachment, used for GI during GBuffer laydown
#if defined(GBUFFER_FEATURE_DEPTH)
DECL_OPT_GBUFFER_TARGET(float, depth, GBUFFER_IDX_R_DEPTH);
#endif
#if defined(GBUFFER_FEATURE_SHADOWMASK)
DECL_OPT_GBUFFER_TARGET(half4, shadowMask, GBUFFER_IDX_RGBA_SHADOWMASK);
#endif
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
DECL_OPT_GBUFFER_TARGET(uint, meshRenderingLayers, GBUFFER_IDX_R_RENDERING_LAYERS);
#endif
};
#undef DECL_SV_TARGET
#undef DECL_OPT_GBUFFER_TARGET
// Pack SurfaceData into GBuffers.
GBufferFragOutput PackGBuffersSurfaceData(SurfaceData surfaceData, InputData inputData, half3 globalIllumination)
{
half3 packedNormalWS = PackGBufferNormal(inputData.normalWS);
uint materialFlags = 0;
// SimpleLit does not use _SPECULARHIGHLIGHTS_OFF to disable specular highlights.
#ifdef _RECEIVE_SHADOWS_OFF
materialFlags |= kMaterialFlagReceiveShadowsOff;
#endif
#if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
materialFlags |= kMaterialFlagSubtractiveMixedLighting;
#endif
GBufferFragOutput output;
output.gBuffer0 = half4(surfaceData.albedo.rgb, PackGBufferMaterialFlags(materialFlags)); // albedo albedo albedo materialFlags (sRGB rendertarget)
output.gBuffer1 = half4(surfaceData.specular.rgb, surfaceData.occlusion); // specular specular specular occlusion
output.gBuffer2 = half4(packedNormalWS, surfaceData.smoothness); // encoded-normal encoded-normal encoded-normal smoothness
output.color = half4(globalIllumination, 1); // GI GI GI unused (lighting buffer)
#if defined(GBUFFER_FEATURE_DEPTH)
output.depth = inputData.positionCS.z;
#endif
#if defined(GBUFFER_FEATURE_SHADOWMASK)
output.shadowMask = inputData.shadowMask; // will have unity_ProbesOcclusion value if subtractive lighting is used (baked)
#endif
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
output.meshRenderingLayers = EncodeMeshRenderingLayer();
#endif
return output;
}
// Pack BRDFData into GBuffers.
GBufferFragOutput PackGBuffersBRDFData(BRDFData brdfData, InputData inputData, half smoothness, half3 globalIllumination, half occlusion = 1.0)
{
half3 packedNormalWS = PackGBufferNormal(inputData.normalWS);
uint materialFlags = 0;
#ifdef _RECEIVE_SHADOWS_OFF
materialFlags |= kMaterialFlagReceiveShadowsOff;
#endif
half3 packedSpecular;
#ifdef _SPECULAR_SETUP
materialFlags |= kMaterialFlagSpecularSetup;
packedSpecular = brdfData.specular.rgb;
#else
packedSpecular.r = brdfData.reflectivity;
packedSpecular.gb = 0.0;
#endif
#ifdef _SPECULARHIGHLIGHTS_OFF
// During the next deferred shading pass, we don't use a shader variant to disable specular calculations.
// Instead, we can either silence specular contribution when writing the gbuffer, and/or reserve a bit in the gbuffer
// and use this during shading to skip computations via dynamic branching. Fastest option depends on platforms.
materialFlags |= kMaterialFlagSpecularHighlightsOff;
packedSpecular = 0.0.xxx;
#endif
#if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
materialFlags |= kMaterialFlagSubtractiveMixedLighting;
#endif
GBufferFragOutput output;
output.gBuffer0 = half4(brdfData.albedo.rgb, PackGBufferMaterialFlags(materialFlags)); // diffuse diffuse diffuse materialFlags (sRGB rendertarget)
output.gBuffer1 = half4(packedSpecular, occlusion); // metallic/specular specular specular occlusion
output.gBuffer2 = half4(packedNormalWS, smoothness); // encoded-normal encoded-normal encoded-normal smoothness
output.color = half4(globalIllumination, 1); // GI GI GI unused (lighting buffer)
#if defined(GBUFFER_FEATURE_DEPTH)
output.depth = inputData.positionCS.z;
#endif
#if defined(GBUFFER_FEATURE_SHADOWMASK)
output.shadowMask = inputData.shadowMask; // will have unity_ProbesOcclusion value if subtractive lighting is used (baked)
#endif
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
output.meshRenderingLayers = EncodeMeshRenderingLayer();
#endif
return output;
}
#endif // UNIVERSAL_GBUFFERUTIL_INCLUDED
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: db51e39af1b3c01449a3e6b1ce782a48
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
// This file contains functionality for letting the Unity Shader Compiler know what render target formats could be used
// The functionality provided here is intended to be used during in the material GBuffer pass.
#ifndef UNIVERSAL_GBUFFEROUTPUTFORMAT_INCLUDED
#define UNIVERSAL_GBUFFEROUTPUTFORMAT_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferCommon.hlsl"
// Keep these formats in sync with the formats returned in DeferredLights.GetGBufferFormat
#pragma rendertarget_format_hint MRT0 R8G8B8A8_SRGB
#pragma rendertarget_format_hint MRT1 R8G8B8A8_SRGB
#pragma rendertarget_format_hint MRT2 R8G8B8A8_SRGB
#pragma rendertarget_format_hint MRT3 R8G8B8A8_SRGB,B10G11R11_UFloatPack32
#pragma rendertarget_format_hint MRT4 R32_SFloat // Assume GBUFFER_FEATURE_DEPTH is always enabled at the moment.
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
#pragma rendertarget_format_hint MRT5 R8_UInt, R16_UInt, R32_UInt
#if defined(GBUFFER_FEATURE_SHADOWMASK)
#pragma rendertarget_format_hint MRT6 B8G8R8A8_UNorm, R8G8B8A8_UNorm
#endif
#else // GBUFFER_FEATURE_RENDERING_LAYERS
#if defined(GBUFFER_FEATURE_SHADOWMASK)
#pragma rendertarget_format_hint MRT5 B8G8R8A8_UNorm, R8G8B8A8_UNorm
#endif
#endif
#endif // UNIVERSAL_GBUFFEROUTPUTFORMAT_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 87322610c9b88a64e8bce40c056d8116
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,655 @@
#ifndef UNIVERSAL_GLOBAL_ILLUMINATION_INCLUDED
#define UNIVERSAL_GLOBAL_ILLUMINATION_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SampleScreenSpaceReflection.hlsl"
#define AMBIENT_PROBE_BUFFER 0
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/AmbientProbe.hlsl"
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
#include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl"
#endif
#if USE_CLUSTER_LIGHT_LOOP
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#endif
#if defined(_SCREEN_SPACE_IRRADIANCE)
TEXTURE2D_X(_ScreenSpaceIrradiance);
half3 SampleScreenSpaceGI(float2 pos)
{
return LOAD_TEXTURE2D_X(_ScreenSpaceIrradiance, pos).rgb;
}
#endif
// If lightmap is not defined than we evaluate GI (ambient + probes) from SH
// Renamed -> LIGHTMAP_SHADOW_MIXING
#if !defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK)
#define _MIXED_LIGHTING_SUBTRACTIVE
#endif
#if !defined(_REFLECTION_PROBE_BLENDING_KEYWORD_DECLARED) && !defined(_REFLECTION_PROBE_BLENDING)
#define _REFLECTION_PROBE_BLENDING 0
#endif
#if !defined(_REFLECTION_PROBE_BOX_PROJECTION_KEYWORD_DECLARED) && !defined(_REFLECTION_PROBE_BOX_PROJECTION)
#define _REFLECTION_PROBE_BOX_PROJECTION 0
#endif
// SH Vertex Evaluation. Depending on target SH sampling might be
// done completely per vertex or mixed with L2 term per vertex and L0, L1
// per pixel. See SampleSHPixel
half3 SampleSHVertex(half3 normalWS)
{
#if defined(EVALUATE_SH_VERTEX)
return EvaluateAmbientProbeSRGB(normalWS);
#elif defined(EVALUATE_SH_MIXED)
// no max since this is only L2 contribution
return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC);
#endif
// Fully per-pixel. Nothing to compute.
return half3(0.0, 0.0, 0.0);
}
// SH Pixel Evaluation. Depending on target SH sampling might be done
// mixed or fully in pixel. See SampleSHVertex
half3 SampleSHPixel(half3 L2Term, half3 normalWS)
{
#if defined(EVALUATE_SH_VERTEX)
return L2Term;
#elif defined(EVALUATE_SH_MIXED)
half3 res = L2Term + SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return max(half3(0, 0, 0), res);
#endif
// Default: Evaluate SH fully per-pixel
return EvaluateAmbientProbeSRGB(normalWS);
}
// APV Prove volume
// Vertex and Mixed both use Vertex sampling
#if (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
half3 SampleProbeVolumeVertex(in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, out float4 probeOcclusion)
{
probeOcclusion = 1.0;
#if defined(EVALUATE_SH_VERTEX) || defined(EVALUATE_SH_MIXED)
half3 bakedGI;
if (_EnableProbeVolumes)
{
EvaluateAdaptiveProbeVolume(absolutePositionWS, normalWS, viewDir, GetMeshRenderingLayer(), bakedGI, probeOcclusion);
}
else
{
bakedGI = EvaluateAmbientProbe(normalWS);
}
#ifdef UNITY_COLORSPACE_GAMMA
bakedGI = LinearToSRGB(bakedGI);
#endif
return bakedGI;
#else
return half3(0, 0, 0);
#endif
}
half3 SampleProbeVolumePixel(in half3 vertexValue, in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, in float2 positionSS, in float4 vertexProbeOcclusion, out float4 probeOcclusion)
{
probeOcclusion = 1.0;
#if defined(EVALUATE_SH_VERTEX) || defined(EVALUATE_SH_MIXED)
probeOcclusion = vertexProbeOcclusion;
return vertexValue;
#elif defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
half3 bakedGI;
if (_EnableProbeVolumes)
{
EvaluateAdaptiveProbeVolume(absolutePositionWS, normalWS, viewDir, positionSS, GetMeshRenderingLayer(), bakedGI, probeOcclusion);
}
else
{
bakedGI = EvaluateAmbientProbe(normalWS);
}
#ifdef UNITY_COLORSPACE_GAMMA
bakedGI = LinearToSRGB(bakedGI);
#endif
return bakedGI;
#else
return half3(0, 0, 0);
#endif
}
half3 SampleProbeVolumePixel(in half3 vertexValue, in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, in float2 positionSS)
{
float4 unusedProbeOcclusion = 0;
return SampleProbeVolumePixel(vertexValue, absolutePositionWS, normalWS, viewDir, positionSS, unusedProbeOcclusion, unusedProbeOcclusion);
}
#endif
half3 SampleProbeSHVertex(in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, out float4 probeOcclusion)
{
probeOcclusion = 1.0;
#if (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
return SampleProbeVolumeVertex(absolutePositionWS, normalWS, viewDir, probeOcclusion);
#else
return SampleSHVertex(normalWS);
#endif
}
half3 SampleProbeSHVertex(in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir)
{
float4 unusedProbeOcclusion = 0;
return SampleProbeSHVertex(absolutePositionWS, normalWS, viewDir, unusedProbeOcclusion);
}
#if defined(UNITY_DOTS_INSTANCING_ENABLED) && !defined(USE_LEGACY_LIGHTMAPS)
// ^ GPU-driven rendering is enabled, and we haven't opted-out from lightmap
// texture arrays. This minimizes batch breakages, but texture arrays aren't
// supported in a performant way on all GPUs.
#define LIGHTMAP_NAME unity_Lightmaps
#define LIGHTMAP_INDIRECTION_NAME unity_LightmapsInd
#define LIGHTMAP_SAMPLER_NAME samplerunity_Lightmaps
#define LIGHTMAP_SAMPLE_EXTRA_ARGS staticLightmapUV, unity_LightmapIndex.x
#else
// ^ Lightmaps are not bound as texture arrays, but as individual textures. The
// batch is broken every time lightmaps are changed, but this is well-supported
// on all GPUs.
#define LIGHTMAP_NAME unity_Lightmap
#define LIGHTMAP_INDIRECTION_NAME unity_LightmapInd
#define LIGHTMAP_SAMPLER_NAME samplerunity_Lightmap
#define LIGHTMAP_SAMPLE_EXTRA_ARGS staticLightmapUV
#endif
// Sample baked and/or realtime lightmap. Non-Direction and Directional if available.
half3 SampleLightmap(float2 staticLightmapUV, float2 dynamicLightmapUV, half3 normalWS)
{
// The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
// However, universal pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
// the compiler will optimize the transform away.
half4 transformCoords = half4(1, 1, 0, 0);
float3 diffuseLighting = 0;
#if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
diffuseLighting = SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME),
TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_INDIRECTION_NAME, LIGHTMAP_SAMPLER_NAME),
LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, normalWS, true);
#elif defined(LIGHTMAP_ON)
diffuseLighting = SampleSingleLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME), LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, true);
#endif
#if defined(DYNAMICLIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
diffuseLighting += SampleDirectionalLightmap(TEXTURE2D_ARGS(unity_DynamicLightmap, samplerunity_DynamicLightmap),
TEXTURE2D_ARGS(unity_DynamicDirectionality, samplerunity_DynamicLightmap),
dynamicLightmapUV, transformCoords, normalWS, false);
#elif defined(DYNAMICLIGHTMAP_ON)
diffuseLighting += SampleSingleLightmap(TEXTURE2D_ARGS(unity_DynamicLightmap, samplerunity_DynamicLightmap),
dynamicLightmapUV, transformCoords, false);
#endif
return diffuseLighting;
}
// Legacy version of SampleLightmap where Realtime GI is not supported.
half3 SampleLightmap(float2 staticLightmapUV, half3 normalWS)
{
float2 dummyDynamicLightmapUV = float2(0,0);
half3 result = SampleLightmap(staticLightmapUV, dummyDynamicLightmapUV, normalWS);
return result;
}
#if defined(_SCREEN_SPACE_IRRADIANCE)
#if !defined(_SURFACE_TYPE_TRANSPARENT)
#define SAMPLE_GI(irradianceTex, pos, normal) SampleScreenSpaceGI(pos)
#else
#define SAMPLE_GI(irradianceTex, pos, normal) EvaluateAmbientProbe(normal)
#endif
#elif defined(LIGHTMAP_ON) && defined(DYNAMICLIGHTMAP_ON)
#define SAMPLE_GI(staticLmName, dynamicLmName, shName, normalWSName) SampleLightmap(staticLmName, dynamicLmName, normalWSName)
#elif defined(DYNAMICLIGHTMAP_ON)
#define SAMPLE_GI(staticLmName, dynamicLmName, shName, normalWSName) SampleLightmap(0, dynamicLmName, normalWSName)
#elif defined(LIGHTMAP_ON)
#define SAMPLE_GI(staticLmName, shName, normalWSName) SampleLightmap(staticLmName, 0, normalWSName)
#elif defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
#ifdef USE_APV_PROBE_OCCLUSION
#define SAMPLE_GI(shName, absolutePositionWS, normalWS, viewDir, positionSS, vertexProbeOcclusion, probeOcclusion) SampleProbeVolumePixel(shName, absolutePositionWS, normalWS, viewDir, positionSS, vertexProbeOcclusion, probeOcclusion)
#else
#define SAMPLE_GI(shName, absolutePositionWS, normalWS, viewDir, positionSS, vertexProbeOcclusion, probeOcclusion) SampleProbeVolumePixel(shName, absolutePositionWS, normalWS, viewDir, positionSS)
#endif
#else
#define SAMPLE_GI(staticLmName, shName, normalWSName) SampleSHPixel(shName, normalWSName)
#endif
float3 GetReflectionProbeCenter(float4 boxMin, float4 boxMax)
{
return boxMin.xyz + (boxMax.xyz - boxMin.xyz) / 2;
}
float3 GetRotatedPoint(float3 centerPosition, float4 quaternion, float3 pointToRotate)
{
return RotateVectorByQuat(quaternion, pointToRotate - centerPosition) + centerPosition;
}
half3 BoxProjectedCubemapDirection(half3 reflectionWS, float3 positionWS, float4 cubemapPositionWS, float4 boxMin, float4 boxMax)
{
// Is this probe using box projection?
if (cubemapPositionWS.w > 0.0f)
{
float3 boxMinMax = (reflectionWS > 0.0f) ? boxMax.xyz : boxMin.xyz;
half3 rbMinMax = half3(boxMinMax - positionWS) / reflectionWS;
half fa = half(min(min(rbMinMax.x, rbMinMax.y), rbMinMax.z));
half3 worldPos = half3(positionWS - cubemapPositionWS.xyz);
half3 result = worldPos + reflectionWS * fa;
return result;
}
else
{
return reflectionWS;
}
}
half3 BoxProjectedCubemapDirection(float4 rotation, half3 reflectionWS, float3 positionWS, float4 cubemapPositionWS, float4 boxMin, float4 boxMax)
{
half3 rotReflectVector = RotateVectorByQuat(rotation, reflectionWS);
float4 inverseRotation = -rotation;
inverseRotation.w = -inverseRotation.w;
half3 dir = BoxProjectedCubemapDirection(rotReflectVector, positionWS, cubemapPositionWS, boxMin, boxMax);
half3 rotatedDir = RotateVectorByQuat(inverseRotation, dir);
return rotatedDir;
}
float CalculateProbeWeight(float3 positionWS, float4 probeBoxMin, float4 probeBoxMax)
{
float blendDistance = probeBoxMax.w;
float3 weightDir = min(positionWS - probeBoxMin.xyz, probeBoxMax.xyz - positionWS) / blendDistance;
return saturate(min(weightDir.x, min(weightDir.y, weightDir.z)));
}
half CalculateProbeVolumeSqrMagnitude(float4 probeBoxMin, float4 probeBoxMax)
{
half3 maxToMin = half3(probeBoxMax.xyz - probeBoxMin.xyz);
return dot(maxToMin, maxToMin);
}
half3 CalculateIrradianceFromReflectionProbes(half3 reflectVector, float3 positionWS, half perceptualRoughness, float2 normalizedScreenSpaceUV)
{
half3 irradiance = half3(0.0h, 0.0h, 0.0h);
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
#if USE_CLUSTER_LIGHT_LOOP && CLUSTER_HAS_REFLECTION_PROBES
float totalWeight = 0.0f;
uint probeIndex;
ClusterIterator it = ClusterInit(normalizedScreenSpaceUV, positionWS, 1);
[loop] while (ClusterNext(it, probeIndex) && totalWeight < 0.99f)
{
probeIndex -= URP_FP_PROBES_BEGIN;
#if defined(REFLECTION_PROBE_ROTATION)
// We need to rotated positionWS such that we can assume the influence volumes to be axis aligned
// when calculating the weight and box projection.
float3 probeCenterPosWS = GetReflectionProbeCenter(urp_ReflProbes_BoxMin[probeIndex], urp_ReflProbes_BoxMax[probeIndex]);
float3 rotPosWS = GetRotatedPoint(probeCenterPosWS, urp_ReflProbes_Rotation[probeIndex], positionWS);
#else
float3 rotPosWS = positionWS;
#endif
float weight = CalculateProbeWeight(rotPosWS, urp_ReflProbes_BoxMin[probeIndex], urp_ReflProbes_BoxMax[probeIndex]);
weight = min(weight, 1.0f - totalWeight);
half3 sampleVector = reflectVector;
if (_REFLECTION_PROBE_BOX_PROJECTION)
{
#if defined(REFLECTION_PROBE_ROTATION)
sampleVector = BoxProjectedCubemapDirection(urp_ReflProbes_Rotation[probeIndex], reflectVector, rotPosWS, urp_ReflProbes_ProbePosition[probeIndex], urp_ReflProbes_BoxMin[probeIndex], urp_ReflProbes_BoxMax[probeIndex]);
#else
sampleVector = BoxProjectedCubemapDirection(reflectVector, rotPosWS, urp_ReflProbes_ProbePosition[probeIndex], urp_ReflProbes_BoxMin[probeIndex], urp_ReflProbes_BoxMax[probeIndex]);
#endif
}
uint maxMip = (uint)abs(urp_ReflProbes_ProbePosition[probeIndex].w) - 1;
half probeMip = min(mip, maxMip);
float2 uv = saturate(PackNormalOctQuadEncode(sampleVector) * 0.5 + 0.5);
float mip0 = floor(probeMip);
float mip1 = mip0 + 1;
float mipBlend = probeMip - mip0;
float4 scaleOffset0 = urp_ReflProbes_MipScaleOffset[probeIndex * 7 + (uint)mip0];
float4 scaleOffset1 = urp_ReflProbes_MipScaleOffset[probeIndex * 7 + (uint)mip1];
half3 irradiance0 = half4(SAMPLE_TEXTURE2D_LOD(urp_ReflProbes_Atlas, sampler_LinearClamp, uv * scaleOffset0.xy + scaleOffset0.zw, 0.0)).rgb;
half3 irradiance1 = half4(SAMPLE_TEXTURE2D_LOD(urp_ReflProbes_Atlas, sampler_LinearClamp, uv * scaleOffset1.xy + scaleOffset1.zw, 0.0)).rgb;
irradiance += weight * lerp(irradiance0, irradiance1, mipBlend);
totalWeight += weight;
}
#else
#if defined(REFLECTION_PROBE_ROTATION)
// We need to rotated positionWS such that we can assume the influence volumes to be axis aligned
// when calculating the weight and box projection.
float3 probeCenterPosWS0 = GetReflectionProbeCenter(unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
float3 rotPosWS0 = GetRotatedPoint(probeCenterPosWS0, unity_SpecCube0_Rotation, positionWS);
float3 probeCenterPosWS1 = GetReflectionProbeCenter(unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
float3 rotPosWS1 = GetRotatedPoint(probeCenterPosWS1, unity_SpecCube1_Rotation, positionWS);
#else
float3 rotPosWS0 = positionWS;
float3 rotPosWS1 = positionWS;
#endif
half probe0Volume = CalculateProbeVolumeSqrMagnitude(unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
half probe1Volume = CalculateProbeVolumeSqrMagnitude(unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
half volumeDiff = probe0Volume - probe1Volume;
float importanceSign = unity_SpecCube1_BoxMin.w;
// A probe is dominant if its importance is higher
// Or have equal importance but smaller volume
bool probe0Dominant = importanceSign > 0.0f || (importanceSign == 0.0f && volumeDiff < -0.0001h);
bool probe1Dominant = importanceSign < 0.0f || (importanceSign == 0.0f && volumeDiff > 0.0001h);
float desiredWeightProbe0 = CalculateProbeWeight(rotPosWS0, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
float desiredWeightProbe1 = CalculateProbeWeight(rotPosWS1, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
// Subject the probes weight if the other probe is dominant
float weightProbe0 = probe1Dominant ? min(desiredWeightProbe0, 1.0f - desiredWeightProbe1) : desiredWeightProbe0;
float weightProbe1 = probe0Dominant ? min(desiredWeightProbe1, 1.0f - desiredWeightProbe0) : desiredWeightProbe1;
float totalWeight = weightProbe0 + weightProbe1;
// If either probe 0 or probe 1 is dominant the sum of weights is guaranteed to be 1.
// If neither is dominant this is not guaranteed - only normalize weights if totalweight exceeds 1.
weightProbe0 /= max(totalWeight, 1.0f);
weightProbe1 /= max(totalWeight, 1.0f);
// Sample the first reflection probe
if (weightProbe0 > 0.01f)
{
half3 reflectVector0 = reflectVector;
if (_REFLECTION_PROBE_BOX_PROJECTION)
{
#if defined(REFLECTION_PROBE_ROTATION)
reflectVector0 = BoxProjectedCubemapDirection(unity_SpecCube0_Rotation, reflectVector, rotPosWS0, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
#else
reflectVector0 = BoxProjectedCubemapDirection(reflectVector, rotPosWS0, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
#endif
}
half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector0, mip));
irradiance += weightProbe0 * DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
}
// Sample the second reflection probe
if (weightProbe1 > 0.01f)
{
half3 reflectVector1 = reflectVector;
if (_REFLECTION_PROBE_BOX_PROJECTION)
{
#if defined(REFLECTION_PROBE_ROTATION)
reflectVector1 = BoxProjectedCubemapDirection(unity_SpecCube1_Rotation, reflectVector, rotPosWS1, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
#else
reflectVector1 = BoxProjectedCubemapDirection(reflectVector, rotPosWS1, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
#endif
}
half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube1, samplerunity_SpecCube1, reflectVector1, mip));
irradiance += weightProbe1 * DecodeHDREnvironment(encodedIrradiance, unity_SpecCube1_HDR);
}
#endif
// Use any remaining weight to blend to environment reflection cube map
if (totalWeight < 0.99f)
{
half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(_GlossyEnvironmentCubeMap, sampler_GlossyEnvironmentCubeMap, reflectVector, mip));
irradiance += (1.0f - totalWeight) * DecodeHDREnvironment(encodedIrradiance, _GlossyEnvironmentCubeMap_HDR);
}
return irradiance;
}
half3 GlossyEnvironmentReflection(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion, float2 normalizedScreenSpaceUV)
{
half3 irradiance = 0;
#if defined(_SCREENSPACEREFLECTIONS_OFF)
half4 ssrColor = 0;
#else
half4 ssrColor = GetScreenSpaceReflection(normalizedScreenSpaceUV, positionWS, perceptualRoughness);
#endif
// We skip sampling reflection probes if they would be overwritten by SSR anyways.
// This optimization causes a miscompilation when using FXC, and the rendering path
// is single pass stereo instancing, so disable it in that path.
#if !defined(STEREO_INSTANCING_ON) || defined(UNITY_COMPILER_DXC)
if (ssrColor.a < 1.0)
#endif
{
#if !defined(_ENVIRONMENTREFLECTIONS_OFF)
if (_REFLECTION_PROBE_BLENDING)
{
irradiance = CalculateIrradianceFromReflectionProbes(reflectVector, positionWS, perceptualRoughness, normalizedScreenSpaceUV);
}
else
{
if (_REFLECTION_PROBE_BOX_PROJECTION)
{
#if defined(REFLECTION_PROBE_ROTATION)
float3 probeCenterPosWS0 = unity_SpecCube0_BoxMin.xyz + (unity_SpecCube0_BoxMax.xyz - unity_SpecCube0_BoxMin.xyz) / 2;
float3 rotPosWS0 = RotateVectorByQuat(unity_SpecCube0_Rotation, positionWS - probeCenterPosWS0) + probeCenterPosWS0;
half3 rotReflectVector0 = RotateVectorByQuat(unity_SpecCube0_Rotation, reflectVector);
float4 inverseRotation0 = -unity_SpecCube0_Rotation;
inverseRotation0.w = -inverseRotation0.w;
reflectVector = BoxProjectedCubemapDirection(rotReflectVector0, rotPosWS0, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
reflectVector = RotateVectorByQuat(inverseRotation0, reflectVector);
#else
reflectVector = BoxProjectedCubemapDirection(reflectVector, positionWS, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
#endif
}
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
}
#else // _ENVIRONMENTREFLECTIONS_OFF
irradiance = _GlossyEnvironmentColor.rgb;
#endif // !_ENVIRONMENTREFLECTIONS_OFF
}
irradiance = lerp(irradiance.rgb, ssrColor.rgb, ssrColor.a);
return irradiance * occlusion;
}
#if !USE_CLUSTER_LIGHT_LOOP
half3 GlossyEnvironmentReflection(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion)
{
return GlossyEnvironmentReflection(reflectVector, positionWS, perceptualRoughness, occlusion, float2(0.0f, 0.0f));
}
#endif
half3 GlossyEnvironmentReflection(half3 reflectVector, half perceptualRoughness, half occlusion)
{
#if !defined(_ENVIRONMENTREFLECTIONS_OFF)
half3 irradiance;
half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
return irradiance * occlusion;
#else
return _GlossyEnvironmentColor.rgb * occlusion;
#endif // _ENVIRONMENTREFLECTIONS_OFF
}
half3 SubtractDirectMainLightFromLightmap(Light mainLight, half3 normalWS, half3 bakedGI)
{
// Let's try to make realtime shadows work on a surface, which already contains
// baked lighting and shadowing from the main sun light.
// Summary:
// 1) Calculate possible value in the shadow by subtracting estimated light contribution from the places occluded by realtime shadow:
// a) preserves other baked lights and light bounces
// b) eliminates shadows on the geometry facing away from the light
// 2) Clamp against user defined ShadowColor.
// 3) Pick original lightmap value, if it is the darkest one.
// 1) Gives good estimate of illumination as if light would've been shadowed during the bake.
// We only subtract the main direction light. This is accounted in the contribution term below.
half shadowStrength = GetMainLightShadowStrength();
half contributionTerm = saturate(dot(mainLight.direction, normalWS));
half3 lambert = mainLight.color * contributionTerm;
half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - mainLight.shadowAttenuation);
half3 subtractedLightmap = bakedGI - estimatedLightContributionMaskedByInverseOfShadow;
// 2) Allows user to define overall ambient of the scene and control situation when realtime shadow becomes too dark.
half3 realtimeShadow = max(subtractedLightmap, _SubtractiveShadowColor.xyz);
realtimeShadow = lerp(bakedGI, realtimeShadow, shadowStrength);
// 3) Pick darkest color
return min(bakedGI, realtimeShadow);
}
half3 GlobalIllumination(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
half3 bakedGI, half occlusion, float3 positionWS,
half3 normalWS, half3 viewDirectionWS, float2 normalizedScreenSpaceUV)
{
// Prevent calling 'reflect' from causing NdotV to be computed twice on Adreno GPUs
#if (UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
half NdotV = dot(normalWS, viewDirectionWS);
half NdotV2 = NdotV + NdotV; // 2.0h * normalWS * NdotV was resulting in promotion to 32 bit precision
half3 reflectVector = normalWS * NdotV2 - viewDirectionWS; // reflect(i,n) = i - 2 * n * dot(i n)
// reflect(-viewDirection, normalWS) = -viewDirection - 2 * normalWS * dot(-viewDirection, normalWS)
// = -viewDirection + 2 * normalWS * dot(viewDirection, normalWS)
// = 2 * normalWS * dot(viewDirection, normalWS) - viewDirection
half NoV = saturate(NdotV);
#else
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
half NoV = saturate(dot(normalWS, viewDirectionWS));
#endif
half fresnelTerm = Pow4(1.0 - NoV);
half3 indirectDiffuse = bakedGI;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, positionWS, brdfData.perceptualRoughness, 1.0h, normalizedScreenSpaceUV);
half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
if (IsOnlyAOLightingFeatureEnabled())
{
color = half3(1,1,1); // "Base white" for AO debug lighting mode
}
#if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
half3 coatIndirectSpecular = GlossyEnvironmentReflection(reflectVector, positionWS, brdfDataClearCoat.perceptualRoughness, 1.0h, normalizedScreenSpaceUV);
// TODO: "grazing term" causes problems on full roughness
half3 coatColor = EnvironmentBRDFClearCoat(brdfDataClearCoat, clearCoatMask, coatIndirectSpecular, fresnelTerm);
// Blend with base layer using khronos glTF recommended way using NoV
// Smooth surface & "ambiguous" lighting
// NOTE: fresnelTerm (above) is pow4 instead of pow5, but should be ok as blend weight.
half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * fresnelTerm;
return (color * (1.0 - coatFresnel * clearCoatMask) + coatColor) * occlusion;
#else
return color * occlusion;
#endif
}
#if !USE_CLUSTER_LIGHT_LOOP
half3 GlobalIllumination(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
half3 bakedGI, half occlusion, float3 positionWS,
half3 normalWS, half3 viewDirectionWS)
{
return GlobalIllumination(brdfData, brdfDataClearCoat, clearCoatMask, bakedGI, occlusion, positionWS, normalWS, viewDirectionWS, float2(0.0f, 0.0f));
}
#endif
// Backwards compatiblity
half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, float3 positionWS, half3 normalWS, half3 viewDirectionWS)
{
const BRDFData noClearCoat = (BRDFData)0;
return GlobalIllumination(brdfData, noClearCoat, 0.0, bakedGI, occlusion, positionWS, normalWS, viewDirectionWS, 0);
}
half3 GlobalIllumination(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
half3 bakedGI, half occlusion,
half3 normalWS, half3 viewDirectionWS)
{
// Prevent calling 'reflect' from causing NdotV to be computed twice on Adreno GPUs
#if (UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
half NdotV = dot(normalWS, viewDirectionWS);
half NdotV2 = NdotV + NdotV; // 2.0h * normalWS * NdotV was resulting in promotion to 32 bit precision
half3 reflectVector = normalWS * NdotV2 - viewDirectionWS; // reflect(i,n) = i - 2 * n * dot(i n)
// reflect(-viewDirection, normalWS) = -viewDirection - 2 * normalWS * dot(-viewDirection, normalWS)
// = -viewDirection + 2 * normalWS * dot(viewDirection, normalWS)
// = 2 * normalWS * dot(viewDirection, normalWS) - viewDirection
half NoV = saturate(NdotV);
#else
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
half NoV = saturate(dot(normalWS, viewDirectionWS));
#endif
half fresnelTerm = Pow4(1.0 - NoV);
half3 indirectDiffuse = bakedGI;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, half(1.0));
half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
#if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
half3 coatIndirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfDataClearCoat.perceptualRoughness, half(1.0));
// TODO: "grazing term" causes problems on full roughness
half3 coatColor = EnvironmentBRDFClearCoat(brdfDataClearCoat, clearCoatMask, coatIndirectSpecular, fresnelTerm);
// Blend with base layer using khronos glTF recommended way using NoV
// Smooth surface & "ambiguous" lighting
// NOTE: fresnelTerm (above) is pow4 instead of pow5, but should be ok as blend weight.
half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * fresnelTerm;
return (color * (1.0 - coatFresnel * clearCoatMask) + coatColor) * occlusion;
#else
return color * occlusion;
#endif
}
half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS)
{
const BRDFData noClearCoat = (BRDFData)0;
return GlobalIllumination(brdfData, noClearCoat, 0.0, bakedGI, occlusion, normalWS, viewDirectionWS);
}
void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI)
{
#if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
bakedGI = SubtractDirectMainLightFromLightmap(light, normalWS, bakedGI);
#endif
}
// Backwards compatibility
void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, half4 shadowMask)
{
MixRealtimeAndBakedGI(light, normalWS, bakedGI);
}
void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, AmbientOcclusionFactor aoFactor)
{
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
{
bakedGI *= aoFactor.indirectAmbientOcclusion;
}
MixRealtimeAndBakedGI(light, normalWS, bakedGI);
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1be91b057dbe43239a838d9e45a42a32
timeCreated: 1615474164
@@ -0,0 +1,248 @@
#ifndef UNIVERSAL_INPUT_INCLUDED
#define UNIVERSAL_INPUT_INCLUDED
// URP package specific shader input variables and defines.
// Unity Engine specific built-in shader input variables are defined in .universal/ShaderLibrary/UnityInput.hlsl
#include "Packages/com.unity.render-pipelines.universal-config/Runtime/ShaderConfig.cs.hlsl"
#define MAX_VISIBLE_LIGHTS_UBO 32
#define MAX_VISIBLE_LIGHTS_SSBO 256
// Keep in sync with RenderingUtils.useStructuredBuffer
#define USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA 0
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderTypes.cs.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Deprecated.hlsl"
// Must match: UniversalRenderPipeline.maxVisibleAdditionalLights
#if defined(SHADER_API_MOBILE) && defined(SHADER_API_GLES30)
#define MAX_VISIBLE_LIGHTS MAX_VISIBLE_LIGHT_COUNT_LOW_END_MOBILE
// WebGPU's minimal limits are based on mobile rather than desktop, so it will need to assume mobile.
#elif defined(SHADER_API_MOBILE) || (defined(SHADER_API_GLCORE) && !defined(SHADER_API_SWITCH) && !defined(SHADER_API_SWITCH2)) || defined(SHADER_API_GLES3) || defined(SHADER_API_WEBGPU) // Workaround because SHADER_API_GLCORE is also defined when SHADER_API_SWITCH is
#define MAX_VISIBLE_LIGHTS MAX_VISIBLE_LIGHT_COUNT_MOBILE
#else
#define MAX_VISIBLE_LIGHTS MAX_VISIBLE_LIGHT_COUNT_DESKTOP
#endif
// Match with values in UniversalRenderPipeline.cs
#define MAX_ZBIN_VEC4S 1024
#if MAX_VISIBLE_LIGHTS <= 16
#define MAX_LIGHTS_PER_TILE 32
#define MAX_TILE_VEC4S 1024
#define MAX_REFLECTION_PROBES 16
#elif MAX_VISIBLE_LIGHTS <= 32
#define MAX_LIGHTS_PER_TILE 32
#define MAX_TILE_VEC4S 1024
#define MAX_REFLECTION_PROBES 32
#else
#define MAX_LIGHTS_PER_TILE MAX_VISIBLE_LIGHTS
#define MAX_TILE_VEC4S 4096
#define MAX_REFLECTION_PROBES 64
#endif
struct InputData
{
float3 positionWS;
float4 positionCS;
float3 normalWS;
half3 viewDirectionWS;
float4 shadowCoord;
half fogCoord;
half3 vertexLighting;
half3 bakedGI;
float2 normalizedScreenSpaceUV;
half4 shadowMask;
half3x3 tangentToWorld;
#if defined(DEBUG_DISPLAY)
half2 dynamicLightmapUV;
half2 staticLightmapUV;
float3 vertexSH;
half3 brdfDiffuse;
half3 brdfSpecular;
// Mipmap Streaming Debug
float2 uv;
uint mipCount;
// texelSize :
// x = 1 / width
// y = 1 / height
// z = width
// w = height
float4 texelSize;
// mipInfo :
// x = quality settings minStreamingMipLevel
// y = original mip count for texture
// z = desired on screen mip level
// w = loaded mip level
float4 mipInfo;
// streamInfo :
// x = streaming priority
// y = time stamp of the latest texture upload
// z = streaming status
// w = 0
float4 streamInfo;
float3 originalColor;
float4 probeOcclusion;
#endif
};
///////////////////////////////////////////////////////////////////////////////
// Constant Buffers //
///////////////////////////////////////////////////////////////////////////////
half4 _GlossyEnvironmentColor;
half4 _SubtractiveShadowColor;
half4 _GlossyEnvironmentCubeMap_HDR;
TEXTURECUBE(_GlossyEnvironmentCubeMap);
SAMPLER(sampler_GlossyEnvironmentCubeMap);
#define _InvCameraViewProj unity_MatrixInvVP
float4 _ScaledScreenParams;
// x = Mip Bias
// y = 2.0 ^ [Mip Bias]
float2 _GlobalMipBias;
// 1.0 if it's possible for AlphaToMask to be enabled for this draw and 0.0 otherwise
float _AlphaToMaskAvailable;
float4 _MainLightPosition;
// In Forward+, .a stores whether the main light is using subtractive mixed mode.
half4 _MainLightColor;
half4 _MainLightOcclusionProbes;
uint _MainLightLayerMask;
// x: SSAO Enabled/Disabled (Needed for situations when OFF keyword is stripped out but feature disabled in runtime)
// yz are currently unused
// w: directLightStrength
half4 _AmbientOcclusionParam;
// x: SSR Enabled/Disabled (Needed for situations when OFF keyword is stripped out but feature disabled in runtime)
// y: Minimum smoothness, used as a mask for SSR.
// z: Smoothness fade start.
// w: is currently unused
half4 _ScreenSpaceReflectionParam;
half4 _AdditionalLightsCount;
uint _RenderingLayerMaxInt;
// Screen coord override.
float4 _ScreenCoordScaleBias;
float4 _ScreenSizeOverride;
uint _EnableProbeVolumes;
#if USE_CLUSTER_LIGHT_LOOP
float4 _FPParams0;
float4 _FPParams1;
float4 _FPParams2;
#define URP_FP_ZBIN_SCALE (_FPParams0.x)
#define URP_FP_ZBIN_OFFSET (_FPParams0.y)
#define URP_FP_PROBES_BEGIN ((uint)_FPParams0.z)
// Directional lights would be in all clusters, so they don't go into the cluster structure.
// Instead, they are stored first in the light buffer.
#define URP_FP_DIRECTIONAL_LIGHTS_COUNT ((uint)_FPParams0.w)
// Scale from screen-space UV [0, 1] to tile coordinates [0, tile resolution].
#define URP_FP_TILE_SCALE ((float2)_FPParams1.xy)
#define URP_FP_TILE_COUNT_X ((uint)_FPParams1.z)
#define URP_FP_WORDS_PER_TILE ((uint)_FPParams1.w)
#define URP_FP_ZBIN_COUNT ((uint)_FPParams2.x)
#define URP_FP_TILE_COUNT ((uint)_FPParams2.y)
#endif
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
StructuredBuffer<LightData> _AdditionalLightsBuffer;
StructuredBuffer<int> _AdditionalLightsIndices;
#else
// GLES3 causes a performance regression in some devices when using CBUFFER.
#ifndef LIGHT_SHADOWS_NO_CBUFFER
CBUFFER_START(AdditionalLights)
#endif
float4 _AdditionalLightsPosition[MAX_VISIBLE_LIGHTS];
// In Forward+, .a stores whether the light is using subtractive mixed mode.
float4 _AdditionalLightsColor[MAX_VISIBLE_LIGHTS];
float4 _AdditionalLightsAttenuation[MAX_VISIBLE_LIGHTS];
float4 _AdditionalLightsSpotDir[MAX_VISIBLE_LIGHTS];
float4 _AdditionalLightsOcclusionProbes[MAX_VISIBLE_LIGHTS];
#ifndef LIGHT_SHADOWS_NO_CBUFFER
CBUFFER_END
#endif
// Keeping mask buffer outside of AdditionalLights due to padding issue (std140 vs Metal MSL)
// We want uint[] but the Unity API does not support it.
float _AdditionalLightsLayerMasks[MAX_VISIBLE_LIGHTS];
#endif
#if USE_CLUSTER_LIGHT_LOOP
CBUFFER_START(urp_ZBinBuffer)
float4 urp_ZBins[MAX_ZBIN_VEC4S];
CBUFFER_END
CBUFFER_START(urp_TileBuffer)
float4 urp_Tiles[MAX_TILE_VEC4S];
CBUFFER_END
TEXTURE2D(urp_ReflProbes_Atlas);
float urp_ReflProbes_Count;
// 2023.3 Deprecated. This is for backwards compatibility. Remove in the future.
#define samplerurp_ReflProbes_Atlas sampler_LinearClamp
#ifndef LIGHT_SHADOWS_NO_CBUFFER
CBUFFER_START(urp_ReflectionProbeBuffer)
#endif
float4 urp_ReflProbes_BoxMax[MAX_REFLECTION_PROBES]; // w contains the blend distance
float4 urp_ReflProbes_BoxMin[MAX_REFLECTION_PROBES]; // w contains the importance
float4 urp_ReflProbes_ProbePosition[MAX_REFLECTION_PROBES]; // w is positive for box projection, |w| is max mip level
float4 urp_ReflProbes_MipScaleOffset[MAX_REFLECTION_PROBES * 7];
float4 urp_ReflProbes_Rotation[MAX_REFLECTION_PROBES];
#ifndef LIGHT_SHADOWS_NO_CBUFFER
CBUFFER_END
#endif
#endif
#define UNITY_MATRIX_M unity_ObjectToWorld
#define UNITY_MATRIX_I_M unity_WorldToObject
#define UNITY_MATRIX_V unity_MatrixV
#define UNITY_MATRIX_I_V unity_MatrixInvV
#define UNITY_MATRIX_P OptimizeProjectionMatrix(glstate_matrix_projection)
#define UNITY_MATRIX_I_P unity_MatrixInvP
#define UNITY_MATRIX_VP unity_MatrixVP
#define UNITY_MATRIX_I_VP unity_MatrixInvVP
#define UNITY_MATRIX_MV mul(UNITY_MATRIX_V, UNITY_MATRIX_M)
#define UNITY_MATRIX_T_MV transpose(UNITY_MATRIX_MV)
#define UNITY_MATRIX_IT_MV transpose(mul(UNITY_MATRIX_I_M, UNITY_MATRIX_I_V))
#define UNITY_MATRIX_MVP mul(UNITY_MATRIX_VP, UNITY_MATRIX_M)
#define UNITY_PREV_MATRIX_M unity_MatrixPreviousM
#define UNITY_PREV_MATRIX_I_M unity_MatrixPreviousMI
// Note: #include order is important here.
// UnityInput.hlsl must be included before UnityInstancing.hlsl, so constant buffer
// declarations don't fail because of instancing macros.
// UniversalDOTSInstancing.hlsl must be included after UnityInstancing.hlsl
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl"
// VFX may also redefine UNITY_MATRIX_M / UNITY_MATRIX_I_M as static per-particle global matrices.
#ifdef HAVE_VFX_MODIFICATION
#include "Packages/com.unity.visualeffectgraph/Shaders/VFXMatricesOverride.hlsl"
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: b2555155ead696140913bef1ec93adf0
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
#ifndef UNIVERSAL_PIPELINE_LODCROSSFADE_INCLUDED
#define UNIVERSAL_PIPELINE_LODCROSSFADE_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl"
float _DitheringTextureInvSize;
TEXTURE2D(_DitheringTexture);
half CopySign(half x, half s)
{
return (s >= 0) ? abs(x) : -abs(x);
}
void LODFadeCrossFade(float4 positionCS)
{
half2 uv = positionCS.xy * _DitheringTextureInvSize;
half d = SAMPLE_TEXTURE2D(_DitheringTexture, sampler_PointRepeat, uv).a;
d = unity_LODFade.x - CopySign(d, unity_LODFade.x);
clip(d);
}
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ef46fb1e00bf67142ae3548411a562b6
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a648b46fb6b4749f589f22d9ef6e441a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,117 @@
#ifndef UNIVERSAL_LIGHT_COOKIE_INCLUDED
#define UNIVERSAL_LIGHT_COOKIE_INCLUDED
// Includes
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookieInput.hlsl"
#if defined(_LIGHT_COOKIES)
#ifndef REQUIRES_WORLD_SPACE_POS_INTERPOLATOR
#define REQUIRES_WORLD_SPACE_POS_INTERPOLATOR 1
#endif
#endif
float2 ComputeLightCookieUVDirectional(float4x4 worldToLight, float3 samplePositionWS, float4 atlasUVRect, uint2 uvWrap)
{
// Translate and rotate 'positionWS' into the light space.
// Project point to light "view" plane, i.e. discard Z.
float2 positionLS = mul(worldToLight, float4(samplePositionWS, 1)).xy;
// Remap [-1, 1] to [0, 1]
// (implies the transform has ortho projection mapping world space box to [-1, 1])
float2 positionUV = positionLS * 0.5 + 0.5;
// Tile texture for cookie in repeat mode
positionUV.x = (uvWrap.x == URP_TEXTURE_WRAP_MODE_REPEAT) ? frac(positionUV.x) : positionUV.x;
positionUV.y = (uvWrap.y == URP_TEXTURE_WRAP_MODE_REPEAT) ? frac(positionUV.y) : positionUV.y;
positionUV.x = (uvWrap.x == URP_TEXTURE_WRAP_MODE_CLAMP) ? saturate(positionUV.x) : positionUV.x;
positionUV.y = (uvWrap.y == URP_TEXTURE_WRAP_MODE_CLAMP) ? saturate(positionUV.y) : positionUV.y;
// Remap to atlas texture
float2 positionAtlasUV = atlasUVRect.xy * float2(positionUV) + atlasUVRect.zw;
return positionAtlasUV;
}
float2 ComputeLightCookieUVSpot(float4x4 worldToLightPerspective, float3 samplePositionWS, float4 atlasUVRect)
{
// Translate, rotate and project 'positionWS' into the light clip space.
float4 positionCS = mul(worldToLightPerspective, float4(samplePositionWS, 1));
float2 positionNDC = positionCS.xy / positionCS.w;
// Remap NDC to the texture coordinates, from NDC [-1, 1]^2 to [0, 1]^2.
float2 positionUV = saturate(positionNDC * 0.5 + 0.5);
// Remap into rect in the atlas texture
float2 positionAtlasUV = atlasUVRect.xy * float2(positionUV) + atlasUVRect.zw;
return positionAtlasUV;
}
float2 ComputeLightCookieUVPoint(float4x4 worldToLight, float3 samplePositionWS, float4 atlasUVRect)
{
// Translate and rotate 'positionWS' into the light space.
float4 positionLS = mul(worldToLight, float4(samplePositionWS, 1));
float3 sampleDirLS = normalize(positionLS.xyz / positionLS.w);
// Project direction to Octahederal quad UV.
float2 positionUV = saturate(PackNormalOctQuadEncode(sampleDirLS) * 0.5 + 0.5);
// Remap to atlas texture
float2 positionAtlasUV = atlasUVRect.xy * float2(positionUV) + atlasUVRect.zw;
return positionAtlasUV;
}
real3 SampleMainLightCookie(float3 samplePositionWS)
{
if(!IsMainLightCookieEnabled())
return real3(1,1,1);
float2 uv = ComputeLightCookieUVDirectional(_MainLightWorldToLight, samplePositionWS, float4(1, 1, 0, 0), URP_TEXTURE_WRAP_MODE_NONE);
real4 color = SampleMainLightCookieTexture(uv);
return IsMainLightCookieTextureRGBFormat() ? color.rgb
: IsMainLightCookieTextureAlphaFormat() ? color.aaa
: color.rrr;
}
real3 SampleAdditionalLightCookie(int perObjectLightIndex, float3 samplePositionWS)
{
if(!IsLightCookieEnabled(perObjectLightIndex))
return real3(1,1,1);
int lightType = GetLightCookieLightType(perObjectLightIndex);
int isSpot = lightType == URP_LIGHT_TYPE_SPOT;
int isDirectional = lightType == URP_LIGHT_TYPE_DIRECTIONAL;
float4x4 worldToLight = GetLightCookieWorldToLightMatrix(perObjectLightIndex);
float4 uvRect = GetLightCookieAtlasUVRect(perObjectLightIndex);
float2 uv;
if(isSpot)
{
uv = ComputeLightCookieUVSpot(worldToLight, samplePositionWS, uvRect);
}
else if(isDirectional)
{
uv = ComputeLightCookieUVDirectional(worldToLight, samplePositionWS, uvRect, URP_TEXTURE_WRAP_MODE_REPEAT);
}
else
{
uv = ComputeLightCookieUVPoint(worldToLight, samplePositionWS, uvRect);
}
real4 color = SampleAdditionalLightsCookieAtlasTexture(uv);
return IsAdditionalLightsCookieAtlasTextureRGBFormat() ? color.rgb
: IsAdditionalLightsCookieAtlasTextureAlphaFormat() ? color.aaa
: color.rrr;
}
#endif //UNIVERSAL_LIGHT_COOKIE_INCLUDED
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8878828335bd847b493e10211fcbf825
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,132 @@
#ifndef UNIVERSAL_LIGHT_COOKIE_INPUT_INCLUDED
#define UNIVERSAL_LIGHT_COOKIE_INPUT_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookieTypes.hlsl"
// Textures
TEXTURE2D(_MainLightCookieTexture);
TEXTURE2D(_AdditionalLightsCookieAtlasTexture);
// Samplers
SAMPLER(sampler_MainLightCookieTexture);
// Buffers
#if !USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
// GLES3 causes a performance regression in some devices when using CBUFFER.
#ifndef LIGHT_SHADOWS_NO_CBUFFER
CBUFFER_START(LightCookies)
#endif
float4x4 _AdditionalLightsWorldToLights[MAX_VISIBLE_LIGHTS];
float4 _AdditionalLightsCookieAtlasUVRects[MAX_VISIBLE_LIGHTS]; // (xy: uv size, zw: uv offset)
#ifndef LIGHT_SHADOWS_NO_CBUFFER
CBUFFER_END
#endif
#endif
float4x4 _MainLightWorldToLight;
float _MainLightCookieTextureFormat;
float _AdditionalLightsCookieAtlasTextureFormat;
// Cannot be included in the CBUFFER, float[] arrays padding differs between std140 (CBUFFER)
// and Metal MSL when packed alongside float4/float4x4 arrays.
float _AdditionalLightsCookieEnableBits[(MAX_VISIBLE_LIGHTS + 31) / 32];
#if !USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
float _AdditionalLightsLightTypes[MAX_VISIBLE_LIGHTS];
#endif
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
StructuredBuffer<float4x4> _AdditionalLightsWorldToLightBuffer;
StructuredBuffer<float4> _AdditionalLightsCookieAtlasUVRectBuffer; // UV rect into light cookie atlas (xy: uv offset, zw: uv size)
StructuredBuffer<float> _AdditionalLightsLightTypeBuffer;
#endif
// Data Getters
float4x4 GetLightCookieWorldToLightMatrix(int lightIndex)
{
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
return _AdditionalLightsWorldToLightBuffer[lightIndex];
#else
return _AdditionalLightsWorldToLights[lightIndex];
#endif
}
float4 GetLightCookieAtlasUVRect(int lightIndex)
{
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
return _AdditionalLightsCookieAtlasUVRectBuffer[lightIndex];
#else
return _AdditionalLightsCookieAtlasUVRects[lightIndex];
#endif
}
int GetLightCookieLightType(int lightIndex)
{
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
return _AdditionalLightsLightTypeBuffer[lightIndex];
#else
return _AdditionalLightsLightTypes[lightIndex];
#endif
}
bool IsMainLightCookieTextureRGBFormat()
{
return _MainLightCookieTextureFormat == URP_LIGHT_COOKIE_FORMAT_RGB;
}
bool IsMainLightCookieTextureAlphaFormat()
{
return _MainLightCookieTextureFormat == URP_LIGHT_COOKIE_FORMAT_ALPHA;
}
bool IsAdditionalLightsCookieAtlasTextureRGBFormat()
{
return _AdditionalLightsCookieAtlasTextureFormat == URP_LIGHT_COOKIE_FORMAT_RGB;
}
bool IsAdditionalLightsCookieAtlasTextureAlphaFormat()
{
return _AdditionalLightsCookieAtlasTextureFormat == URP_LIGHT_COOKIE_FORMAT_ALPHA;
}
// Sampling
real4 SampleMainLightCookieTexture(float2 uv)
{
return SAMPLE_TEXTURE2D(_MainLightCookieTexture, sampler_MainLightCookieTexture, uv);
}
real4 SampleAdditionalLightsCookieAtlasTexture(float2 uv)
{
// No mipmap support
return SAMPLE_TEXTURE2D_LOD(_AdditionalLightsCookieAtlasTexture, sampler_LinearClamp, uv, 0);
}
// Helpers
bool IsMainLightCookieEnabled()
{
return _MainLightCookieTextureFormat != URP_LIGHT_COOKIE_FORMAT_NONE;
}
bool IsLightCookieEnabled(int lightBufferIndex)
{
#if 0
float4 uvRect = GetLightCookieAtlasUVRect(lightBufferIndex);
return any(uvRect != 0);
#else
// 2^5 == 32, bit mask for a float/uint.
uint elemIndex = ((uint)lightBufferIndex) >> 5;
uint bitOffset = (uint)lightBufferIndex & ((1 << 5) - 1);
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
uint elem = asuint(_AdditionalLightsCookieEnableBitsBuffer[elemIndex]);
#else
uint elem = asuint(_AdditionalLightsCookieEnableBits[elemIndex]);
#endif
return (elem & (1u << bitOffset)) != 0u;
#endif
}
#endif //UNIVERSAL_LIGHT_COOKIE_INPUT_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a70b6c101edaa442a80370b0d514fb3c
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
#ifndef UNIVERSAL_LIGHT_COOKIE_TYPES_INCLUDED
#define UNIVERSAL_LIGHT_COOKIE_TYPES_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityTypes.hlsl"
// Types
#define URP_LIGHT_COOKIE_FORMAT_NONE (-1)
#define URP_LIGHT_COOKIE_FORMAT_RGB (0)
#define URP_LIGHT_COOKIE_FORMAT_ALPHA (1)
#define URP_LIGHT_COOKIE_FORMAT_RED (2)
#endif //UNIVERSAL_LIGHT_COOKIE_TYPES_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 394c5e9a352f74e998cb797d7aa461d4
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,559 @@
#ifndef UNIVERSAL_LIGHTING_INCLUDED
#define UNIVERSAL_LIGHTING_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/Debugging3D.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GlobalIllumination.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
#if defined(LIGHTMAP_ON)
#define DECLARE_LIGHTMAP_OR_SH(lmName, shName, index) float2 lmName : TEXCOORD##index
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT) OUT.xy = lightmapUV.xy * lightmapScaleOffset.xy + lightmapScaleOffset.zw;
#define OUTPUT_SH4(absolutePositionWS, normalWS, viewDir, OUT, OUT_OCCLUSION)
#define OUTPUT_SH(normalWS, OUT)
#else
#define DECLARE_LIGHTMAP_OR_SH(lmName, shName, index) half3 shName : TEXCOORD##index
#define OUTPUT_LIGHTMAP_UV(lightmapUV, lightmapScaleOffset, OUT)
#ifdef USE_APV_PROBE_OCCLUSION
#define OUTPUT_SH4(absolutePositionWS, normalWS, viewDir, OUT, OUT_OCCLUSION) OUT.xyz = SampleProbeSHVertex(absolutePositionWS, normalWS, viewDir, OUT_OCCLUSION)
#else
#define OUTPUT_SH4(absolutePositionWS, normalWS, viewDir, OUT, OUT_OCCLUSION) OUT.xyz = SampleProbeSHVertex(absolutePositionWS, normalWS, viewDir)
#endif
// Note: This is the legacy function, which does not support APV.
// Kept to avoid breaking shaders still calling it (UUM-37723)
#define OUTPUT_SH(normalWS, OUT) OUT.xyz = SampleSHVertex(normalWS)
#endif
///////////////////////////////////////////////////////////////////////////////
// Lighting Functions //
///////////////////////////////////////////////////////////////////////////////
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
{
half NdotL = saturate(dot(normal, lightDir));
return lightColor * NdotL;
}
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specular, half smoothness)
{
float3 halfVec = SafeNormalize(float3(lightDir) + float3(viewDir));
half NdotH = half(saturate(dot(normal, halfVec)));
half modifier = pow(float(NdotH), float(smoothness)); // Half produces banding, need full precision
// NOTE: In order to fix internal compiler error on mobile platforms, this needs to be float3
float3 specularReflection = specular.rgb * modifier;
return lightColor * specularReflection;
}
half3 LightingPhysicallyBased(BRDFData brdfData, BRDFData brdfDataClearCoat,
half3 lightColor, half3 lightDirectionWS, float lightAttenuation,
half3 normalWS, half3 viewDirectionWS,
half clearCoatMask, bool specularHighlightsOff)
{
#if (UNITY_PLATFORM_META_QUEST)
half NdotL = dot(normalWS, lightDirectionWS);
#else
half NdotL = saturate(dot(normalWS, lightDirectionWS));
#endif
#if (UNITY_PLATFORM_META_QUEST)
[branch]
if (NdotL > 0.0)
{
half3 radiance = lightColor * (lightAttenuation * saturate(NdotL));
#else
half3 radiance = lightColor * (lightAttenuation * NdotL);
#endif
half3 brdf = brdfData.diffuse;
#ifndef _SPECULARHIGHLIGHTS_OFF
[branch]
if (!specularHighlightsOff)
{
brdf += brdfData.specular * DirectBRDFSpecular(brdfData, normalWS, lightDirectionWS, viewDirectionWS);
#if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
// Clear coat evaluates the specular a second time and has some common terms with the base specular.
// We rely on the compiler to merge these and compute them only once.
half brdfCoat = kDielectricSpec.r * DirectBRDFSpecular(brdfDataClearCoat, normalWS, lightDirectionWS, viewDirectionWS);
// Mix clear coat and base layer using khronos glTF recommended formula
// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md
// Use NoV for direct too instead of LoH as an optimization (NoV is light invariant).
half NoV = saturate(dot(normalWS, viewDirectionWS));
// Use slightly simpler fresnelTerm (Pow4 vs Pow5) as a small optimization.
// It is matching fresnel used in the GI/Env, so should produce a consistent clear coat blend (env vs. direct)
half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * Pow4(1.0 - NoV);
brdf = brdf * (1.0 - clearCoatMask * coatFresnel) + brdfCoat * clearCoatMask;
#endif // _CLEARCOAT
}
#endif // _SPECULARHIGHLIGHTS_OFF
return brdf * radiance;
#if (UNITY_PLATFORM_META_QUEST)
}
#endif
return 0.0;
}
half3 LightingPhysicallyBased(BRDFData brdfData, BRDFData brdfDataClearCoat, Light light, half3 normalWS, half3 viewDirectionWS, half clearCoatMask, bool specularHighlightsOff)
{
return LightingPhysicallyBased(brdfData, brdfDataClearCoat, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, clearCoatMask, specularHighlightsOff);
}
// Backwards compatibility
half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS)
{
#ifdef _SPECULARHIGHLIGHTS_OFF
bool specularHighlightsOff = true;
#else
bool specularHighlightsOff = false;
#endif
const BRDFData noClearCoat = (BRDFData)0;
return LightingPhysicallyBased(brdfData, noClearCoat, light, normalWS, viewDirectionWS, 0.0, specularHighlightsOff);
}
half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, float lightAttenuation, half3 normalWS, half3 viewDirectionWS)
{
Light light;
light.color = lightColor;
light.direction = lightDirectionWS;
light.distanceAttenuation = lightAttenuation;
light.shadowAttenuation = 1;
return LightingPhysicallyBased(brdfData, light, normalWS, viewDirectionWS);
}
half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS, bool specularHighlightsOff)
{
const BRDFData noClearCoat = (BRDFData)0;
return LightingPhysicallyBased(brdfData, noClearCoat, light, normalWS, viewDirectionWS, 0.0, specularHighlightsOff);
}
half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, float lightAttenuation, half3 normalWS, half3 viewDirectionWS, bool specularHighlightsOff)
{
Light light;
light.color = lightColor;
light.direction = lightDirectionWS;
light.distanceAttenuation = lightAttenuation;
light.shadowAttenuation = 1;
return LightingPhysicallyBased(brdfData, light, viewDirectionWS, specularHighlightsOff, specularHighlightsOff);
}
half3 VertexLighting(float3 positionWS, half3 normalWS)
{
half3 vertexLightColor = half3(0.0, 0.0, 0.0);
#ifdef _ADDITIONAL_LIGHTS_VERTEX
uint lightsCount = GetAdditionalLightsCount();
uint meshRenderingLayers = GetMeshRenderingLayer();
LIGHT_LOOP_BEGIN(lightsCount)
Light light = GetAdditionalLight(lightIndex, positionWS);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
#if defined(UNITY_PLATFORM_META_QUEST)
if(light.distanceAttenuation > 0.0)
#endif
{
half3 lightColor = light.color * light.distanceAttenuation;
vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);
}
}
LIGHT_LOOP_END
#endif
return vertexLightColor;
}
struct LightingData
{
half3 giColor;
half3 mainLightColor;
half3 additionalLightsColor;
half3 vertexLightingColor;
half3 emissionColor;
};
half3 CalculateLightingColor(LightingData lightingData, half3 albedo)
{
half3 lightingColor = 0;
if (IsOnlyAOLightingFeatureEnabled())
{
return lightingData.giColor; // Contains white + AO
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_GLOBAL_ILLUMINATION))
{
lightingColor += lightingData.giColor;
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_MAIN_LIGHT))
{
lightingColor += lightingData.mainLightColor;
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_ADDITIONAL_LIGHTS))
{
lightingColor += lightingData.additionalLightsColor;
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_VERTEX_LIGHTING))
{
lightingColor += lightingData.vertexLightingColor;
}
lightingColor *= albedo;
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_EMISSION))
{
lightingColor += lightingData.emissionColor;
}
return lightingColor;
}
half4 CalculateFinalColor(LightingData lightingData, half alpha)
{
half3 finalColor = CalculateLightingColor(lightingData, 1);
return half4(finalColor, alpha);
}
half4 CalculateFinalColor(LightingData lightingData, half3 albedo, half alpha, float fogCoord)
{
half fogFactor = 0;
#if defined(_FOG_FRAGMENT)
bool anyFogEnabled = false;
#if defined(FOG_LINEAR_KEYWORD_DECLARED)
if (FOG_LINEAR)
anyFogEnabled = true;
#endif
#if defined(FOG_EXP_KEYWORD_DECLARED)
if (FOG_EXP)
anyFogEnabled = true;
#endif
#if defined(FOG_EXP2_KEYWORD_DECLARED)
if (FOG_EXP2)
anyFogEnabled = true;
#endif
if (anyFogEnabled)
{
float viewZ = -fogCoord;
float nearToFarZ = max(viewZ - _ProjectionParams.y, 0);
fogFactor = ComputeFogFactorZ0ToFar(nearToFarZ);
}
#else // #if defined(_FOG_FRAGMENT)
fogFactor = fogCoord;
#endif // #if defined(_FOG_FRAGMENT)
half3 lightingColor = CalculateLightingColor(lightingData, albedo);
half3 finalColor = MixFog(lightingColor, fogFactor);
return half4(finalColor, alpha);
}
LightingData CreateLightingData(InputData inputData, SurfaceData surfaceData)
{
LightingData lightingData;
lightingData.giColor = inputData.bakedGI;
lightingData.emissionColor = surfaceData.emission;
lightingData.vertexLightingColor = 0;
lightingData.mainLightColor = 0;
lightingData.additionalLightsColor = 0;
return lightingData;
}
half3 CalculateBlinnPhong(Light light, InputData inputData, SurfaceData surfaceData)
{
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
half3 lightDiffuseColor = LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
half3 lightSpecularColor = half3(0,0,0);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
half smoothness = exp2(10 * surfaceData.smoothness + 1);
lightSpecularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, half4(surfaceData.specular, 1), smoothness);
#endif
#if _ALPHAPREMULTIPLY_ON
return lightDiffuseColor * surfaceData.albedo * surfaceData.alpha + lightSpecularColor;
#else
return lightDiffuseColor * surfaceData.albedo + lightSpecularColor;
#endif
}
///////////////////////////////////////////////////////////////////////////////
// Fragment Functions //
// Used by ShaderGraph and others builtin renderers //
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// PBR lighting...
////////////////////////////////////////////////////////////////////////////////
half4 UniversalFragmentPBR(InputData inputData, SurfaceData surfaceData)
{
#if defined(_SPECULARHIGHLIGHTS_OFF)
bool specularHighlightsOff = true;
#else
bool specularHighlightsOff = false;
#endif
BRDFData brdfData;
// NOTE: can modify "surfaceData"...
InitializeBRDFData(surfaceData, brdfData);
#if defined(DEBUG_DISPLAY)
half4 debugColor;
if (CanDebugOverrideOutputColor(inputData, surfaceData, brdfData, debugColor))
{
return debugColor;
}
#endif
// Clear-coat calculation...
BRDFData brdfDataClearCoat = CreateClearCoatBRDFData(surfaceData, brdfData);
half4 shadowMask = CalculateShadowMask(inputData);
AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
uint meshRenderingLayers = GetMeshRenderingLayer();
#if (UNITY_PLATFORM_META_QUEST)
if (dot(GetMainLight().direction, inputData.normalWS) <= 0.0)
{
inputData.shadowCoord.z = -1; // Force outside of shadowmap
}
#endif
Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
// NOTE: We don't apply AO to the GI here because it's done in the lighting calculation below...
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI);
LightingData lightingData = CreateLightingData(inputData, surfaceData);
lightingData.giColor = GlobalIllumination(brdfData, brdfDataClearCoat, surfaceData.clearCoatMask,
inputData.bakedGI, aoFactor.indirectAmbientOcclusion, inputData.positionWS,
inputData.normalWS, inputData.viewDirectionWS, inputData.normalizedScreenSpaceUV);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
#endif
{
lightingData.mainLightColor = LightingPhysicallyBased(brdfData, brdfDataClearCoat,
mainLight,
inputData.normalWS, inputData.viewDirectionWS,
surfaceData.clearCoatMask, specularHighlightsOff);
}
#if defined(_ADDITIONAL_LIGHTS)
uint pixelLightCount = GetAdditionalLightsCount();
#if USE_CLUSTER_LIGHT_LOOP
[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, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light,
inputData.normalWS, inputData.viewDirectionWS,
surfaceData.clearCoatMask, specularHighlightsOff);
}
}
#endif
LIGHT_LOOP_BEGIN(pixelLightCount)
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
#if defined(UNITY_PLATFORM_META_QUEST)
if(light.distanceAttenuation > 0.0)
#endif
lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light,
inputData.normalWS, inputData.viewDirectionWS,
surfaceData.clearCoatMask, specularHighlightsOff);
}
LIGHT_LOOP_END
#endif
#if defined(_ADDITIONAL_LIGHTS_VERTEX)
lightingData.vertexLightingColor += inputData.vertexLighting * brdfData.diffuse;
#endif
#if REAL_IS_HALF && !defined(UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
// Clamp any half.inf+ to HALF_MAX
return min(CalculateFinalColor(lightingData, surfaceData.alpha), HALF_MAX);
#else
return CalculateFinalColor(lightingData, surfaceData.alpha);
#endif
}
// Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments...
half4 UniversalFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
half smoothness, half occlusion, half3 emission, half alpha)
{
SurfaceData surfaceData;
surfaceData.albedo = albedo;
surfaceData.specular = specular;
surfaceData.metallic = metallic;
surfaceData.smoothness = smoothness;
surfaceData.normalTS = half3(0, 0, 1);
surfaceData.emission = emission;
surfaceData.occlusion = occlusion;
surfaceData.alpha = alpha;
surfaceData.clearCoatMask = 0;
surfaceData.clearCoatSmoothness = 1;
return UniversalFragmentPBR(inputData, surfaceData);
}
////////////////////////////////////////////////////////////////////////////////
/// Phong lighting...
////////////////////////////////////////////////////////////////////////////////
half4 UniversalFragmentBlinnPhong(InputData inputData, SurfaceData surfaceData)
{
#if defined(DEBUG_DISPLAY)
half4 debugColor;
if (CanDebugOverrideOutputColor(inputData, surfaceData, debugColor))
{
return debugColor;
}
#endif
uint meshRenderingLayers = GetMeshRenderingLayer();
half4 shadowMask = CalculateShadowMask(inputData);
AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, aoFactor);
inputData.bakedGI *= surfaceData.albedo;
LightingData lightingData = CreateLightingData(inputData, surfaceData);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
#endif
{
lightingData.mainLightColor += CalculateBlinnPhong(mainLight, inputData, surfaceData);
}
#if defined(_ADDITIONAL_LIGHTS)
uint pixelLightCount = GetAdditionalLightsCount();
#if USE_CLUSTER_LIGHT_LOOP
[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, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
lightingData.additionalLightsColor += CalculateBlinnPhong(light, inputData, surfaceData);
}
}
#endif
LIGHT_LOOP_BEGIN(pixelLightCount)
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
#if defined(UNITY_PLATFORM_META_QUEST)
if(light.distanceAttenuation > 0.0)
#endif
lightingData.additionalLightsColor += CalculateBlinnPhong(light, inputData, surfaceData);
}
LIGHT_LOOP_END
#endif
#if defined(_ADDITIONAL_LIGHTS_VERTEX)
lightingData.vertexLightingColor += inputData.vertexLighting * surfaceData.albedo;
#endif
return CalculateFinalColor(lightingData, surfaceData.alpha);
}
// Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments...
half4 UniversalFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half smoothness, half3 emission, half alpha, half3 normalTS)
{
SurfaceData surfaceData;
surfaceData.albedo = diffuse;
surfaceData.alpha = alpha;
surfaceData.emission = emission;
surfaceData.metallic = 0;
surfaceData.occlusion = 1;
surfaceData.smoothness = smoothness;
surfaceData.specular = specularGloss.rgb;
surfaceData.clearCoatMask = 0;
surfaceData.clearCoatSmoothness = 1;
surfaceData.normalTS = normalTS;
return UniversalFragmentBlinnPhong(inputData, surfaceData);
}
////////////////////////////////////////////////////////////////////////////////
/// Unlit
////////////////////////////////////////////////////////////////////////////////
half4 UniversalFragmentBakedLit(InputData inputData, SurfaceData surfaceData)
{
#if defined(DEBUG_DISPLAY)
half4 debugColor;
if (CanDebugOverrideOutputColor(inputData, surfaceData, debugColor))
{
return debugColor;
}
#endif
AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
LightingData lightingData = CreateLightingData(inputData, surfaceData);
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
{
lightingData.giColor *= aoFactor.indirectAmbientOcclusion;
}
return CalculateFinalColor(lightingData, surfaceData.albedo, surfaceData.alpha, inputData.fogCoord);
}
// Deprecated: Use the version which takes "SurfaceData" instead of passing all of these arguments...
half4 UniversalFragmentBakedLit(InputData inputData, half3 color, half alpha, half3 normalTS)
{
SurfaceData surfaceData;
surfaceData.albedo = color;
surfaceData.alpha = alpha;
surfaceData.emission = half3(0, 0, 0);
surfaceData.metallic = 0;
surfaceData.occlusion = 1;
surfaceData.smoothness = 1;
surfaceData.specular = half3(0, 0, 0);
surfaceData.clearCoatMask = 0;
surfaceData.clearCoatSmoothness = 1;
surfaceData.normalTS = normalTS;
return UniversalFragmentBakedLit(inputData, surfaceData);
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 762f0a4829f44584ba01e2f0661150d9
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
#ifndef UNIVERSAL_META_INPUT_INCLUDED
#define UNIVERSAL_META_INPUT_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/MetaPass.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#define MetaInput UnityMetaInput
#define MetaFragment UnityMetaFragment
float4 MetaVertexPosition(float4 positionOS, float2 uv1, float2 uv2, float4 uv1ST, float4 uv2ST)
{
return UnityMetaVertexPosition(positionOS.xyz, uv1, uv2, uv1ST, uv2ST);
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6c9c9877e9a3dff4fbc73fd447c653d8
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
#ifndef UNIVERSAL_PIPELINE_MOTIONVECTORSCOMMON_INCLUDED
#define UNIVERSAL_PIPELINE_MOTIONVECTORSCOMMON_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
float _SpaceWarpNDCModifier;
// 6000.0 Deprecated. This is for backwards compatibility. Remove in the future.
void ApplyMotionVectorZBias(inout float4 positionCS)
{
}
float2 CalcNdcMotionVectorFromCsPositions(float4 posCS, float4 prevPosCS)
{
// Note: unity_MotionVectorsParams.y is 0 is forceNoMotion is enabled
bool forceNoMotion = unity_MotionVectorsParams.y == 0.0;
if (forceNoMotion)
return float2(0.0, 0.0);
// Non-uniform raster needs to keep the posNDC values in float to avoid additional conversions
// since uv remap functions use floats
float2 posNDC = posCS.xy * rcp(posCS.w);
float2 prevPosNDC = prevPosCS.xy * rcp(prevPosCS.w);
float2 velocity;
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
// Convert velocity from NDC space (-1..1) to screen UV 0..1 space since FoveatedRendering remap needs that range.
float2 posUV = RemapFoveatedRenderingResolve(posNDC * 0.5 + 0.5);
float2 prevPosUV = RemapFoveatedRenderingPrevFrameLinearToNonUniform(prevPosNDC * 0.5 + 0.5);
// Calculate forward velocity
velocity = (posUV - prevPosUV);
#if UNITY_UV_STARTS_AT_TOP
velocity.y = -velocity.y;
#endif
}
else
#endif
{
// Calculate forward velocity
velocity = (posNDC.xy - prevPosNDC.xy);
#if UNITY_UV_STARTS_AT_TOP
velocity.y = -velocity.y;
#endif
// Convert velocity from NDC space (-1..1) to UV 0..1 space
// Note: It doesn't mean we don't have negative values, we store negative or positive offset in UV space.
// Note: ((posNDC * 0.5 + 0.5) - (prevPosNDC * 0.5 + 0.5)) = (velocity * 0.5)
velocity.xy *= 0.5;
}
return velocity;
}
// Same as CalcNdcMotionVectorFromCsPositions but returns vec3 ndc space motion vector.
// Also Application SpaceWarp does not support non-uniform foveated rendering so the relevant foveated rendering code is not in this variant.
float3 CalcAswNdcMotionVectorFromCsPositions(float4 posCS, float4 prevPosCS)
{
float3 posNDC = posCS.xyz * rcp(posCS.w);
float3 prevPosNDC = prevPosCS.xyz * rcp(prevPosCS.w);
float3 velocity;
// Calculate forward velocity
velocity = (posNDC.xyz - prevPosNDC.xyz);
#if UNITY_UV_STARTS_AT_TOP
velocity.y = velocity.y * _SpaceWarpNDCModifier;
#endif
return velocity;
}
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a20568904d9c412459181938be987e12
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,190 @@
#ifndef UNIVERSAL_NORMAL_RECONSTRUCTION
#define UNIVERSAL_NORMAL_RECONSTRUCTION
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#if defined(USING_STEREO_MATRICES)
#define unity_eyeIndex unity_StereoEyeIndex
#else
#define unity_eyeIndex 0
#endif
float4x4 _NormalReconstructionMatrix[2];
float GetRawDepth(float2 uv)
{
return SampleSceneDepth(uv.xy).r;
}
// inspired by keijiro's depth inverse projection
// https://github.com/keijiro/DepthInverseProjection
// constructs view space ray at the far clip plane from the screen uv
// then multiplies that ray by the linear 01 depth
float3 ViewSpacePosAtScreenUV(float2 uv, float deviceDepth)
{
float3 viewSpaceRay = mul(_NormalReconstructionMatrix[unity_eyeIndex], float4(uv * 2.0 - 1.0, 1.0, 1.0) * _ProjectionParams.z).xyz;
return viewSpaceRay * Linear01Depth(deviceDepth, _ZBufferParams);
}
float3 ViewSpacePosAtPixelPosition(float2 positionSS, float deviceDepth)
{
float2 uv = positionSS * _ScreenSize.zw;
return ViewSpacePosAtScreenUV(uv, deviceDepth);
}
half3 ReconstructNormalDerivative(float2 positionSS, float deviceDepth)
{
float3 viewSpacePos = ViewSpacePosAtPixelPosition(positionSS, deviceDepth);
float3 hDeriv = ddy(viewSpacePos);
float3 vDeriv = ddx(viewSpacePos);
return half3(SafeNormalize(cross(hDeriv, vDeriv)));
}
float3 ViewSpacePosAtScreenUV(float2 uv)
{
float3 viewSpaceRay = mul(_NormalReconstructionMatrix[unity_eyeIndex], float4(uv * 2.0 - 1.0, 1.0, 1.0) * _ProjectionParams.z).xyz;
float rawDepth = GetRawDepth(uv);
return viewSpaceRay * Linear01Depth(rawDepth, _ZBufferParams);
}
float3 ViewSpacePosAtPixelPosition(float2 positionSS)
{
float2 uv = positionSS * _ScreenSize.zw;
return ViewSpacePosAtScreenUV(uv);
}
half3 ReconstructNormalDerivative(float2 positionSS)
{
float3 viewSpacePos = ViewSpacePosAtPixelPosition(positionSS);
float3 hDeriv = ddy(viewSpacePos);
float3 vDeriv = ddx(viewSpacePos);
return half3(SafeNormalize(cross(hDeriv, vDeriv)));
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 33 math, 3 tex
half3 ReconstructNormalTap3(float2 positionSS)
{
// get current pixel's view space position
float3 viewSpacePos_c = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 0.0));
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
// get the difference between the current and each offset position
float3 hDeriv = viewSpacePos_r - viewSpacePos_c;
float3 vDeriv = viewSpacePos_u - viewSpacePos_c;
// get view space normal from the cross product of the diffs
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 50 math, 4 tex
half3 ReconstructNormalTap4(float2 positionSS)
{
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = ViewSpacePosAtPixelPosition(positionSS + float2(-1.0, 0.0));
float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
float3 viewSpacePos_d = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, -1.0));
float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
// get the difference between the current and each offset position
float3 hDeriv = viewSpacePos_r - viewSpacePos_l;
float3 vDeriv = viewSpacePos_u - viewSpacePos_d;
// get view space normal from the cross product of the diffs
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 54 math, 5 tex
half3 ReconstructNormalTap5(float2 positionSS)
{
// get current pixel's view space position
half3 viewSpacePos_c = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 0.0));
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = ViewSpacePosAtPixelPosition(positionSS + float2(-1.0, 0.0));
float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
float3 viewSpacePos_d = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, -1.0));
float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
// get the difference between the current and each offset position
float3 l = viewSpacePos_c - viewSpacePos_l;
float3 r = viewSpacePos_r - viewSpacePos_c;
float3 d = viewSpacePos_c - viewSpacePos_d;
float3 u = viewSpacePos_u - viewSpacePos_c;
// pick horizontal and vertical diff with the smallest z difference
float3 hDeriv = abs(l.z) < abs(r.z) ? l : r;
float3 vDeriv = abs(d.z) < abs(u.z) ? d : u;
// get view space normal from the cross product of the two smallest offsets
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 66 math, 9 tex
half3 ReconstructNormalTap9(float2 positionSS)
{
// screen uv from positionSS
float2 uv = positionSS * _ScreenSize.zw;
// current pixel's depth
float c = GetRawDepth(uv);
// get current pixel's view space position
float3 viewSpacePos_c = ViewSpacePosAtScreenUV(uv);
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = ViewSpacePosAtScreenUV(uv + float2(-1.0, 0.0) * _ScreenSize.zw);
float3 viewSpacePos_r = ViewSpacePosAtScreenUV(uv + float2(1.0, 0.0) * _ScreenSize.zw);
float3 viewSpacePos_d = ViewSpacePosAtScreenUV(uv + float2(0.0, -1.0) * _ScreenSize.zw);
float3 viewSpacePos_u = ViewSpacePosAtScreenUV(uv + float2(0.0, 1.0) * _ScreenSize.zw);
// get the difference between the current and each offset position
float3 l = viewSpacePos_c - viewSpacePos_l;
float3 r = viewSpacePos_r - viewSpacePos_c;
float3 d = viewSpacePos_c - viewSpacePos_d;
float3 u = viewSpacePos_u - viewSpacePos_c;
// get depth values at 1 & 2 pixels offsets from current along the horizontal axis
half4 H = half4(
GetRawDepth(uv + float2(-1.0, 0.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(1.0, 0.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(-2.0, 0.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(2.0, 0.0) * _ScreenSize.zw.xy)
);
// get depth values at 1 & 2 pixels offsets from current along the vertical axis
half4 V = half4(
GetRawDepth(uv + float2(0.0, -1.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(0.0, 1.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(0.0, -2.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(0.0, 2.0) * _ScreenSize.zw.xy)
);
// current pixel's depth difference from slope of offset depth samples
// differs from original article because we're using non-linear depth values
// see article's comments
half2 he = abs((2 * H.xy - H.zw) - c);
half2 ve = abs((2 * V.xy - V.zw) - c);
// pick horizontal and vertical diff with the smallest depth difference from slopes
float3 hDeriv = he.x < he.y ? l : r;
float3 vDeriv = ve.x < ve.y ? d : u;
// get view space normal from the cross product of the best derivatives
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
#endif // UNIVERSAL_NORMAL_RECONSTRUCTION
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 20013f01a8cbaef4c9545926c27b8d73
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,119 @@
#ifndef UNIVERSAL_OBJECT_MOTION_VECTORS_INCLUDED
#define UNIVERSAL_OBJECT_MOTION_VECTORS_INCLUDED
#pragma target 3.5
#pragma vertex vert
#pragma fragment frag
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
//-------------------------------------
// Other pragmas
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
// -------------------------------------
// Includes
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityInput.hlsl"
#if defined(LOD_FADE_CROSSFADE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
#endif
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/MotionVectorsCommon.hlsl"
// -------------------------------------
// Structs
struct Attributes
{
float4 position : POSITION;
#if _ALPHATEST_ON || APPLICATION_SPACE_WARP_MOTION_TRANSPARENT
float2 uv : TEXCOORD0;
#endif
float3 positionOld : TEXCOORD4;
#if _ADD_PRECOMPUTED_VELOCITY
float3 alembicMotionVector : TEXCOORD5;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 positionCSNoJitter : POSITION_CS_NO_JITTER;
float4 previousPositionCSNoJitter : PREV_POSITION_CS_NO_JITTER;
#if _ALPHATEST_ON || APPLICATION_SPACE_WARP_MOTION_TRANSPARENT
float2 uv : TEXCOORD0;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// -------------------------------------
// Vertex
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
const VertexPositionInputs vertexInput = GetVertexPositionInputs(input.position.xyz);
#if defined(_ALPHATEST_ON) || APPLICATION_SPACE_WARP_MOTION_TRANSPARENT
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
#endif
#if defined(APPLICATION_SPACE_WARP_MOTION)
// We do not need jittered position in ASW
output.positionCSNoJitter = mul(_NonJitteredViewProjMatrix, mul(UNITY_MATRIX_M, input.position));;
output.positionCS = output.positionCSNoJitter;
#else
// Jittered. Match the frame.
output.positionCS = vertexInput.positionCS;
output.positionCSNoJitter = mul(_NonJitteredViewProjMatrix, mul(UNITY_MATRIX_M, input.position));
#endif
float4 prevPos = (unity_MotionVectorsParams.x == 1) ? float4(input.positionOld, 1) : input.position;
#if _ADD_PRECOMPUTED_VELOCITY
prevPos = prevPos - float4(input.alembicMotionVector, 0);
#endif
output.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, mul(UNITY_PREV_MATRIX_M, prevPos));
return output;
}
// -------------------------------------
// Fragment
float4 frag(Varyings input) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if defined(_ALPHATEST_ON)
Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
#endif
#if defined(LOD_FADE_CROSSFADE)
LODFadeCrossFade(input.positionCS);
#endif
#if defined(APPLICATION_SPACE_WARP_MOTION)
#if APPLICATION_SPACE_WARP_MOTION_TRANSPARENT
clip((SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a * _BaseColor.a) - 0.001);
#endif
return float4(CalcAswNdcMotionVectorFromCsPositions(input.positionCSNoJitter, input.previousPositionCSNoJitter), 1);
#else
return float4(CalcNdcMotionVectorFromCsPositions(input.positionCSNoJitter, input.previousPositionCSNoJitter), 0, 0);
#endif
}
#endif // UNIVERSAL_OBJECT_MOTION_VECTORS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6d239a0044031854a817ab72a66ce766
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,173 @@
#ifndef UNIVERSAL_PARTICLES_INCLUDED
#define UNIVERSAL_PARTICLES_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ParticlesInstancing.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/Particles.hlsl"
struct ParticleParams
{
float4 positionWS;
float4 vertexColor;
float4 projectedPosition;
half4 baseColor;
float3 blendUv;
float2 uv;
};
void InitParticleParams(VaryingsParticle input, out ParticleParams output)
{
output = (ParticleParams) 0;
output.uv = input.texcoord;
output.vertexColor = input.color;
#if defined(_FLIPBOOKBLENDING_ON)
output.blendUv = input.texcoord2AndBlend;
#else
output.blendUv = float3(0,0,0);
#endif
#if !defined(PARTICLES_EDITOR_META_PASS)
output.positionWS = input.positionWS;
output.baseColor = _BaseColor;
#if defined(_SOFTPARTICLES_ON) || defined(_FADING_ON) || defined(_DISTORTION_ON)
output.projectedPosition = input.projectedPosition;
#else
output.projectedPosition = float4(0,0,0,0);
#endif
#endif
}
// Pre-multiplied alpha helper
#if defined(_ALPHAPREMULTIPLY_ON)
#define ALBEDO_MUL albedo
#else
#define ALBEDO_MUL albedo.a
#endif
#if defined(_ALPHAPREMULTIPLY_ON)
#define SOFT_PARTICLE_MUL_ALBEDO(albedo, val) albedo * val
#elif defined(_ALPHAMODULATE_ON)
#define SOFT_PARTICLE_MUL_ALBEDO(albedo, val) half4(lerp(half3(1.0, 1.0, 1.0), albedo.rgb, albedo.a * val), albedo.a * val)
#else
#define SOFT_PARTICLE_MUL_ALBEDO(albedo, val) albedo * half4(1.0, 1.0, 1.0, val)
#endif
// Color blending fragment function
half4 MixParticleColor(half4 baseColor, half4 particleColor, half4 colorAddSubDiff)
{
#if defined(_COLOROVERLAY_ON) // Overlay blend
half4 output = baseColor;
output.rgb = lerp(1 - 2 * (1 - baseColor.rgb) * (1 - particleColor.rgb), 2 * baseColor.rgb * particleColor.rgb, step(baseColor.rgb, 0.5));
output.a *= particleColor.a;
return output;
#elif defined(_COLORCOLOR_ON) // Color blend
half3 aHSL = RgbToHsv(baseColor.rgb);
half3 bHSL = RgbToHsv(particleColor.rgb);
half3 rHSL = half3(bHSL.x, bHSL.y, aHSL.z);
return half4(HsvToRgb(rHSL), baseColor.a * particleColor.a);
#elif defined(_COLORADDSUBDIFF_ON) // Additive, Subtractive and Difference blends based on 'colorAddSubDiff'
half4 output = baseColor;
output.rgb = baseColor.rgb + particleColor.rgb * colorAddSubDiff.x;
output.rgb = lerp(output.rgb, abs(output.rgb), colorAddSubDiff.y);
output.a *= particleColor.a;
return output;
#else // Default to Multiply blend
return baseColor * particleColor;
#endif
}
// Soft particles - returns alpha value for fading particles based on the depth to the background pixel
float SoftParticles(float near, float far, float4 projection)
{
float fade = 1;
if (near > 0.0 || far > 0.0)
{
float2 uv = UnityStereoTransformScreenSpaceTex(projection.xy / projection.w);
#if defined(UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION)
uv = RemovePretransformRotation(uv);
#endif
uv = FoveatedRemapLinearToNonUniform(uv);
float rawDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r;
float sceneZ = (unity_OrthoParams.w == 0) ? LinearEyeDepth(rawDepth, _ZBufferParams) : LinearDepthToEyeDepth(rawDepth);
float thisZ = LinearEyeDepth(projection.z / projection.w, _ZBufferParams);
fade = saturate(far * ((sceneZ - near) - thisZ));
}
return fade;
}
// Soft particles - returns alpha value for fading particles based on the depth to the background pixel
float SoftParticles(float near, float far, ParticleParams params)
{
float fade = 1;
if (near > 0.0 || far > 0.0)
{
float2 uv = UnityStereoTransformScreenSpaceTex(params.projectedPosition.xy / params.projectedPosition.w);
#if defined(UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION)
uv = RemovePretransformRotation(uv);
#endif
uv = FoveatedRemapLinearToNonUniform(uv);
float rawDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r;
float sceneZ = (unity_OrthoParams.w == 0) ? LinearEyeDepth(rawDepth, _ZBufferParams) : LinearDepthToEyeDepth(rawDepth);
float thisZ = LinearEyeDepth(params.positionWS.xyz, GetWorldToViewMatrix());
fade = saturate(far * ((sceneZ - near) - thisZ));
}
return fade;
}
// Camera fade - returns alpha value for fading particles based on camera distance
half CameraFade(float near, float far, float4 projection)
{
float thisZ = LinearEyeDepth(projection.z / projection.w, _ZBufferParams);
return half(saturate((thisZ - near) * far));
}
half3 AlphaModulateAndPremultiply(half3 albedo, half alpha)
{
#if defined(_ALPHAMODULATE_ON)
return AlphaModulate(albedo, alpha);
#elif defined(_ALPHAPREMULTIPLY_ON)
return AlphaPremultiply(albedo, alpha);
#endif
return albedo;
}
half3 Distortion(float4 baseColor, float3 normal, half strength, half blend, float4 projection)
{
float2 screenUV = (projection.xy / projection.w) + normal.xy * strength * baseColor.a;
screenUV = UnityStereoTransformScreenSpaceTex(screenUV);
float3 distortion = SampleSceneColor(screenUV);
return half3(lerp(distortion, baseColor.rgb, saturate(baseColor.a - blend)));
}
// Sample a texture and do blending for texture sheet animation if needed
half4 BlendTexture(UnityTexture2D _Texture, float2 uv, float3 blendUv)
{
half4 color = half4(SAMPLE_TEXTURE2D(_Texture.tex, _Texture.samplerstate, uv));
#ifdef _FLIPBOOKBLENDING_ON
half4 color2 = half4(SAMPLE_TEXTURE2D(_Texture.tex, _Texture.samplerstate, blendUv.xy));
color = lerp(color, color2, half(blendUv.z));
#endif
return color;
}
// Sample a normal map in tangent space
half3 SampleNormalTS(float2 uv, float3 blendUv, UnityTexture2D bumpMap, half scale = half(1.0))
{
#if defined(_NORMALMAP)
half4 n = BlendTexture(bumpMap, uv, blendUv);
#if BUMP_SCALE_NOT_SUPPORTED
return UnpackNormal(n);
#else
return UnpackNormalScale(n, scale);
#endif
#else
return half3(0.0, 0.0, 1.0);
#endif
}
#endif // UNIVERSAL_PARTICLES_INCLUDED
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 58997c4bd657ad848919e91029ee01eb
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,97 @@
#ifndef UNIVERSAL_PARTICLESINSTANCING_INCLUDED
#define UNIVERSAL_PARTICLESINSTANCING_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ParticlesInstancing.hlsl"
#if defined(UNITY_PARTICLE_INSTANCING_ENABLED)
// Kept for backward compatibility with custom shaders that call it directly.
void ParticleInstancingMatrices(out float4x4 objectToWorld, out float4x4 worldToObject)
{
UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID];
// transform matrix
objectToWorld._11_21_31_41 = float4(data.transform._11_21_31, 0.0f);
objectToWorld._12_22_32_42 = float4(data.transform._12_22_32, 0.0f);
objectToWorld._13_23_33_43 = float4(data.transform._13_23_33, 0.0f);
objectToWorld._14_24_34_44 = float4(data.transform._14_24_34, 1.0f);
// inverse transform matrix
float3x3 worldToObject3x3;
worldToObject3x3[0] = objectToWorld[1].yzx * objectToWorld[2].zxy - objectToWorld[1].zxy * objectToWorld[2].yzx;
worldToObject3x3[1] = objectToWorld[0].zxy * objectToWorld[2].yzx - objectToWorld[0].yzx * objectToWorld[2].zxy;
worldToObject3x3[2] = objectToWorld[0].yzx * objectToWorld[1].zxy - objectToWorld[0].zxy * objectToWorld[1].yzx;
float det = dot(objectToWorld[0].xyz, worldToObject3x3[0]);
worldToObject3x3 = transpose(worldToObject3x3);
worldToObject3x3 *= rcp(det);
float3 worldToObjectPosition = mul(worldToObject3x3, -objectToWorld._14_24_34);
worldToObject._11_21_31_41 = float4(worldToObject3x3._11_21_31, 0.0f);
worldToObject._12_22_32_42 = float4(worldToObject3x3._12_22_32, 0.0f);
worldToObject._13_23_33_43 = float4(worldToObject3x3._13_23_33, 0.0f);
worldToObject._14_24_34_44 = float4(worldToObjectPosition, 1.0f);
}
// Builds VertexPositionInputs from the particle instance transform directly,
// bypassing GetVertexPositionInputs() which reads UNITY_MATRIX_M.
VertexPositionInputs ParticleInstancingGetVertexPositionInputs(float3x4 transform, float3 positionOS)
{
VertexPositionInputs vertexInput;
vertexInput.positionWS = ParticleInstancingTransformPosition(transform, positionOS);
vertexInput.positionVS = TransformWorldToView(vertexInput.positionWS);
vertexInput.positionCS = TransformWorldToHClip(vertexInput.positionWS);
float4 ndc = vertexInput.positionCS * 0.5f;
vertexInput.positionNDC.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
vertexInput.positionNDC.zw = vertexInput.positionCS.zw;
return vertexInput;
}
// Builds VertexNormalInputs from the particle instance transform directly,
// bypassing GetVertexNormalInputs() which reads UNITY_MATRIX_I_M.
// Tangents transform with the forward 3x3 (covariant, like directions).
// Normals require the inverse-transpose: cofactor(m) equals det(m)*m^{-T};
// after SafeNormalize this gives the correct world normal under non-uniform scale.
// Matches TransformParticleMesh in the ShaderGraph package (Particles.hlsl).
VertexNormalInputs ParticleInstancingGetVertexNormalInputs(float3x4 transform, float3 normalOS, float4 tangentOS)
{
ParticleInstancingTransformNormalTangent(transform, normalOS, tangentOS.xyz);
VertexNormalInputs tbn;
tbn.normalWS = SafeNormalize(normalOS);
tbn.tangentWS = real3(SafeNormalize(tangentOS.xyz));
real sign = real(tangentOS.w) * GetOddNegativeScale();
tbn.bitangentWS = real3(cross(tbn.normalWS, float3(tbn.tangentWS))) * sign;
return tbn;
}
#endif
VertexPositionInputs GetParticleVertexPositionInputs(float3 positionOS)
{
#if defined(UNITY_PARTICLE_INSTANCING_ENABLED)
return ParticleInstancingGetVertexPositionInputs(unity_ParticleInstanceData[unity_InstanceID].transform, positionOS);
#else
return GetVertexPositionInputs(positionOS);
#endif
}
VertexNormalInputs GetParticleVertexNormalInputs(float3 normalOS, float4 tangentOS)
{
#if defined(UNITY_PARTICLE_INSTANCING_ENABLED)
return ParticleInstancingGetVertexNormalInputs(unity_ParticleInstanceData[unity_InstanceID].transform, normalOS, tangentOS);
#else
return GetVertexNormalInputs(normalOS, tangentOS);
#endif
}
VertexNormalInputs GetParticleVertexNormalInputs(float3 normalOS)
{
return GetParticleVertexNormalInputs(normalOS, float4(0, 0, 0, 1));
}
#endif // UNIVERSAL_PARTICLESINSTANCING_INCLUDED
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c70398529f54bc44ca6a3ed0211e039f
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,6 @@
#ifndef UNIVERSAL_PROBE_VOLUME_VARIANTS_INCLUDED
#define UNIVERSAL_PROBE_VOLUME_VARIANTS_INCLUDED
#pragma multi_compile _ PROBE_VOLUMES_L1 PROBE_VOLUMES_L2
#endif // UNIVERSAL_PROBE_VOLUME_VARIANTS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4156fde60711cfd4c9cc05a737bd013e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,321 @@
#ifndef UNIVERSAL_REALTIME_LIGHTS_INCLUDED
#define UNIVERSAL_REALTIME_LIGHTS_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookie.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Clustering.hlsl"
// Abstraction over Light shading data.
struct Light
{
half3 direction;
half3 color;
float distanceAttenuation; // full-float precision required on some platforms
half shadowAttenuation;
uint layerMask;
};
#if USE_CLUSTER_LIGHT_LOOP && defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
#define CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK if (_AdditionalLightsColor[lightIndex].a > 0.0h) continue;
#else
#define CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK
#endif
#if defined(UNITY_PLATFORM_META_QUEST) && META_QUEST_LIGHTUNROLL
#define UNROLL_ONELIGHT [unroll(1)]
#else
#define UNROLL_ONELIGHT
#endif
#if USE_CLUSTER_LIGHT_LOOP
#define LIGHT_LOOP_BEGIN(lightCount) { \
uint lightIndex; \
ClusterIterator _urp_internal_clusterIterator = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 0); \
[loop] while (ClusterNext(_urp_internal_clusterIterator, lightIndex)) { \
lightIndex += URP_FP_DIRECTIONAL_LIGHTS_COUNT; \
CLUSTER_LIGHT_LOOP_SUBTRACTIVE_LIGHT_CHECK
#define LIGHT_LOOP_END } }
#else
#define LIGHT_LOOP_BEGIN(lightCount) \
UNROLL_ONELIGHT \
for (uint lightIndex = 0u; lightIndex < lightCount; ++lightIndex) {
#define LIGHT_LOOP_END }
#endif
///////////////////////////////////////////////////////////////////////////////
// Attenuation Functions /
///////////////////////////////////////////////////////////////////////////////
// Matches Unity Vanilla HINT_NICE_QUALITY attenuation
// Attenuation smoothly decreases to light range.
#if (UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
float DistanceAttenuation(float distanceSqr, half2 distanceAttenuation, float distRsqrt)
#else
float DistanceAttenuation(float distanceSqr, half2 distanceAttenuation)
#endif
{
// We use a shared distance attenuation for additional directional and puctual lights
// for directional lights attenuation will be 1
#if (UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
// distRsqrt is rsqrt(distanceSqr), already computed at the call site for light direction
// normalization. We reuse it here: distRsqrt² = rsqrt(d²)² = 1/d², avoiding a separate
// rcp(distanceSqr) call and saving one EFU (complex) instruction per light.
float lightAtten = distRsqrt * distRsqrt;
#else
float lightAtten = rcp(distanceSqr);
#endif
float2 distanceAttenuationFloat = float2(distanceAttenuation);
// Use the smoothing factor also used in the Unity lightmapper.
half factor = half(distanceSqr * distanceAttenuationFloat.x);
half smoothFactor = saturate(half(1.0) - factor * factor);
smoothFactor = smoothFactor * smoothFactor;
return lightAtten * smoothFactor;
}
half AngleAttenuation(half3 spotDirection, half3 lightDirection, half2 spotAttenuation)
{
// Spot Attenuation with a linear falloff can be defined as
// (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
// This can be rewritten as
// invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
// SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
// SdotL * spotAttenuation.x + spotAttenuation.y
// If we precompute the terms in a MAD instruction
half SdotL = dot(spotDirection, lightDirection);
half atten = saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
return atten * atten;
}
///////////////////////////////////////////////////////////////////////////////
// Light Abstraction //
///////////////////////////////////////////////////////////////////////////////
Light GetMainLight()
{
Light light;
light.direction = half3(_MainLightPosition.xyz);
#if USE_CLUSTER_LIGHT_LOOP
#if defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
light.distanceAttenuation = _MainLightColor.a;
#else
light.distanceAttenuation = 1.0;
#endif
#else
light.distanceAttenuation = unity_LightData.z; // unity_LightData.z is 1 when not culled by the culling mask, otherwise 0.
#endif
light.shadowAttenuation = 1.0;
light.color = _MainLightColor.rgb;
light.layerMask = _MainLightLayerMask;
return light;
}
Light GetMainLight(float4 shadowCoord)
{
Light light = GetMainLight();
light.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
return light;
}
Light GetMainLight(float4 shadowCoord, float3 positionWS, half4 shadowMask)
{
Light light = GetMainLight();
light.shadowAttenuation = MainLightShadow(shadowCoord, positionWS, shadowMask, _MainLightOcclusionProbes);
#if defined(_LIGHT_COOKIES)
real3 cookieColor = SampleMainLightCookie(positionWS);
light.color *= cookieColor;
#endif
return light;
}
Light GetMainLight(InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
{
Light light = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
#if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
{
light.color *= aoFactor.directAmbientOcclusion;
}
#endif
return light;
}
// Fills a light struct given a perObjectLightIndex
Light GetAdditionalPerObjectLight(int perObjectLightIndex, float3 positionWS)
{
// Abstraction over Light input constants
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
float4 lightPositionWS = _AdditionalLightsBuffer[perObjectLightIndex].position;
half3 color = _AdditionalLightsBuffer[perObjectLightIndex].color.rgb;
half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[perObjectLightIndex].attenuation;
half4 spotDirection = _AdditionalLightsBuffer[perObjectLightIndex].spotDirection;
uint lightLayerMask = _AdditionalLightsBuffer[perObjectLightIndex].layerMask;
#else
float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex];
half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb;
half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex];
half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex];
uint lightLayerMask = asuint(_AdditionalLightsLayerMasks[perObjectLightIndex]);
#endif
// Directional lights store direction in lightPosition.xyz and have .w set to 0.0.
// This way the following code will work for both directional and punctual lights.
float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
#if (UNITY_PLATFORM_META_QUEST) // This is platform specific change targeting performance only
float distRsqrt = rsqrt(distanceSqr);
half3 lightDirection = half3(lightVector * distRsqrt);
float distAtten = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy, distRsqrt);
#else
half3 lightDirection = half3(lightVector * rsqrt(distanceSqr));
float distAtten = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy);
#endif
#if (META_QUEST_NO_SPOTLIGHTS_LIGHT_LOOP)
// full-float precision required on some platforms
float attenuation = distAtten;
#else
// full-float precision required on some platforms
float attenuation = distAtten * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
#endif
Light light;
light.direction = lightDirection;
light.distanceAttenuation = attenuation;
light.shadowAttenuation = 1.0; // This value can later be overridden in GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
light.color = color;
light.layerMask = lightLayerMask;
return light;
}
uint GetPerObjectLightIndexOffset()
{
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
return uint(unity_LightData.x);
#else
return 0;
#endif
}
// Returns a per-object index given a loop index.
// This abstract the underlying data implementation for storing lights/light indices
int GetPerObjectLightIndex(uint index)
{
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
/////////////////////////////////////////////////////////////////////////////////////////////
// Structured Buffer Path /
// /
// Lights and light indices are stored in StructuredBuffer. We can just index them. /
// Currently all non-mobile platforms take this path :( /
// There are limitation in mobile GPUs to use SSBO (performance / no vertex shader support) /
/////////////////////////////////////////////////////////////////////////////////////////////
uint offset = uint(unity_LightData.x);
return _AdditionalLightsIndices[offset + index];
#else
/////////////////////////////////////////////////////////////////////////////////////////////
// UBO path /
// /
// We pack 8 x 16bit uint light indices into float4 unity_PackedLightIndices; /
// light index 0 is packed into lower 16 bits of unity_PackedLightIndices.x, /
// light index 1 is packed into high 16 bits of unity_PackedLightIndices.x and so on /
/////////////////////////////////////////////////////////////////////////////////////////////
uint4 packed4 = asuint(unity_PackedLightIndices);
uint2 pair = index >= 4 ? packed4.zw : packed4.xy;
uint word = (index & 2) ? pair.y : pair.x;
return (word >> ((index & 1) << 4)) & 0xFFFF;
#endif
}
// Fills a light struct given a loop i index. This will convert the i
// index to a perObjectLightIndex
Light GetAdditionalLight(uint i, float3 positionWS)
{
#if USE_CLUSTER_LIGHT_LOOP
int lightIndex = i;
#else
int lightIndex = GetPerObjectLightIndex(i);
#endif
return GetAdditionalPerObjectLight(lightIndex, positionWS);
}
Light GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
{
#if USE_CLUSTER_LIGHT_LOOP
int lightIndex = i;
#else
int lightIndex = GetPerObjectLightIndex(i);
#endif
Light light = GetAdditionalPerObjectLight(lightIndex, positionWS);
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
half4 occlusionProbeChannels = _AdditionalLightsBuffer[lightIndex].occlusionProbeChannels;
#else
half4 occlusionProbeChannels = _AdditionalLightsOcclusionProbes[lightIndex];
#endif
light.shadowAttenuation = AdditionalLightShadow(lightIndex, positionWS, light.direction, shadowMask, occlusionProbeChannels);
#if defined(_LIGHT_COOKIES)
real3 cookieColor = SampleAdditionalLightCookie(lightIndex, positionWS);
light.color *= cookieColor;
#endif
return light;
}
Light GetAdditionalLight(uint i, InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
{
Light light = GetAdditionalLight(i, inputData.positionWS, shadowMask);
#if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
{
light.color *= aoFactor.directAmbientOcclusion;
}
#endif
return light;
}
int GetAdditionalLightsCount()
{
#if USE_CLUSTER_LIGHT_LOOP
// Counting the number of lights in clustered requires traversing the bit list, and is not needed up front.
return 0;
#else
// TODO: we need to expose in SRP api an ability for the pipeline cap the amount of lights
// in the culling. This way we could do the loop branch with an uniform
// This would be helpful to support baking exceeding lights in SH as well
return int(min(_AdditionalLightsCount.x, unity_LightData.y));
#endif
}
half4 CalculateShadowMask(InputData inputData)
{
// To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
half4 shadowMask = inputData.shadowMask; // Shadowmask was sampled from lightmap
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
half4 shadowMask = inputData.shadowMask; // Shadowmask (probe occlusion) was sampled from APV
#elif !defined (LIGHTMAP_ON)
half4 shadowMask = unity_ProbesOcclusion; // Sample shadowmask (probe occlusion) from legacy probes
#else
half4 shadowMask = half4(1, 1, 1, 1); // Fallback shadowmask, fully unoccluded
#endif
return shadowMask;
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4e8e2a4c57cb4eb6bf8653ab88069a9c
timeCreated: 1615472820
@@ -0,0 +1,7 @@
#ifndef UNIVERSAL_WRITE_RENDERING_LAYERS_PRAGMAS_INCLUDED
#define UNIVERSAL_WRITE_RENDERING_LAYERS_PRAGMAS_INCLUDED
#pragma multi_compile_fragment _ _WRITE_RENDERING_LAYERS
#pragma target 4.5 _WRITE_RENDERING_LAYERS
#endif // UNIVERSAL_WRITE_RENDERING_LAYERS_PRAGMAS_INCLUDED
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: bcd650cf6823f4f7fb62fe0eccae07b0
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,636 @@
#ifndef UNIVERSAL_SSAO_INCLUDED
#define UNIVERSAL_SSAO_INCLUDED
// Quality Constants
#if defined(_SAMPLE_COUNT_HIGH)
static const int SAMPLE_COUNT = 12;
static const int GTAO_STEP_COUNT = 6;
static const int GTAO_DIRECTION_COUNT = 4;
#elif defined(_SAMPLE_COUNT_MEDIUM)
static const int SAMPLE_COUNT = 8;
static const int GTAO_STEP_COUNT = 4;
static const int GTAO_DIRECTION_COUNT = 2;
#else
static const int SAMPLE_COUNT = 4;
static const int GTAO_STEP_COUNT = 2;
static const int GTAO_DIRECTION_COUNT = 1;
#endif
// Textures and Caller-defined macros for sampling (must be defined before SSAOCommon include)
TEXTURE2D_HALF(_BlueNoiseTexture);
SAMPLER(sampler_BlitTexture);
#define SSAO_COMMON_SAMPLE_BASEMAP(uv) half4(SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_BlitTexture, UnityStereoTransformScreenSpaceTex(uv)))
#define SSAO_COMMON_SAMPLE_BASEMAP_R(uv) half(SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_BlitTexture, UnityStereoTransformScreenSpaceTex(uv)).r)
#define SSAO_COMMON_SAMPLE_BLUE_NOISE(uv) SAMPLE_TEXTURE2D(_BlueNoiseTexture, sampler_PointRepeat, UnityStereoTransformScreenSpaceTex(uv)).a
#define SSAO_COMMON_FETCH_DEPTH(samplePos, screenSize, downsample) SampleDepth(samplePos / screenSize, downsample)
#define SSAO_COMMON_DECLARE_UNIFORMS
// Includes
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAOCommon.hlsl"
// Fragment-specific uniform params
float4 _CameraViewTopLeftCorner[2];
float4x4 _CameraViewProjections[2]; // Platform-agnostic projection matrix. Handle both non-XR and XR modes.
float4 _ProjectionParams2;
float4 _CameraViewXExtent[2];
float4 _CameraViewYExtent[2];
float4 _CameraViewZExtent[2];
// Textures
TEXTURE2D_X_HALF(_ScreenSpaceOcclusionTexture);
TEXTURE2D_X_HALF(_SSAOHistoryTexture);
TEXTURE2D_X(_MotionVectorTexture);
// Local convenience aliases for entry point functions
#define INTENSITY _SSAOParams.x
#define RADIUS _SSAOParams.y
#define DOWNSAMPLE _SSAOParams.z
#define FALLOFF _SSAOParams.w
#if defined(USING_STEREO_MATRICES)
#define unity_eyeIndex unity_StereoEyeIndex
#else
#define unity_eyeIndex 0
#endif
// Hardcoded random UV values that improves performance.
// The values were taken from this function:
// r = frac(43758.5453 * sin( dot(float2(12.9898, 78.233), uv)) ));
// Indices 0 to 19 are for u = 0.0
// Indices 20 to 39 are for u = 1.0
static half SSAORandomUV[40] =
{
0.00000000, // 00
0.33984375, // 01
0.75390625, // 02
0.56640625, // 03
0.98437500, // 04
0.07421875, // 05
0.23828125, // 06
0.64062500, // 07
0.35937500, // 08
0.50781250, // 09
0.38281250, // 10
0.98437500, // 11
0.17578125, // 12
0.53906250, // 13
0.28515625, // 14
0.23137260, // 15
0.45882360, // 16
0.54117650, // 17
0.12941180, // 18
0.64313730, // 19
0.92968750, // 20
0.76171875, // 21
0.13333330, // 22
0.01562500, // 23
0.00000000, // 24
0.10546875, // 25
0.64062500, // 26
0.74609375, // 27
0.67968750, // 28
0.35156250, // 29
0.49218750, // 30
0.12500000, // 31
0.26562500, // 32
0.62500000, // 33
0.44531250, // 34
0.17647060, // 35
0.44705890, // 36
0.93333340, // 37
0.87058830, // 38
0.56862750, // 39
};
// ------------------------------------------------------------------
// Fragment-Specific Functions
// ------------------------------------------------------------------
half EncodeAO(half x)
{
#if UNITY_COLORSPACE_GAMMA
return half(1.0 - max(LinearToSRGB(1.0 - saturate(x)), 0.0));
#else
return x;
#endif
}
// Pseudo random number generator
half GetRandomVal(half u, half sampleIndex)
{
return SSAORandomUV[u * 20 + sampleIndex];
}
// Sample point picker
half3 PickSamplePoint(float2 uv, int sampleIndex, half sampleIndexHalf, half rcpSampleCount, half3 centerNormal, float2 pixelDensity)
{
half3 v;
#if defined(_BLUE_NOISE)
const half lerpVal = sampleIndexHalf * rcpSampleCount;
const half noise = SSAO_COMMON_SAMPLE_BLUE_NOISE(((uv + BlueNoiseOffset) * BlueNoiseScale) + lerpVal);
const half u = frac(GetRandomVal(HALF_ZERO, sampleIndexHalf).x + noise) * HALF_TWO - HALF_ONE;
const half theta = (GetRandomVal(HALF_ONE, sampleIndexHalf).x + noise) * HALF_TWO_PI * HALF_HUNDRED;
const half u2 = half(sqrt(HALF_ONE - u * u));
half sinTheta, cosTheta;
sincos(theta, sinTheta, cosTheta);
v = half3(u2 * cosTheta, u2 * sinTheta, u);
v *= (dot(centerNormal, v) >= HALF_ZERO) * HALF_TWO - HALF_ONE;
v *= lerp(0.1, 1.0, lerpVal * lerpVal);
#else
const float2 positionSS = GetScreenSpacePosition(uv, DOWNSAMPLE);
const half noise = half(InterleavedGradientNoise(positionSS, sampleIndex));
const half u = frac(GetRandomVal(HALF_ZERO, sampleIndex) + noise) * HALF_TWO - HALF_ONE;
const half theta = (GetRandomVal(HALF_ONE, sampleIndex) + noise) * HALF_TWO_PI;
const half u2 = half(sqrt(HALF_ONE - u * u));
half sinTheta, cosTheta;
sincos(theta, sinTheta, cosTheta);
v = half3(u2 * cosTheta, u2 * sinTheta, u);
v *= sqrt((sampleIndexHalf + HALF_ONE) * rcpSampleCount);
v = faceforward(v, -centerNormal, v);
#endif
v *= RADIUS;
v.xy *= pixelDensity;
return v;
}
float SampleAndGetLinearEyeDepth(float2 uv)
{
const float rawDepth = SampleDepth(uv, DOWNSAMPLE);
return GetLinearEyeDepth(rawDepth);
}
// This returns a vector in world unit (not a position), from camera to the given point described by uv screen coordinate and depth (in absolute world unit).
float3 ReconstructViewPos(float2 uv, float linearDepth)
{
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
uv = RemapFoveatedRenderingNonUniformToLinear(uv);
}
#endif
// Screen is y-inverted.
uv.y = 1.0 - uv.y;
// view pos in world space
float3 viewPos;
#if defined(_ORTHOGRAPHIC)
float zScale = linearDepth * _ProjectionParams.w; // divide by far plane
viewPos = _CameraViewTopLeftCorner[unity_eyeIndex].xyz
+ _CameraViewXExtent[unity_eyeIndex].xyz * uv.x
+ _CameraViewYExtent[unity_eyeIndex].xyz * uv.y
+ _CameraViewZExtent[unity_eyeIndex].xyz * zScale;
#else
float zScale = linearDepth * _ProjectionParams2.x; // divide by near plane
viewPos = _CameraViewTopLeftCorner[unity_eyeIndex].xyz
+ _CameraViewXExtent[unity_eyeIndex].xyz * uv.x
+ _CameraViewYExtent[unity_eyeIndex].xyz * uv.y;
viewPos *= zScale;
#endif
return viewPos;
}
// Try reconstructing normal accurately from depth buffer.
// Low: DDX/DDY on the current pixel
// Medium: 3 taps on each direction | x | * | y |
// High: 5 taps on each direction: | z | x | * | y | w |
// https://atyuwen.github.io/posts/normal-reconstruction/
// https://wickedengine.net/2019/09/22/improved-normal-reconstruction-from-depth/
half3 ReconstructNormal(float2 uv, float linearDepth, float3 vpos, float2 pixelDensity)
{
#if defined(_SOURCE_DEPTH_LOW)
return half3(normalize(cross(ddy(vpos), ddx(vpos))));
#else
float2 delta = float2(_SourceSize.zw * 2.0) * rcp(pixelDensity);
// Sample the neighbour fragments
float2 lUV = float2(-delta.x, 0.0);
float2 rUV = float2(delta.x, 0.0);
float2 uUV = float2(0.0, delta.y);
float2 dUV = float2(0.0, -delta.y);
float3 l1 = float3(uv + lUV, 0.0); l1.z = SampleAndGetLinearEyeDepth(l1.xy); // Left1
float3 r1 = float3(uv + rUV, 0.0); r1.z = SampleAndGetLinearEyeDepth(r1.xy); // Right1
float3 u1 = float3(uv + uUV, 0.0); u1.z = SampleAndGetLinearEyeDepth(u1.xy); // Up1
float3 d1 = float3(uv + dUV, 0.0); d1.z = SampleAndGetLinearEyeDepth(d1.xy); // Down1
// Determine the closest horizontal and vertical pixels...
// horizontal: left = 0.0 right = 1.0
// vertical : down = 0.0 up = 1.0
#if defined(_SOURCE_DEPTH_MEDIUM)
uint closest_horizontal = l1.z > r1.z ? 0 : 1;
uint closest_vertical = d1.z > u1.z ? 0 : 1;
#else
float3 l2 = float3(uv + lUV * 2.0, 0.0); l2.z = SampleAndGetLinearEyeDepth(l2.xy); // Left2
float3 r2 = float3(uv + rUV * 2.0, 0.0); r2.z = SampleAndGetLinearEyeDepth(r2.xy); // Right2
float3 u2 = float3(uv + uUV * 2.0, 0.0); u2.z = SampleAndGetLinearEyeDepth(u2.xy); // Up2
float3 d2 = float3(uv + dUV * 2.0, 0.0); d2.z = SampleAndGetLinearEyeDepth(d2.xy); // Down2
const uint closest_horizontal = abs( (2.0 * l1.z - l2.z) - linearDepth) < abs( (2.0 * r1.z - r2.z) - linearDepth) ? 0 : 1;
const uint closest_vertical = abs( (2.0 * d1.z - d2.z) - linearDepth) < abs( (2.0 * u1.z - u2.z) - linearDepth) ? 0 : 1;
#endif
// Calculate the triangle, in a counter-clockwize order, to
// use based on the closest horizontal and vertical depths.
// h == 0.0 && v == 0.0: p1 = left, p2 = down
// h == 1.0 && v == 0.0: p1 = down, p2 = right
// h == 1.0 && v == 1.0: p1 = right, p2 = up
// h == 0.0 && v == 1.0: p1 = up, p2 = left
// Calculate the view space positions for the three points...
float3 P1;
float3 P2;
if (closest_vertical == 0)
{
P1 = closest_horizontal == 0 ? l1 : d1;
P2 = closest_horizontal == 0 ? d1 : r1;
}
else
{
P1 = closest_horizontal == 0 ? u1 : r1;
P2 = closest_horizontal == 0 ? l1 : u1;
}
// Use the cross product to calculate the normal...
return half3(normalize(cross(ReconstructViewPos(P2.xy, P2.z) - vpos, ReconstructViewPos(P1.xy, P1.z) - vpos)));
#endif
}
half3 SampleNormal(float2 uv, float linearDepth, float2 pixelDensity)
{
#if defined(_SOURCE_DEPTH_NORMALS)
return half3(SampleSceneNormals(uv));
#else
float3 vpos = ReconstructViewPos(uv, linearDepth);
return ReconstructNormal(uv, linearDepth, vpos, pixelDensity);
#endif
}
// Distance-based AO estimator based on Morgan 2011
// "Alchemy screen-space ambient obscurance algorithm"
// http://graphics.cs.williams.edu/papers/AlchemyHPG11/
half4 FragSSAO(Varyings input)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord;
float centerRawDepth = SampleDepth(uv, DOWNSAMPLE);
float centerLinearDepth = GetLinearEyeDepth(centerRawDepth);
half centerHalfLinearDepth = half(centerLinearDepth);
if (ShouldSkipAO(centerRawDepth, centerHalfLinearDepth, FALLOFF))
return PackAOAndNormal(HALF_ZERO, HALF_ZERO);
float2 pixelDensity;
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
pixelDensity = RemapFoveatedRenderingDensity(RemapFoveatedRenderingNonUniformToLinear(uv));
}
else
#endif
{
pixelDensity = float2(1.0f, 1.0f);
}
// Normal for this fragment
half3 centerNormal = SampleNormal(uv, centerLinearDepth, pixelDensity);
// View position for this fragment
float3 centerViewPos = ReconstructViewPos(uv, centerLinearDepth);
// Parameters used in coordinate conversion
half3 camTransform000102 = half3(_CameraViewProjections[unity_eyeIndex]._m00, _CameraViewProjections[unity_eyeIndex]._m01, _CameraViewProjections[unity_eyeIndex]._m02);
half3 camTransform101112 = half3(_CameraViewProjections[unity_eyeIndex]._m10, _CameraViewProjections[unity_eyeIndex]._m11, _CameraViewProjections[unity_eyeIndex]._m12);
const half rcpSampleCount = half(rcp(SAMPLE_COUNT));
half ao = HALF_ZERO;
half sHalf = HALF_MINUS_ONE;
UNITY_UNROLL
for (int s = 0; s < SAMPLE_COUNT; s++)
{
sHalf += HALF_ONE;
// Sample point
half3 v_s1 = PickSamplePoint(uv, s, sHalf, rcpSampleCount, centerNormal, pixelDensity);
half3 vpos_s1 = half3(centerViewPos + v_s1);
half2 spos_s1 = half2(
camTransform000102.x * vpos_s1.x + camTransform000102.y * vpos_s1.y + camTransform000102.z * vpos_s1.z,
camTransform101112.x * vpos_s1.x + camTransform101112.y * vpos_s1.y + camTransform101112.z * vpos_s1.z
);
half zDist;
half2 uv_s1_01;
#if defined(_ORTHOGRAPHIC)
zDist = centerHalfLinearDepth;
uv_s1_01 = saturate((spos_s1 + HALF_ONE) * HALF_HALF);
#else
zDist = half(-dot(UNITY_MATRIX_V[2].xyz, vpos_s1));
uv_s1_01 = saturate(half2(spos_s1 * rcp(zDist) + HALF_ONE) * HALF_HALF);
#endif
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
uv_s1_01 = RemapFoveatedRenderingLinearToNonUniform(uv_s1_01);
}
#endif
// Relative depth of the sample point
float rawDepth_s = SampleDepth(uv_s1_01, DOWNSAMPLE);
float linearDepth_s = GetLinearEyeDepth(rawDepth_s);
// We need to make sure we not use the AO value if the sample point it's outside the radius or if it's the sky...
half halfLinearDepth_s = half(linearDepth_s);
half isInsideRadius = abs(zDist - halfLinearDepth_s) < RADIUS ? 1.0 : 0.0;
isInsideRadius *= rawDepth_s > SKY_DEPTH_VALUE ? 1.0 : 0.0;
// Relative postition of the sample point
half3 v_s2 = half3(ReconstructViewPos(uv_s1_01, linearDepth_s) - centerViewPos);
// Estimate the obscurance value
half dotVal = dot(v_s2, centerNormal) - kBeta * centerHalfLinearDepth;
half a1 = max(dotVal, HALF_ZERO);
half a2 = dot(v_s2, v_s2) + kEpsilon;
ao += a1 * rcp(a2) * isInsideRadius;
}
// Intensity normalization
ao *= RADIUS;
// Calculate falloff...
half falloff = HALF_ONE - centerHalfLinearDepth * half(rcp(FALLOFF));
falloff = falloff*falloff;
// Apply contrast + intensity + falloff^2
ao = PositivePow(saturate(ao * INTENSITY * falloff * rcpSampleCount), kContrast);
// Return the packed ao + normals
return PackAOAndNormal(ao, centerNormal);
}
// ------------------------------------------------------------------
// GTAO (Ground Truth Ambient Occlusion)
// ------------------------------------------------------------------
half4 FragGTAO(Varyings input)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord;
GTAOConfig config = CreateGTAOConfig(_SSAOParams, _SSAOParams2, _AODepthToViewParams, BlueNoiseScale, BlueNoiseOffset, TemporalRotation, TemporalOffset);
float centerRawDepth = SampleDepth(uv, config.downsample);
float centerLinearDepth = GetLinearEyeDepth(centerRawDepth);
half centerHalfLinearDepth = half(centerLinearDepth);
float2 pixelDensity;
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
pixelDensity = RemapFoveatedRenderingDensity(RemapFoveatedRenderingNonUniformToLinear(uv));
}
else
#endif
{
pixelDensity = float2(1.0f, 1.0f);
}
half3 centerNormal = SampleNormal(uv, centerLinearDepth, pixelDensity);
if (ShouldSkipAO(centerRawDepth, centerHalfLinearDepth, config.falloff))
return PackAOAndNormal(HALF_ZERO, centerNormal);
float2 positionSS = GetScreenSpacePosition(uv, config.downsample);
float3 positionVS = GetPositionVS(positionSS, centerRawDepth, config.depthToViewParams);
half3 V = GetViewVectorVS(positionVS);
return EvaluateGTAO(config, uv, positionSS, positionVS, V, centerNormal, centerLinearDepth);
}
// ------------------------------------------------------------------
// Unified SSAO Fragment Shader Entry Point
// ------------------------------------------------------------------
half4 SSAO(Varyings input) : SV_Target
{
#if _GTAO_MODE
return FragGTAO(input);
#else
return FragSSAO(input);
#endif
}
// ------------------------------------------------------------------
// Bilateral Blur
// ------------------------------------------------------------------
// Geometry-aware separable bilateral filter
half4 Blur(const float2 uv, const float2 delta) : SV_Target
{
half4 p0 = SSAO_COMMON_SAMPLE_BASEMAP(uv );
half4 p1a = SSAO_COMMON_SAMPLE_BASEMAP(uv - delta * 1.3846153846);
half4 p1b = SSAO_COMMON_SAMPLE_BASEMAP(uv + delta * 1.3846153846);
half4 p2a = SSAO_COMMON_SAMPLE_BASEMAP(uv - delta * 3.2307692308);
half4 p2b = SSAO_COMMON_SAMPLE_BASEMAP(uv + delta * 3.2307692308);
half3 n0 = GetPackedNormal(p0);
half w0 = half(0.2270270270);
half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * half(0.3162162162);
half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * half(0.3162162162);
half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * half(0.0702702703);
half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * half(0.0702702703);
half s = half(0.0);
s += GetPackedAO(p0) * w0;
s += GetPackedAO(p1a) * w1a;
s += GetPackedAO(p1b) * w1b;
s += GetPackedAO(p2a) * w2a;
s += GetPackedAO(p2b) * w2b;
s *= rcp(w0 + w1a + w1b + w2a + w2b);
return PackAOAndNormal(s, n0);
}
// Geometry-aware bilateral filter (single pass/small kernel)
half BlurSmall(const float2 uv, const float2 delta)
{
half4 p0 = SSAO_COMMON_SAMPLE_BASEMAP(uv );
half4 p1 = SSAO_COMMON_SAMPLE_BASEMAP(uv + float2(-delta.x, -delta.y));
half4 p2 = SSAO_COMMON_SAMPLE_BASEMAP(uv + float2( delta.x, -delta.y));
half4 p3 = SSAO_COMMON_SAMPLE_BASEMAP(uv + float2(-delta.x, delta.y));
half4 p4 = SSAO_COMMON_SAMPLE_BASEMAP(uv + float2( delta.x, delta.y));
half3 n0 = GetPackedNormal(p0);
half w0 = HALF_ONE;
half w1 = CompareNormal(n0, GetPackedNormal(p1));
half w2 = CompareNormal(n0, GetPackedNormal(p2));
half w3 = CompareNormal(n0, GetPackedNormal(p3));
half w4 = CompareNormal(n0, GetPackedNormal(p4));
half s = HALF_ZERO;
s += GetPackedAO(p0) * w0;
s += GetPackedAO(p1) * w1;
s += GetPackedAO(p2) * w2;
s += GetPackedAO(p3) * w3;
s += GetPackedAO(p4) * w4;
return s *= rcp(w0 + w1 + w2 + w3 + w4);
}
half4 HorizontalBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
const float2 uv = input.texcoord;
const float2 delta = float2(_SourceSize.z * rcp(DOWNSAMPLE), 0.0);
return Blur(uv, delta);
}
half4 VerticalBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
const float2 uv = input.texcoord;
const float2 delta = float2(0.0, _SourceSize.w * rcp(DOWNSAMPLE));
return Blur(uv, delta);
}
half4 FinalBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
const float2 uv = input.texcoord;
const float2 delta = _SourceSize.zw * rcp(DOWNSAMPLE);
return HALF_ONE - BlurSmall(uv, delta );
}
// ------------------------------------------------------------------
// Gaussian Blur
// ------------------------------------------------------------------
// https://software.intel.com/content/www/us/en/develop/blogs/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms.html
half GaussianBlur(half2 uv, half2 pixelOffset)
{
half colOut = 0;
// Kernel width 7 x 7
const int stepCount = 2;
const half gWeights[stepCount] ={
0.44908,
0.05092
};
const half gOffsets[stepCount] ={
0.53805,
2.06278
};
UNITY_UNROLL
for( int i = 0; i < stepCount; i++ )
{
half2 texCoordOffset = gOffsets[i] * pixelOffset;
half4 p1 = SSAO_COMMON_SAMPLE_BASEMAP(uv + texCoordOffset);
half4 p2 = SSAO_COMMON_SAMPLE_BASEMAP(uv - texCoordOffset);
half col = p1.r + p2.r;
colOut += gWeights[i] * col;
}
return colOut;
}
half4 HorizontalGaussianBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
half2 uv = input.texcoord;
half2 delta = half2(_SourceSize.z * rcp(DOWNSAMPLE), HALF_ZERO);
half g = GaussianBlur(uv, delta);
return half4(g, g, g, 1);
}
half4 VerticalGaussianBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
half2 uv = input.texcoord;
half2 delta = half2(HALF_ZERO, _SourceSize.w * rcp(DOWNSAMPLE));
half g = HALF_ONE - GaussianBlur(uv, delta);
return half4(g, g, g, 1);
}
// ------------------------------------------------------------------
// Kawase Blur
// ------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Developed by Masaki Kawase, Bunkasha Games
// Used in DOUBLE-S.T.E.A.L. (aka Wreckless)
// From his GDC2003 Presentation: Frame Buffer Postprocessing Effects in DOUBLE-S.T.E.A.L (Wreckless)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
half KawaseBlurFilter( half2 texCoord, half2 pixelSize, half iteration )
{
half2 texCoordSample;
half2 halfPixelSize = pixelSize * HALF_HALF;
half2 dUV = ( pixelSize.xy * half2( iteration, iteration ) ) + halfPixelSize.xy;
half cOut;
// Sample top left pixel
texCoordSample.x = texCoord.x - dUV.x;
texCoordSample.y = texCoord.y + dUV.y;
cOut = SSAO_COMMON_SAMPLE_BASEMAP_R(texCoordSample);
// Sample top right pixel
texCoordSample.x = texCoord.x + dUV.x;
texCoordSample.y = texCoord.y + dUV.y;
cOut += SSAO_COMMON_SAMPLE_BASEMAP_R(texCoordSample);
// Sample bottom right pixel
texCoordSample.x = texCoord.x + dUV.x;
texCoordSample.y = texCoord.y - dUV.y;
cOut += SSAO_COMMON_SAMPLE_BASEMAP_R(texCoordSample);
// Sample bottom left pixel
texCoordSample.x = texCoord.x - dUV.x;
texCoordSample.y = texCoord.y - dUV.y;
cOut += SSAO_COMMON_SAMPLE_BASEMAP_R(texCoordSample);
// Average
cOut *= half(0.25);
return cOut;
}
half4 KawaseBlur(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
half2 uv = input.texcoord;
half2 texelSize = _SourceSize.zw * rcp(DOWNSAMPLE);
half col = KawaseBlurFilter(uv, texelSize, 0);
col = HALF_ONE - col;
return half4(col, col, col, 1);
}
#endif //UNIVERSAL_SSAO_INCLUDED
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 930a5f40803cb414b84db9a1889f890c
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,458 @@
#ifndef UNIVERSAL_SSAO_COMMON_INCLUDED
#define UNIVERSAL_SSAO_COMMON_INCLUDED
// Shared SSAO/GTAO library used by both the fragment path (SSAO.hlsl) and the compute path (GTAO.compute).
// Callers must define the following macros before including this file:
// SSAO_COMMON_SAMPLE_BASEMAP(uv) - sample the AO accumulation texture (rgba)
// SSAO_COMMON_SAMPLE_BASEMAP_R(uv) - sample the AO accumulation texture (r only)
// SSAO_COMMON_SAMPLE_BLUE_NOISE(uv) - sample the blue noise texture
// SSAO_COMMON_FETCH_DEPTH(samplePos, screenSize, ds) - fetch scene depth at a sample position
//
// The compute path (GTAO.compute) additionally defines:
// GTAO_COMPUTE_PATH - guards fragment-only code (SampleDepth, UNITY_UNROLL)
// GTAO_STEP_COUNT - runtime uniform (vs compile-time constant in fragment path)
// GTAO_DIRECTION_COUNT - runtime uniform (vs compile-time constant in fragment path)
#include "Packages/com.unity.render-pipelines.core/Runtime/Sampling/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#define SCREEN_PARAMS GetScaledScreenParams()
// Shared uniform declarations — activated when SSAO_COMMON_DECLARE_UNIFORMS is defined by the caller.
// Functions in this file never read these globals directly; all inputs are passed as explicit parameters.
#ifdef SSAO_COMMON_DECLARE_UNIFORMS
half4 _SSAOParams;
half4 _SSAOParams2;
float4 _AODepthToViewParams;
float4 _SourceSize;
#if defined(_TEMPORAL_FILTERING)
half _SSAOTemporalRotation;
uint _SSAOTemporalOffset; // Valid range: [0,3]
#define TemporalRotation _SSAOTemporalRotation
#define TemporalOffset _SSAOTemporalOffset
#else
static const half TemporalRotation = 0;
static const uint TemporalOffset = 0;
#endif
half _SSAOHistoryLength;
half _SSAOGhostingMitigation;
#if defined(_BLUE_NOISE)
half4 _SSAOBlueNoiseParams;
#define BlueNoiseScale _SSAOBlueNoiseParams.xy
#define BlueNoiseOffset _SSAOBlueNoiseParams.zw
#else
static const half2 BlueNoiseScale = 0;
static const half2 BlueNoiseOffset = 0;
#endif
#endif // SSAO_COMMON_DECLARE_UNIFORMS
// Constants
static const half kContrast = half(0.6);
static const half kGeometryCoeff = half(0.8);
static const half kBeta = half(0.004);
static const half kEpsilon = half(0.0001);
static const float kFalloffFadeStartScale = 0.75;
static const float GOLDEN_RATIO = 1.6180339887;
static const uint R1_ALPHA_UINT = 2654435769u; // (golden_ratio - 1) * (1 << 32)
static const float SKY_DEPTH_VALUE = 0.00001;
static const half HALF_POINT_ONE = half(0.1);
static const half HALF_MINUS_ONE = half(-1.0);
static const half HALF_ZERO = half(0.0);
static const half HALF_HALF = half(0.5);
static const half HALF_ONE = half(1.0);
static const half4 HALF4_ONE = half4(1.0, 1.0, 1.0, 1.0);
static const half HALF_TWO = half(2.0);
static const half HALF_TWO_PI = half(6.28318530717958647693);
static const half HALF_FOUR = half(4.0);
static const half HALF_INV_NINE = half(0.11111111111111111111);
static const half HALF_HUNDRED = half(100.0);
struct GTAOConfig
{
half intensity;
half radius;
half downsample;
half falloff;
float4 depthToViewParams;
half gtaoMinimumRadiusInPixels;
half gtaoFOVCorrection;
half2 blueNoiseScale;
half2 blueNoiseOffset;
half temporalRotation;
uint temporalOffset;
};
GTAOConfig CreateGTAOConfig(half4 ssaoParams, half4 ssaoParams2, float4 depthToViewParams, half2 blueNoiseScale, half2 blueNoiseOffset, half temporalRotation, uint temporalOffset)
{
GTAOConfig config;
config.intensity = ssaoParams.x;
config.radius = ssaoParams.y;
config.downsample = ssaoParams.z;
config.falloff = ssaoParams.w;
config.depthToViewParams = depthToViewParams;
config.gtaoMinimumRadiusInPixels = ssaoParams2.x;
config.gtaoFOVCorrection = ssaoParams2.z;
config.blueNoiseScale = blueNoiseScale;
config.blueNoiseOffset = blueNoiseOffset;
config.temporalRotation = temporalRotation;
config.temporalOffset = temporalOffset;
return config;
}
#ifndef GTAO_COMPUTE_PATH
// For Downsampled SSAO we need to adjust the UV coordinates
// so it hits the center of the pixel inside the depth texture.
// The texelSize multiplier is 1.0 when DOWNSAMPLE is enabled, otherwise 0.0
#define ADJUSTED_DEPTH_UV(uv, downsample) uv.xy + ((_CameraDepthTexture_TexelSize.xy * 0.5) * (1.0 - (downsample - 0.5) * 2.0))
float SampleDepth(float2 uv, half downsample)
{
return SampleSceneDepth(ADJUSTED_DEPTH_UV(uv.xy, downsample));
}
#endif
// ------------------------------------------------------------------
// Shared Helper Functions
// ------------------------------------------------------------------
half4 PackAOAndNormal(half ao, half3 n)
{
n *= HALF_HALF;
n += HALF_HALF;
return half4(ao, n);
}
half3 GetPackedNormal(half4 p)
{
return p.gba * HALF_TWO - HALF_ONE;
}
half GetPackedAO(half4 p)
{
return p.r;
}
half CompareNormal(half3 d1, half3 d2)
{
return smoothstep(kGeometryCoeff, HALF_ONE, dot(d1, d2));
}
float2 GetScreenSpacePosition(float2 uv, half downsample)
{
return float2(uv * SCREEN_PARAMS.xy * downsample);
}
float GetLinearEyeDepth(float rawDepth)
{
#if defined(_ORTHOGRAPHIC)
return LinearDepthToEyeDepth(rawDepth);
#else
return LinearEyeDepth(rawDepth, _ZBufferParams);
#endif
}
float3 GetPositionVS(float2 positionSS, float depth, float4 depthToViewParams)
{
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
positionSS = RemapFoveatedRenderingNonUniformToLinear(positionSS);
}
#endif
float linearDepth = GetLinearEyeDepth(depth);
#if defined(_ORTHOGRAPHIC)
return float3(positionSS * depthToViewParams.xy - depthToViewParams.zw, linearDepth);
#else
return float3((positionSS * depthToViewParams.xy - depthToViewParams.zw) * linearDepth, linearDepth);
#endif
}
// View vector in view space. Orthographic cameras have a constant view direction along -Z.
half3 GetViewVectorVS(float3 positionVS)
{
#if defined(_ORTHOGRAPHIC)
return half3(0, 0, -1);
#else
return half3(normalize(-positionVS));
#endif
}
// Checks if the fragment should skip AO (sky or beyond falloff).
inline bool ShouldSkipAO(float rawDepth, half halfLinearDepth, half falloff)
{
return rawDepth == UNITY_RAW_FAR_CLIP_VALUE || rawDepth < SKY_DEPTH_VALUE || halfLinearDepth > falloff;
}
// Packing.hlsl uses `real`, which can resolve to min16float in this compute path.
// Use float math for history depth packing to avoid precision/overflow issues near 1.0.
float2 PackFloatToR8G8Safe(float value)
{
uint packedBits = (uint)round(saturate(value) * 65535.0);
return float2((packedBits & 0xFFu) / 255.0, ((packedBits >> 8) & 0xFFu) / 255.0);
}
float UnpackFloatFromR8G8Safe(float2 value)
{
uint lo = (uint)round(saturate(value.x) * 255.0);
uint hi = (uint)round(saturate(value.y) * 255.0);
return ((hi << 8) | lo) / 65535.0;
}
float4 CreateHistoryData(float ao, float depth, float reciprocalHistoryFrameCount)
{
float4 historyData;
historyData.xy = PackFloatToR8G8Safe(depth);
historyData.z = saturate(ao);
historyData.w = saturate(reciprocalHistoryFrameCount);
return historyData;
}
// ------------------------------------------------------------------
// Shared GTAO Functions
// ------------------------------------------------------------------
float2 FastAcosGTAO(float2 x)
{
float2 outVal = -0.156583 * abs(x) + HALF_PI;
outVal *= sqrt(saturate(1.0 - abs(x)));
return lerp(PI - outVal, outVal, step(0.0, x));
}
float2 GetDirectionGTAO_BlueNoise(float2 uv, int dirIdx, float rcpDirectionCount, float2 blueNoiseOffset, float2 blueNoiseScale, float temporalRotation)
{
const float lerpVal = float(dirIdx) * rcpDirectionCount;
float noise = SSAO_COMMON_SAMPLE_BLUE_NOISE((uv + blueNoiseOffset) * blueNoiseScale + lerpVal);
#if defined(_TEMPORAL_FILTERING)
noise = frac(noise + temporalRotation);
#endif
const float sliceAngle = (float(dirIdx) + noise) * PI * rcpDirectionCount;
float sinAngle, cosAngle;
sincos(sliceAngle, sinAngle, cosAngle);
return float2(cosAngle, sinAngle);
}
float2 GetDirectionGTAO_IGN(float2 positionSS, int dirIdx, float temporalRotation, half rcpDirectionCount)
{
float noise = InterleavedGradientNoise(positionSS, 0);
#if defined(_TEMPORAL_FILTERING)
static const float rotations[6] = { 60.0, 300.0, 180.0, 240.0, 120.0, 0.0 };
noise = frac(noise + temporalRotation + (rotations[(uint)dirIdx % 6] / 360.0));
#endif
const float sliceAngle = (float(dirIdx) + noise) * PI * rcpDirectionCount;
float sinAngle, cosAngle;
sincos(sliceAngle, sinAngle, cosAngle);
return float2(cosAngle, sinAngle);
}
half GetOffsetGTAO_BlueNoise(float2 uv, half2 blueNoiseOffset, half2 blueNoiseScale, uint temporalOffset)
{
const half blueNoise = SSAO_COMMON_SAMPLE_BLUE_NOISE((uv + blueNoiseOffset) * blueNoiseScale);
// Low-discrepancy step offset via golden ratio
float offset = blueNoise * GOLDEN_RATIO;
#if defined(_TEMPORAL_FILTERING)
static const float offsets[4] = { 0.0, 0.5, 0.25, 0.75 };
offset += offsets[temporalOffset];
#endif
return frac(offset);
}
half GetOffsetGTAO_IGN(uint2 positionSS, uint temporalOffset)
{
#if defined(_TEMPORAL_FILTERING)
// Use a stable 4-phase pattern for temporal accumulation.
float offset = 0.25 * ((positionSS.y - positionSS.x) & 0x3);
static const float offsets[4] = { 0.0, 0.5, 0.25, 0.75 };
offset = frac(offset + offsets[temporalOffset]);
#else
// Different seed than slice angle's IGN to decorrelate X/Y noise.
float offset = InterleavedGradientNoise(float2(positionSS), 1);
#endif
return offset;
}
float GetHorizonAngle(float maxH, float candidateH, float distSq, half invRadiusSq)
{
// Quadratic falloff to zero at radius boundary
half falloff = saturate(1.0 - (distSq * invRadiusSq));
// Raise horizon blended by falloff
return max(maxH, lerp(maxH, candidateH, falloff));
}
void UpdateHorizon(inout float maxHorizon, float2 samplePos, float3 V, float3 positionVS, float sampleDepth, float4 depthToViewParams, half invRadiusSq)
{
float3 samplePosVS = GetPositionVS(samplePos, sampleDepth, depthToViewParams);
float3 deltaPos = samplePosVS - positionVS;
float deltaLenSq = dot(deltaPos, deltaPos);
float currHorizon = dot(deltaPos, V) * rsqrt(deltaLenSq);
maxHorizon = GetHorizonAngle(maxHorizon, currHorizon, deltaLenSq, invRadiusSq);
}
half IntegrateArcCosWeighted(float2 horizonAngles, float n, float sinN, float cosN)
{
// Double the horizon angles for the double-angle cosine terms
float doubledHorizon0 = horizonAngles.x * 2.0;
float doubledHorizon1 = horizonAngles.y * 2.0;
// Analytical cosine-weighted arc integral (GTAO paper)
return 0.25 * ((-cos(doubledHorizon0 - n) + cosN + doubledHorizon0 * sinN) + (-cos(doubledHorizon1 - n) + cosN + doubledHorizon1 * sinN));
}
float2 EstimateSliceVisibility(GTAOConfig config, int dirIdx, float2 uv, float2 positionSS, float3 positionVS, half3 V, float3 normalVS, float fovCorrectedRadiusSS, half invRadiusSq, half rayOffset, half rcpDirectionCount)
{
#if defined(_BLUE_NOISE)
float2 dir = GetDirectionGTAO_BlueNoise(uv, dirIdx, rcpDirectionCount, config.blueNoiseOffset, config.blueNoiseScale, config.temporalRotation);
#else
float2 dir = GetDirectionGTAO_IGN(positionSS, dirIdx, config.temporalRotation, rcpDirectionCount);
#endif
float3 sliceN = normalize(cross(float3(dir.xy, 0.0), V));
float3 projN = normalVS - sliceN * dot(normalVS, sliceN);
float projNLen = length(projN);
float cosN = saturate(dot(projN / projNLen, V));
float3 T = cross(V, sliceN);
float N = -sign(dot(projN, T)) * acos(cosN);
// Per-slice horizon accumulator: x = positive direction, y = negative direction.
float sinN = sin(N);
float2 maxHorizons = float2(sinN, -sinN);
const half2 screenSize = SCREEN_PARAMS.xy * config.downsample;
const float pixelTooCloseThreshold = 1.3;
const float minStepFraction = pixelTooCloseThreshold / fovCorrectedRadiusSS;
const float rcpStepCount = rcp(GTAO_STEP_COUNT);
// Single step loop driving both directions. Step stride/noise computed once and reused.
// Unroll for performance on the fragment path. On the compute path, keep the loop dynamic to support runtime quality settings.
#ifndef GTAO_COMPUTE_PATH
UNITY_UNROLL
#endif
for (int stepIdx = 0; stepIdx < GTAO_STEP_COUNT; stepIdx++)
{
// R1 sequence using integer arithmetic for bit-exact frac()
uint stepSeed = uint(dirIdx + stepIdx * GTAO_STEP_COUNT) * R1_ALPHA_UINT;
float stepNoise = frac(rayOffset + UintToFloat01(stepSeed));
float rayStep = (float(stepIdx) + stepNoise) * rcpStepCount;
rayStep = rayStep * rayStep + minStepFraction;
float2 stepVec = round(rayStep * fovCorrectedRadiusSS * dir);
// positive direction
float2 samplePos = positionSS + stepVec;
float sampleDepth = SSAO_COMMON_FETCH_DEPTH(samplePos, screenSize, config.downsample);
UpdateHorizon(maxHorizons.x, samplePos, V, positionVS, sampleDepth, config.depthToViewParams, invRadiusSq);
// negative direction
samplePos = positionSS - stepVec;
sampleDepth = SSAO_COMMON_FETCH_DEPTH(samplePos, screenSize, config.downsample);
UpdateHorizon(maxHorizons.y, samplePos, V, positionVS, sampleDepth, config.depthToViewParams, invRadiusSq);
}
// Convert horizon cosines to signed angles relative to slice normal N.
float2 horizonAcos = FastAcosGTAO(maxHorizons);
maxHorizons.x = N + max(-horizonAcos.x - N, -HALF_PI);
maxHorizons.y = N + min( horizonAcos.y - N, HALF_PI);
// (visibility, maxVisibility) summed across slices and divided once by the caller.
// maxVisibility = the integral with horizons fully open, normalizing visibility into [0, 1].
return float2(projNLen * IntegrateArcCosWeighted(maxHorizons, N, sinN, cosN), projNLen * (N * sinN + cosN));
}
half EvaluateGTAOValue(GTAOConfig config, float2 uv, float2 positionSS, float3 positionVS, half3 V, half3 normal, float linearDepth)
{
float3 normalVS = TransformWorldToViewNormal(normal);
normalVS = float3(normalVS.xy, -normalVS.z);
// Shrink origin toward camera at grazing angles to avoid the surface itself being a horizon.
positionVS *= lerp(0.997, 1.0, abs(dot(normalVS, V)));
#if defined(_ORTHOGRAPHIC)
float fovCorrectedRadiusSS = max(config.radius * config.gtaoFOVCorrection, config.gtaoMinimumRadiusInPixels);
float invEffectiveRadius = config.gtaoFOVCorrection / fovCorrectedRadiusSS;
#else
float fovCorrectedRadiusSS = max(config.radius * config.gtaoFOVCorrection * rcp(linearDepth), config.gtaoMinimumRadiusInPixels);
float invEffectiveRadius = config.gtaoFOVCorrection / (fovCorrectedRadiusSS * linearDepth);
#endif
half invRadiusSq = invEffectiveRadius * invEffectiveRadius;
#if defined(_BLUE_NOISE)
half rayOffset = GetOffsetGTAO_BlueNoise(uv, config.blueNoiseOffset, config.blueNoiseScale, config.temporalOffset);
#else
half rayOffset = GetOffsetGTAO_IGN((uint2)positionSS, config.temporalOffset);
#endif
const half rcpDirectionCount = half(rcp(GTAO_DIRECTION_COUNT));
float2 acc = 0;
// Unroll for performance on the fragment path. On the compute path, keep the loop dynamic to support runtime quality settings.
#if !defined(GTAO_COMPUTE_PATH)
UNITY_UNROLL
#endif
for (int dirIdx = 0; dirIdx < GTAO_DIRECTION_COUNT; dirIdx++)
{
acc += EstimateSliceVisibility(config, dirIdx, uv, positionSS, positionVS, V, normalVS, fovCorrectedRadiusSS, invRadiusSq, rayOffset, rcpDirectionCount);
}
half integral = acc.y > half(1e-5) ? saturate(acc.x / acc.y) : HALF_ONE;
half ao = HALF_ONE - PositivePow(integral, config.intensity);
half fadeFactor = smoothstep(config.falloff * kFalloffFadeStartScale, config.falloff, linearDepth);
ao *= (HALF_ONE - fadeFactor);
return ao;
}
half4 EvaluateGTAO(GTAOConfig config, float2 uv, float2 positionSS, float3 positionVS, half3 V, half3 normal, float linearDepth)
{
half ao = EvaluateGTAOValue(config, uv, positionSS, positionVS, V, normal, linearDepth);
// Return the packed ao + normals
return PackAOAndNormal(ao, normal);
}
// ------------------------------------------------------------------
// Shared Temporal Filter
// ------------------------------------------------------------------
void ResolverAABB(half aabbScale, half2 uv, half2 screenSize,
inout half minColor, inout half maxColor, inout half filterColor)
{
half2 texelSize = rcp(screenSize);
half s00 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2(-1, -1) * texelSize);
half s10 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2( 0, -1) * texelSize);
half s20 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2( 1, -1) * texelSize);
half s01 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2(-1, 0) * texelSize);
half s11 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2( 0, 0) * texelSize); // center
half s21 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2( 1, 0) * texelSize);
half s02 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2(-1, 1) * texelSize);
half s12 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2( 0, 1) * texelSize);
half s22 = SSAO_COMMON_SAMPLE_BASEMAP_R(uv + half2( 1, 1) * texelSize);
// Gaussian weighted filtering (3x3 kernel)
static const half cornerWeight = 0.0625h; // 1.0h / 16.0h
static const half edgeWeight = 0.125h; // 2.0h / 16.0h
static const half centerWeight = 0.25h; // 4.0h / 16.0h
half filtered = s00 * cornerWeight + s10 * edgeWeight + s20 * cornerWeight
+ s01 * edgeWeight + s11 * centerWeight + s21 * edgeWeight
+ s02 * cornerWeight + s12 * edgeWeight + s22 * cornerWeight;
// Variance-based AABB
half m1 = s00 + s10 + s20 + s01 + s11 + s21 + s02 + s12 + s22;
half m2 = s00*s00 + s10*s10 + s20*s20 + s01*s01 + s11*s11 + s21*s21 + s02*s02 + s12*s12 + s22*s22;
half mean = m1 * HALF_INV_NINE;
half stddev = sqrt(max(0, m2 * HALF_INV_NINE - mean * mean));
minColor = mean - aabbScale * stddev;
maxColor = mean + aabbScale * stddev;
filterColor = filtered;
minColor = min(minColor, filtered);
maxColor = max(maxColor, filtered);
}
#endif //UNIVERSAL_SSAO_COMMON_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: effce4cba4eecea489c4b17e1eb3825e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,41 @@
#ifndef SAMPLE_SCREEN_SPACE_REFLECTION_INCLUDED
#define SAMPLE_SCREEN_SPACE_REFLECTION_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ScreenSpaceReflectionCommon.hlsl"
// SSR reflection color
TEXTURE2D_X(_ScreenSpaceReflectionTexture);
half4 SampleScreenSpaceReflection(float2 normalizedScreenSpaceUV, float3 positionWS, float perceptualRoughness)
{
float2 uv = UnityStereoTransformScreenSpaceTex(normalizedScreenSpaceUV);
// Fade out reflections for pixels that have smoothness below our minimum.
float perceptualSmoothness = PerceptualRoughnessToPerceptualSmoothness(perceptualRoughness);
float fadeStart = _ScreenSpaceReflectionParam.y;
float fadeEnd = _ScreenSpaceReflectionParam.z;
float fade = smoothstep(fadeStart, fadeEnd, perceptualSmoothness);
float4 reflColor = float4(0,0,0,0);
if (fade > 1e-3)
{
// Map roughness to mip level to get blur.
float mipLevel = GetSSRMipLevelFromPerceptualRoughness(positionWS, perceptualRoughness);
reflColor = SAMPLE_TEXTURE2D_X_LOD(_ScreenSpaceReflectionTexture, sampler_TrilinearClamp, uv, mipLevel);
reflColor.a *= fade;
}
return reflColor;
}
half4 GetScreenSpaceReflection(float2 normalizedScreenSpaceUV, float3 positionWS, float perceptualRoughness)
{
#if _SCREEN_SPACE_REFLECTION_KEYWORD_DECLARED
if (_SCREEN_SPACE_REFLECTION)
return SampleScreenSpaceReflection(normalizedScreenSpaceUV, positionWS, perceptualRoughness) * _ScreenSpaceReflectionParam.x;
else
#endif
return 0;
}
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 229e2e6b5e442024a819f1a5bc578442
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,84 @@
#ifndef SCREEN_SPACE_REFLECTION_COMMON_INCLUDED
#define SCREEN_SPACE_REFLECTION_COMMON_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
//#define SSR_USE_DISTANCE_BASED_BLUR
static const float k_SSRBlurReferenceDistance = 1.0;
// x : Blurriness - Exposed as a volume parameter; see ScreenSpaceReflectionVolumeSettings.blurriness.
// y : Delta between the screen Space Reflection texture last mip index and a reference last mip index.
// z : Screen Space Reflection texture last valid mip index
// w : Unused
float4 _ScreenSpaceReflectionParam2;
float GetSSRBlurriness()
{
return _ScreenSpaceReflectionParam2.x;
}
float GetSSRTextureMipOffset()
{
return _ScreenSpaceReflectionParam2.y;
}
float GetSSRTextureLastValidMipIndex()
{
return _ScreenSpaceReflectionParam2.z;
}
float GetSSRBlurConeHalfAngle(float perceptualRoughness)
{
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
// Ref: "Moving Frostbite to PBR", p. 72. But using a different E value to match the reflection probe
// roughness curve.
//
// const float e = 0.85;
// return atan(e*roughness/(1.0 - e));
// (Hopefully) Faster polynomial approximation of above
float shininess = 1.0 - roughness;
float shininess2 = shininess * shininess;
return 0.2094 * (roughness + 5.6667 * (1.0 - shininess2 * shininess2));
}
float GetSSRMipLevelFromPerceptualRoughness(float3 positionWS, float perceptualRoughness)
{
// Map perceptual roughness to a blur cone radius
float blurConeAngle = GetSSRBlurConeHalfAngle(perceptualRoughness);
float blurRadius = GetSSRBlurriness() * tan(blurConeAngle);
#ifdef SSR_USE_DISTANCE_BASED_BLUR
// Adjust based on camera distance
if (IsPerspectiveProjection())
{
float fragZ = TransformWorldToView(positionWS).z;
// Assume we have the blur radius at a distance BLUR_REFERENCE_DISTANCE to the camera and divide this radius
// by 2 if the ratio between that reference distance and the fragment Z doubles.
const float k_MinimumZ = 0.01;
float scalingRatio = k_SSRBlurReferenceDistance / max(k_MinimumZ, abs(fragZ));
blurRadius *= scalingRatio;
}
else
{
// TODO : handle orthographic projection. see https://jira.unity3d.com/browse/GFXLIGHT-1849
}
#endif
// Map this blur radius back to a mip level, but assuming the reference resolution.
const float k_MinimumRadius = 0.001;
float mipLevel = log2(max(k_MinimumRadius, blurRadius));
// Adjust for resolution: shift that mip by the difference between the actual SSR mip count and the reference one,
// so the same material roughness produces approximately the same screen-space blur in pixels regardless of
// reflection buffer resolution. The minimum-radius clamp keeps roughness 0 at mip 0 up to resolutions of
// k_SSRBlurReferenceResolution * 2^-log2(k_MinimumRadius) ~= 1024 * 1024 = 1M pixels wide. The subtraction below
// keeps roughness 1 at the highest mip level.
mipLevel += GetSSRTextureMipOffset();
return clamp(mipLevel, 0, GetSSRTextureLastValidMipIndex());
}
#endif
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d39ce33cadd344129a28bf89a1b8e4e4
timeCreated: 1773851159
@@ -0,0 +1,171 @@
#ifndef UNITY_GRAPHFUNCTIONS_LW_INCLUDED
#define UNITY_GRAPHFUNCTIONS_LW_INCLUDED
#define SHADERGRAPH_SAMPLE_SCENE_DEPTH(uv) shadergraph_LWSampleSceneDepth(uv)
#define SHADERGRAPH_SAMPLE_SCENE_COLOR(uv) shadergraph_LWSampleSceneColor(uv)
#define SHADERGRAPH_SAMPLE_SCENE_NORMAL(uv) shadergraph_LWSampleSceneNormals(uv)
#define SHADERGRAPH_BAKED_GI(positionWS, normalWS, positionSS, uvStaticLightmap, uvDynamicLightmap, applyScaling) shadergraph_LWBakedGI(positionWS, normalWS, positionSS, uvStaticLightmap, uvDynamicLightmap, applyScaling)
#define SHADERGRAPH_REFLECTION_PROBE(viewDir, normalOS, lod) shadergraph_LWReflectionProbe(viewDir, normalOS, lod)
#define SHADERGRAPH_FOG(position, color, density) shadergraph_LWFog(position, color, density)
#define SHADERGRAPH_AMBIENT_SKY unity_AmbientSky
#define SHADERGRAPH_AMBIENT_EQUATOR unity_AmbientEquator
#define SHADERGRAPH_AMBIENT_GROUND unity_AmbientGround
#define SHADERGRAPH_MAIN_LIGHT_DIRECTION shadergraph_URPMainLightDirection
#define SHADERGRAPH_RENDERER_BOUNDS_MIN shadergraph_RendererBoundsWS_Min()
#define SHADERGRAPH_RENDERER_BOUNDS_MAX shadergraph_RendererBoundsWS_Max()
#if defined(REQUIRE_DEPTH_TEXTURE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#endif
#if defined(REQUIRE_OPAQUE_TEXTURE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl"
#endif
#if defined(REQUIRE_NORMAL_TEXTURE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
#endif
float shadergraph_LWSampleSceneDepth(float2 uv)
{
#if defined(REQUIRE_DEPTH_TEXTURE)
return SampleSceneDepth(uv);
#else
return 0;
#endif
}
#if defined(_DEPTH_AS_INPUT_ATTACHMENT)
float shadergraph_LWFetchSceneDepth(float2 fragCoord)
{
#if defined(REQUIRE_DEPTH_TEXTURE)
return FetchSceneDepth(fragCoord);
#else
return 0;
#endif
}
#elif defined(_DEPTH_AS_INPUT_ATTACHMENT_MSAA)
float shadergraph_LWFetchSceneDepth(float2 fragCoord)
{
#if defined(REQUIRE_DEPTH_TEXTURE)
return FetchSceneDepth(fragCoord, 0);
#else
return 0;
#endif
}
#endif
float3 shadergraph_LWSampleSceneColor(float2 uv)
{
#if defined(REQUIRE_OPAQUE_TEXTURE)
return SampleSceneColor(uv);
#else
return 0;
#endif
}
float3 shadergraph_LWSampleSceneNormals(float2 uv)
{
#if defined(REQUIRE_NORMAL_TEXTURE)
return SampleSceneNormals(uv);
#else
return 0;
#endif
}
float3 shadergraph_LWBakedGI(float3 positionWS, float3 normalWS, uint2 positionSS, float2 uvStaticLightmap, float2 uvDynamicLightmap, bool applyScaling)
{
#ifdef LIGHTMAP_ON
if (applyScaling)
{
uvStaticLightmap = uvStaticLightmap * unity_LightmapST.xy + unity_LightmapST.zw;
uvDynamicLightmap = uvDynamicLightmap * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
}
#if defined(DYNAMICLIGHTMAP_ON)
return SampleLightmap(uvStaticLightmap, uvDynamicLightmap, normalWS);
#else
return SampleLightmap(uvStaticLightmap, normalWS);
#endif
#else
#if (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
if (_EnableProbeVolumes)
{
float3 bakeDiffuseLighting;
EvaluateAdaptiveProbeVolume(positionWS, normalWS, GetWorldSpaceNormalizeViewDir(positionWS), positionSS, bakeDiffuseLighting);
return bakeDiffuseLighting;
}
else
return SampleSH(normalWS);
#else
return SampleSH(normalWS);
#endif
#endif
}
float3 shadergraph_LWReflectionProbe(float3 viewDir, float3 normalOS, float lod)
{
float3 reflectVec = reflect(-viewDir, normalOS);
#if USE_CLUSTER_LIGHT_LOOP
return SAMPLE_TEXTURECUBE_LOD(_GlossyEnvironmentCubeMap, sampler_GlossyEnvironmentCubeMap, reflectVec, lod).rgb;
#else
return DecodeHDREnvironment(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVec, lod), unity_SpecCube0_HDR);
#endif
}
void shadergraph_LWFog(float3 positionOS, out float4 color, out float density)
{
color = unity_FogColor;
density = 0.0f;
#if defined(FOG_LINEAR_KEYWORD_DECLARED)
if (FOG_LINEAR || FOG_EXP || FOG_EXP2)
{
float viewZ = -TransformWorldToView(TransformObjectToWorld(positionOS)).z;
float nearZ0ToFarZ = max(viewZ - _ProjectionParams.y, 0);
// ComputeFogFactorZ0ToFar returns the fog "occlusion" (0 for full fog and 1 for no fog) so this has to be inverted for density.
density = 1.0f - ComputeFogIntensity(ComputeFogFactorZ0ToFar(nearZ0ToFarZ));
}
#endif // defined(FOG_LINEAR_KEYWORD_DECLARED)
}
// This function assumes the bitangent flip is encoded in tangentWS.w
float3x3 BuildTangentToWorld(float4 tangentWS, float3 normalWS)
{
// tangentWS must not be normalized (mikkts requirement)
// Normalize normalWS vector but keep the renormFactor to apply it to bitangent and tangent
float3 unnormalizedNormalWS = normalWS;
float renormFactor = 1.0 / length(unnormalizedNormalWS);
// bitangent on the fly option in xnormal to reduce vertex shader outputs.
// this is the mikktspace transformation (must use unnormalized attributes)
float3x3 tangentToWorld = CreateTangentToWorld(unnormalizedNormalWS, tangentWS.xyz, tangentWS.w > 0.0 ? 1.0 : -1.0);
// surface gradient based formulation requires a unit length initial normal. We can maintain compliance with mikkts
// by uniformly scaling all 3 vectors since normalization of the perturbed normal will cancel it.
tangentToWorld[0] = tangentToWorld[0] * renormFactor;
tangentToWorld[1] = tangentToWorld[1] * renormFactor;
tangentToWorld[2] = tangentToWorld[2] * renormFactor; // normalizes the interpolated vertex normal
return tangentToWorld;
}
float3 shadergraph_URPMainLightDirection()
{
return -GetMainLight().direction;
}
float3 shadergraph_RendererBoundsWS_Min()
{
return GetCameraRelativePositionWS(unity_RendererBounds_Min.xyz);
}
float3 shadergraph_RendererBoundsWS_Max()
{
return GetCameraRelativePositionWS(unity_RendererBounds_Max.xyz);
}
// Always include Shader Graph version
// Always include last to avoid double macros
#include "Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl"
#endif // UNITY_GRAPHFUNCTIONS_LW_INCLUDED
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 9adc879d74aec4400bbdce89ff664a05
timeCreated: 1488965025
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,45 @@
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Contains structs used for shader input.
/// </summary>
public static partial class ShaderInput
{
/// <summary>
/// Container struct for various data used for lights in URP.
/// </summary>
[GenerateHLSL(PackingRules.Exact, false)]
public struct LightData
{
/// <summary>
/// The position of the light.
/// </summary>
public Vector4 position;
/// <summary>
/// The color of the light.
/// </summary>
public Vector4 color;
/// <summary>
/// The attenuation of the light.
/// </summary>
public Vector4 attenuation;
/// <summary>
/// The direction of the light (Spot light).
/// </summary>
public Vector4 spotDirection;
/// <summary>
/// The channel for probe occlusion.
/// </summary>
public Vector4 occlusionProbeChannels;
/// <summary>
/// The layer mask used.
/// </summary>
public uint layerMask;
}
}
}
@@ -0,0 +1,20 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef SHADERTYPES_CS_HLSL
#define SHADERTYPES_CS_HLSL
// Generated from UnityEngine.Rendering.Universal.ShaderInput+LightData
// PackingRules = Exact
struct LightData
{
float4 position;
float4 color;
float4 attenuation;
float4 spotDirection;
float4 occlusionProbeChannels;
uint layerMask;
};
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6be8cfeb6b34eca43b000cb7bad7255e
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f82f912becb8b444f8f6c886f823bea6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More