A game about forced loneliness, made by TACStudios
1#ifndef UNITY_ENTITY_LIGHTING_INCLUDED 2#define UNITY_ENTITY_LIGHTING_INCLUDED 3 4#if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH || defined(UNITY_UNIFIED_SHADER_PRECISION_MODEL) 5#pragma warning (disable : 3205) // conversion of larger type to smaller 6#endif 7 8#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" 9#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" 10#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SphericalHarmonics.hlsl" 11 12#define LIGHTMAP_RGBM_MAX_GAMMA real(5.0) // NB: Must match value in RGBMRanges.h 13#define LIGHTMAP_RGBM_MAX_LINEAR real(34.493242) // LIGHTMAP_RGBM_MAX_GAMMA ^ 2.2 14 15#ifdef UNITY_LIGHTMAP_RGBM_ENCODING 16 #ifdef UNITY_COLORSPACE_GAMMA 17 #define LIGHTMAP_HDR_MULTIPLIER LIGHTMAP_RGBM_MAX_GAMMA 18 #define LIGHTMAP_HDR_EXPONENT real(1.0) // Not used in gamma color space 19 #else 20 #define LIGHTMAP_HDR_MULTIPLIER LIGHTMAP_RGBM_MAX_LINEAR 21 #define LIGHTMAP_HDR_EXPONENT real(2.2) 22 #endif 23#elif defined(UNITY_LIGHTMAP_DLDR_ENCODING) 24 #ifdef UNITY_COLORSPACE_GAMMA 25 #define LIGHTMAP_HDR_MULTIPLIER real(2.0) 26 #else 27 #define LIGHTMAP_HDR_MULTIPLIER real(4.59) // 2.0 ^ 2.2 28 #endif 29 #define LIGHTMAP_HDR_EXPONENT real(0.0) 30#else // (UNITY_LIGHTMAP_FULL_HDR) 31 #define LIGHTMAP_HDR_MULTIPLIER real(1.0) 32 #define LIGHTMAP_HDR_EXPONENT real(1.0) 33#endif 34 35// This sample a 3D volume storing SH 36// Volume is store as 3D texture with 4 R, G, B, Occ set of 4 coefficient store atlas in same 3D texture. Occ is use for occlusion. 37// TODO: the packing here is inefficient as we will fetch values far away from each other and they may not fit into the cache - Suggest we pack RGB continuously 38// TODO: The calcul of texcoord could be perform with a single matrix multicplication calcualted on C++ side that will fold probeVolumeMin and probeVolumeSizeInv into it and handle the identity case, no reasons to do it in C++ (ask Ionut about it) 39// It should also handle the camera relative path (if the render pipeline use it) 40// bakeDiffuseLighting and backBakeDiffuseLighting must be initialize outside the function 41void SampleProbeVolumeSH4(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float3 backNormalWS, float4x4 WorldToTexture, 42 float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv, 43 inout float3 bakeDiffuseLighting, inout float3 backBakeDiffuseLighting) 44{ 45 float3 position = (transformToLocal == 1.0) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS; 46 float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz; 47 // Each component is store in the same texture 3D. Each use one quater on the x axis 48 // Here we get R component then increase by step size (0.25) to get other component. This assume 4 component 49 // but last one is not used. 50 // Clamp to edge of the "internal" texture, as R is from half texel to size of R texture minus half texel. 51 // This avoid leaking 52 texCoord.x = clamp(texCoord.x * 0.25, 0.5 * texelSizeX, 0.25 - 0.5 * texelSizeX); 53 54 float4 shAr = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0); 55 texCoord.x += 0.25; 56 float4 shAg = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0); 57 texCoord.x += 0.25; 58 float4 shAb = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0); 59 60 bakeDiffuseLighting += SHEvalLinearL0L1(normalWS, shAr, shAg, shAb); 61 backBakeDiffuseLighting += SHEvalLinearL0L1(backNormalWS, shAr, shAg, shAb); 62} 63 64// Just a shortcut that call function above 65float3 SampleProbeVolumeSH4(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture, 66 float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv) 67{ 68 float3 backNormalWSUnused = 0.0; 69 float3 bakeDiffuseLighting = 0.0; 70 float3 backBakeDiffuseLightingUnused = 0.0; 71 SampleProbeVolumeSH4(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), positionWS, normalWS, backNormalWSUnused, WorldToTexture, 72 transformToLocal, texelSizeX, probeVolumeMin, probeVolumeSizeInv, 73 bakeDiffuseLighting, backBakeDiffuseLightingUnused); 74 return bakeDiffuseLighting; 75} 76 77// The SphericalHarmonicsL2 coefficients are packed into 7 coefficients per color channel instead of 9. 78// The packing from 9 to 7 is done from engine code and will use the alpha component of the pixel to store an additional SH coefficient. 79// The 3D atlas texture will contain 7 SH coefficient parts. 80// bakeDiffuseLighting and backBakeDiffuseLighting must be initialize outside the function 81void SampleProbeVolumeSH9(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float3 backNormalWS, float4x4 WorldToTexture, 82 float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv, 83 inout float3 bakeDiffuseLighting, inout float3 backBakeDiffuseLighting) 84{ 85 float3 position = (transformToLocal == 1.0f) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS; 86 float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv; 87 88 const uint shCoeffCount = 7; 89 const float invShCoeffCount = 1.0f / float(shCoeffCount); 90 91 // We need to compute proper X coordinate to sample into the atlas. 92 texCoord.x = texCoord.x / shCoeffCount; 93 94 // Clamp the x coordinate otherwise we'll have leaking between RGB coefficients. 95 float texCoordX = clamp(texCoord.x, 0.5f * texelSizeX, invShCoeffCount - 0.5f * texelSizeX); 96 97 float4 SHCoefficients[7]; 98 99 for (uint i = 0; i < shCoeffCount; i++) 100 { 101 texCoord.x = texCoordX + i * invShCoeffCount; 102 SHCoefficients[i] = SAMPLE_TEXTURE3D_LOD(SHVolumeTexture, SHVolumeSampler, texCoord, 0); 103 } 104 105 bakeDiffuseLighting += SampleSH9(SHCoefficients, normalize(normalWS)); 106 backBakeDiffuseLighting += SampleSH9(SHCoefficients, normalize(backNormalWS)); 107} 108 109// Just a shortcut that call function above 110float3 SampleProbeVolumeSH9(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float3 normalWS, float4x4 WorldToTexture, 111 float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv) 112{ 113 float3 backNormalWSUnused = 0.0; 114 float3 bakeDiffuseLighting = 0.0; 115 float3 backBakeDiffuseLightingUnused = 0.0; 116 SampleProbeVolumeSH9(TEXTURE3D_ARGS(SHVolumeTexture, SHVolumeSampler), positionWS, normalWS, backNormalWSUnused, WorldToTexture, 117 transformToLocal, texelSizeX, probeVolumeMin, probeVolumeSizeInv, 118 bakeDiffuseLighting, backBakeDiffuseLightingUnused); 119 return bakeDiffuseLighting; 120} 121 122float4 SampleProbeOcclusion(TEXTURE3D_PARAM(SHVolumeTexture, SHVolumeSampler), float3 positionWS, float4x4 WorldToTexture, 123 float transformToLocal, float texelSizeX, float3 probeVolumeMin, float3 probeVolumeSizeInv) 124{ 125 float3 position = (transformToLocal == 1.0) ? mul(WorldToTexture, float4(positionWS, 1.0)).xyz : positionWS; 126 float3 texCoord = (position - probeVolumeMin) * probeVolumeSizeInv.xyz; 127 128 // Sample fourth texture in the atlas 129 // We need to compute proper U coordinate to sample. 130 // Clamp the coordinate otherwize we'll have leaking between ShB coefficients and Probe Occlusion(Occ) info 131 texCoord.x = max(texCoord.x * 0.25 + 0.75, 0.75 + 0.5 * texelSizeX); 132 133 return SAMPLE_TEXTURE3D(SHVolumeTexture, SHVolumeSampler, texCoord); 134} 135 136// Following functions are to sample enlighten lightmaps (or lightmaps encoded the same way as our 137// enlighten implementation). They assume use of RGB9E5 for dynamic illuminance map and RGBM for baked ones. 138// It is required for other platform that aren't supporting this format to implement variant of these functions 139// (But these kind of platform should use regular render loop and not news shaders). 140 141// TODO: This is the max value allowed for emissive (bad name - but keep for now to retrieve it) (It is 8^2.2 (gamma) and 8 is the limit of punctual light slider...), comme from UnityCg.cginc. Fix it! 142// Ask Jesper if this can be change for HDRenderPipeline 143#define EMISSIVE_RGBM_SCALE 97.0 144 145// RGBM stuff is temporary. For now baked lightmap are in RGBM and the RGBM range for lightmaps is specific so we can't use the generic method. 146// In the end baked lightmaps are going to be BC6H so the code will be the same as dynamic lightmaps. 147// Same goes for emissive packed as an input for Enlighten with another hard coded multiplier. 148 149// TODO: This function is used with the LightTransport pass to encode lightmap or emissive 150real4 PackEmissiveRGBM(real3 rgb) 151{ 152 real kOneOverRGBMMaxRange = 1.0 / EMISSIVE_RGBM_SCALE; 153 const real kMinMultiplier = 2.0 * 1e-2; 154 155 real4 rgbm = real4(rgb * kOneOverRGBMMaxRange, 1.0); 156 rgbm.a = max(max(rgbm.r, rgbm.g), max(rgbm.b, kMinMultiplier)); 157 rgbm.a = ceil(rgbm.a * 255.0) / 255.0; 158 159 // Division-by-zero warning from d3d9, so make compiler happy. 160 rgbm.a = max(rgbm.a, kMinMultiplier); 161 162 rgbm.rgb /= rgbm.a; 163 return rgbm; 164} 165 166real3 UnpackLightmapRGBM(real4 rgbmInput, real4 decodeInstructions) 167{ 168#ifdef UNITY_COLORSPACE_GAMMA 169 return rgbmInput.rgb * (rgbmInput.a * decodeInstructions.x); 170#else 171 return rgbmInput.rgb * (PositivePow(rgbmInput.a, decodeInstructions.y) * decodeInstructions.x); 172#endif 173} 174 175real3 UnpackLightmapDoubleLDR(real4 encodedColor, real4 decodeInstructions) 176{ 177 return encodedColor.rgb * decodeInstructions.x; 178} 179 180#ifndef BUILTIN_TARGET_API 181real3 DecodeLightmap(real4 encodedIlluminance, real4 decodeInstructions) 182{ 183#if defined(UNITY_LIGHTMAP_RGBM_ENCODING) 184 return UnpackLightmapRGBM(encodedIlluminance, decodeInstructions); 185#elif defined(UNITY_LIGHTMAP_DLDR_ENCODING) 186 return UnpackLightmapDoubleLDR(encodedIlluminance, decodeInstructions); 187#else // (UNITY_LIGHTMAP_FULL_HDR) 188 return encodedIlluminance.rgb; 189#endif 190} 191#endif 192 193real3 DecodeHDREnvironment(real4 encodedIrradiance, real4 decodeInstructions) 194{ 195 // Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels) 196 real alpha = max(decodeInstructions.w * (encodedIrradiance.a - 1.0) + 1.0, 0.0); 197 198 // If Linear mode is not supported we can skip exponent part 199 return (decodeInstructions.x * PositivePow(alpha, decodeInstructions.y)) * encodedIrradiance.rgb; 200} 201 202#if defined(UNITY_DOTS_INSTANCING_ENABLED) && !defined(USE_LEGACY_LIGHTMAPS) 203// ^ GPU-driven rendering is enabled, and we haven't opted-out from lightmap 204// texture arrays. This minimizes batch breakages, but texture arrays aren't 205// supported in a performant way on all GPUs. 206#define TEXTURE2D_LIGHTMAP_PARAM TEXTURE2D_ARRAY_PARAM 207#define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARRAY_ARGS 208#define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D_ARRAY 209#define LIGHTMAP_EXTRA_ARGS float2 uv, float slice 210#define LIGHTMAP_EXTRA_ARGS_USE uv, slice 211#else 212// ^ Lightmaps are not bound as texture arrays, but as individual textures. The 213// batch is broken every time lightmaps are changed, but this is well-supported 214// on all GPUs. 215#define TEXTURE2D_LIGHTMAP_PARAM TEXTURE2D_PARAM 216#define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARGS 217#define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D 218#define LIGHTMAP_EXTRA_ARGS float2 uv 219#define LIGHTMAP_EXTRA_ARGS_USE uv 220#endif 221 222// For the built-in target, lightmaps are defined with half precision. 223// Unfortunately, TEXTURE2D_Half_PARAM is not defined. 224#ifdef BUILTIN_TARGET_API 225#undef TEXTURE2D_LIGHTMAP_PARAM 226#undef TEXTURE2D_LIGHTMAP_ARGS 227#undef SAMPLE_TEXTURE2D_LIGHTMAP 228 229#ifdef SHADER_API_GLES 230#define TEXTURE2D_LIGHTMAP_PARAM(textureName, samplerName) TEXTURE2D_HALF(textureName) 231#else 232#define TEXTURE2D_LIGHTMAP_PARAM(textureName, samplerName) TEXTURE2D_HALF(textureName), SAMPLER(samplerName) 233#endif 234 235#define TEXTURE2D_LIGHTMAP_ARGS TEXTURE2D_ARGS 236#define SAMPLE_TEXTURE2D_LIGHTMAP SAMPLE_TEXTURE2D 237#endif 238 239// isStaticLightmap mean it is not an Enlighten map 240real3 SampleSingleLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, bool isStaticLightmap) 241{ 242 real4 decodeInstructions = real4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0, 0.0); 243 244 // transform is scale and bias 245 uv = uv * transform.xy + transform.zw; 246 real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba; 247 // Remark: static lightmap is RGBM for now, dynamic lightmap is RGB9E5 248 real3 illuminance = isStaticLightmap ? DecodeLightmap(encodedIlluminance, decodeInstructions) : encodedIlluminance.rgb; 249 250 return illuminance; 251} 252 253// deprecated 254real3 SampleSingleLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, bool isStaticLightmap, real4 ignore) 255{ 256 return SampleSingleLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS_USE, transform, isStaticLightmap); 257} 258 259void SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, 260 float3 normalWS, float3 backNormalWS, bool isStaticLightmap, inout real3 bakeDiffuseLighting, inout real3 backBakeDiffuseLighting) 261{ 262 // In directional mode Enlighten bakes dominant light direction 263 // in a way, that using it for half Lambert and then dividing by a "rebalancing coefficient" 264 // gives a result close to plain diffuse response lightmaps, but normalmapped. 265 266 // Note that dir is not unit length on purpose. Its length is "directionality", like 267 // for the directional specular lightmaps. 268 269 real3 illuminance = SampleSingleLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS_USE, transform, isStaticLightmap); 270 271 // transform is scale and bias 272 uv = uv * transform.xy + transform.zw; 273 274 real4 direction = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapDirTex, lightmapDirSampler, LIGHTMAP_EXTRA_ARGS_USE); 275 276 real halfLambert = dot(normalWS, direction.xyz - 0.5) + 0.5; 277 bakeDiffuseLighting += illuminance * halfLambert / max(1e-4, direction.w); 278 279 real backHalfLambert = dot(backNormalWS, direction.xyz - 0.5) + 0.5; 280 backBakeDiffuseLighting += illuminance * backHalfLambert / max(1e-4, direction.w); 281} 282 283// deprecated 284void SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, 285 float3 normalWS, float3 backNormalWS, bool isStaticLightmap, real4 ignore, inout real3 bakeDiffuseLighting, inout real3 backBakeDiffuseLighting) 286{ 287 SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_ARGS(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS_USE, 288 transform, normalWS, backNormalWS, isStaticLightmap, bakeDiffuseLighting, backBakeDiffuseLighting); 289} 290 291// Just a shortcut that call function above 292real3 SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, float3 normalWS, bool isStaticLightmap) 293{ 294 float3 backNormalWSUnused = 0.0; 295 real3 bakeDiffuseLighting = 0.0; 296 real3 backBakeDiffuseLightingUnused = 0.0; 297 SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_ARGS(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS_USE, transform, 298 normalWS, backNormalWSUnused, isStaticLightmap, bakeDiffuseLighting, backBakeDiffuseLightingUnused); 299 300 return bakeDiffuseLighting; 301} 302 303// deprecated 304real3 SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, float3 normalWS, 305 bool isStaticLightmap, real4 ignore) 306{ 307 return SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_ARGS(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS_USE, transform, normalWS, isStaticLightmap); 308} 309 310#if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH 311#pragma warning (enable : 3205) // conversion of larger type to smaller 312#endif 313 314#endif // UNITY_ENTITY_LIGHTING_INCLUDED