説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

GlobalIllumination.hlsl 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. #ifndef UNIVERSAL_GLOBAL_ILLUMINATION_INCLUDED
  2. #define UNIVERSAL_GLOBAL_ILLUMINATION_INCLUDED
  3. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
  4. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
  5. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
  6. #define AMBIENT_PROBE_BUFFER 0
  7. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/AmbientProbe.hlsl"
  8. #if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
  9. #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl"
  10. #endif
  11. #if USE_FORWARD_PLUS
  12. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
  13. #endif
  14. // If lightmap is not defined than we evaluate GI (ambient + probes) from SH
  15. // Renamed -> LIGHTMAP_SHADOW_MIXING
  16. #if !defined(_MIXED_LIGHTING_SUBTRACTIVE) && defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK)
  17. #define _MIXED_LIGHTING_SUBTRACTIVE
  18. #endif
  19. // SH Vertex Evaluation. Depending on target SH sampling might be
  20. // done completely per vertex or mixed with L2 term per vertex and L0, L1
  21. // per pixel. See SampleSHPixel
  22. half3 SampleSHVertex(half3 normalWS)
  23. {
  24. #if defined(EVALUATE_SH_VERTEX)
  25. return EvaluateAmbientProbeSRGB(normalWS);
  26. #elif defined(EVALUATE_SH_MIXED)
  27. // no max since this is only L2 contribution
  28. return SHEvalLinearL2(normalWS, unity_SHBr, unity_SHBg, unity_SHBb, unity_SHC);
  29. #endif
  30. // Fully per-pixel. Nothing to compute.
  31. return half3(0.0, 0.0, 0.0);
  32. }
  33. // SH Pixel Evaluation. Depending on target SH sampling might be done
  34. // mixed or fully in pixel. See SampleSHVertex
  35. half3 SampleSHPixel(half3 L2Term, half3 normalWS)
  36. {
  37. #if defined(EVALUATE_SH_VERTEX)
  38. return L2Term;
  39. #elif defined(EVALUATE_SH_MIXED)
  40. half3 res = L2Term + SHEvalLinearL0L1(normalWS, unity_SHAr, unity_SHAg, unity_SHAb);
  41. #ifdef UNITY_COLORSPACE_GAMMA
  42. res = LinearToSRGB(res);
  43. #endif
  44. return max(half3(0, 0, 0), res);
  45. #endif
  46. // Default: Evaluate SH fully per-pixel
  47. return EvaluateAmbientProbeSRGB(normalWS);
  48. }
  49. // APV Prove volume
  50. // Vertex and Mixed both use Vertex sampling
  51. #if (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
  52. half3 SampleProbeVolumeVertex(in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, out float4 probeOcclusion)
  53. {
  54. probeOcclusion = 1.0;
  55. #if defined(EVALUATE_SH_VERTEX) || defined(EVALUATE_SH_MIXED)
  56. half3 bakedGI;
  57. // The screen space position is used for noise, which is irrelevant when doing vertex sampling
  58. float2 positionSS = float2(0, 0);
  59. if (_EnableProbeVolumes)
  60. {
  61. EvaluateAdaptiveProbeVolume(absolutePositionWS, normalWS, viewDir, positionSS, GetMeshRenderingLayer(), bakedGI, probeOcclusion);
  62. }
  63. else
  64. {
  65. bakedGI = EvaluateAmbientProbe(normalWS);
  66. }
  67. #ifdef UNITY_COLORSPACE_GAMMA
  68. bakedGI = LinearToSRGB(bakedGI);
  69. #endif
  70. return bakedGI;
  71. #else
  72. return half3(0, 0, 0);
  73. #endif
  74. }
  75. half3 SampleProbeVolumePixel(in half3 vertexValue, in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, in float2 positionSS, in float4 vertexProbeOcclusion, out float4 probeOcclusion)
  76. {
  77. probeOcclusion = 1.0;
  78. #if defined(EVALUATE_SH_VERTEX) || defined(EVALUATE_SH_MIXED)
  79. probeOcclusion = vertexProbeOcclusion;
  80. return vertexValue;
  81. #elif defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
  82. half3 bakedGI;
  83. if (_EnableProbeVolumes)
  84. {
  85. EvaluateAdaptiveProbeVolume(absolutePositionWS, normalWS, viewDir, positionSS, GetMeshRenderingLayer(), bakedGI, probeOcclusion);
  86. }
  87. else
  88. {
  89. bakedGI = EvaluateAmbientProbe(normalWS);
  90. }
  91. #ifdef UNITY_COLORSPACE_GAMMA
  92. bakedGI = LinearToSRGB(bakedGI);
  93. #endif
  94. return bakedGI;
  95. #else
  96. return half3(0, 0, 0);
  97. #endif
  98. }
  99. half3 SampleProbeVolumePixel(in half3 vertexValue, in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, in float2 positionSS)
  100. {
  101. float4 unusedProbeOcclusion = 0;
  102. return SampleProbeVolumePixel(vertexValue, absolutePositionWS, normalWS, viewDir, positionSS, unusedProbeOcclusion, unusedProbeOcclusion);
  103. }
  104. #endif
  105. half3 SampleProbeSHVertex(in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir, out float4 probeOcclusion)
  106. {
  107. probeOcclusion = 1.0;
  108. #if (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
  109. return SampleProbeVolumeVertex(absolutePositionWS, normalWS, viewDir, probeOcclusion);
  110. #else
  111. return SampleSHVertex(normalWS);
  112. #endif
  113. }
  114. half3 SampleProbeSHVertex(in float3 absolutePositionWS, in float3 normalWS, in float3 viewDir)
  115. {
  116. float4 unusedProbeOcclusion = 0;
  117. return SampleProbeSHVertex(absolutePositionWS, normalWS, viewDir, unusedProbeOcclusion);
  118. }
  119. #if defined(UNITY_DOTS_INSTANCING_ENABLED) && !defined(USE_LEGACY_LIGHTMAPS)
  120. // ^ GPU-driven rendering is enabled, and we haven't opted-out from lightmap
  121. // texture arrays. This minimizes batch breakages, but texture arrays aren't
  122. // supported in a performant way on all GPUs.
  123. #define LIGHTMAP_NAME unity_Lightmaps
  124. #define LIGHTMAP_INDIRECTION_NAME unity_LightmapsInd
  125. #define LIGHTMAP_SAMPLER_NAME samplerunity_Lightmaps
  126. #define LIGHTMAP_SAMPLE_EXTRA_ARGS staticLightmapUV, unity_LightmapIndex.x
  127. #else
  128. // ^ Lightmaps are not bound as texture arrays, but as individual textures. The
  129. // batch is broken every time lightmaps are changed, but this is well-supported
  130. // on all GPUs.
  131. #define LIGHTMAP_NAME unity_Lightmap
  132. #define LIGHTMAP_INDIRECTION_NAME unity_LightmapInd
  133. #define LIGHTMAP_SAMPLER_NAME samplerunity_Lightmap
  134. #define LIGHTMAP_SAMPLE_EXTRA_ARGS staticLightmapUV
  135. #endif
  136. // Sample baked and/or realtime lightmap. Non-Direction and Directional if available.
  137. half3 SampleLightmap(float2 staticLightmapUV, float2 dynamicLightmapUV, half3 normalWS)
  138. {
  139. // The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
  140. // However, universal pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
  141. // the compiler will optimize the transform away.
  142. half4 transformCoords = half4(1, 1, 0, 0);
  143. float3 diffuseLighting = 0;
  144. #if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
  145. diffuseLighting = SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME),
  146. TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_INDIRECTION_NAME, LIGHTMAP_SAMPLER_NAME),
  147. LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, normalWS, true);
  148. #elif defined(LIGHTMAP_ON)
  149. diffuseLighting = SampleSingleLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME), LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, true);
  150. #endif
  151. #if defined(DYNAMICLIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
  152. diffuseLighting += SampleDirectionalLightmap(TEXTURE2D_ARGS(unity_DynamicLightmap, samplerunity_DynamicLightmap),
  153. TEXTURE2D_ARGS(unity_DynamicDirectionality, samplerunity_DynamicLightmap),
  154. dynamicLightmapUV, transformCoords, normalWS, false);
  155. #elif defined(DYNAMICLIGHTMAP_ON)
  156. diffuseLighting += SampleSingleLightmap(TEXTURE2D_ARGS(unity_DynamicLightmap, samplerunity_DynamicLightmap),
  157. dynamicLightmapUV, transformCoords, false);
  158. #endif
  159. return diffuseLighting;
  160. }
  161. // Legacy version of SampleLightmap where Realtime GI is not supported.
  162. half3 SampleLightmap(float2 staticLightmapUV, half3 normalWS)
  163. {
  164. float2 dummyDynamicLightmapUV = float2(0,0);
  165. half3 result = SampleLightmap(staticLightmapUV, dummyDynamicLightmapUV, normalWS);
  166. return result;
  167. }
  168. // We either sample GI from baked lightmap or from probes.
  169. // If lightmap: sampleData.xy = lightmapUV
  170. // If probe: sampleData.xyz = L2 SH terms
  171. #if defined(LIGHTMAP_ON) && defined(DYNAMICLIGHTMAP_ON)
  172. #define SAMPLE_GI(staticLmName, dynamicLmName, shName, normalWSName) SampleLightmap(staticLmName, dynamicLmName, normalWSName)
  173. #elif defined(DYNAMICLIGHTMAP_ON)
  174. #define SAMPLE_GI(staticLmName, dynamicLmName, shName, normalWSName) SampleLightmap(0, dynamicLmName, normalWSName)
  175. #elif defined(LIGHTMAP_ON)
  176. #define SAMPLE_GI(staticLmName, shName, normalWSName) SampleLightmap(staticLmName, 0, normalWSName)
  177. #elif defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
  178. #ifdef USE_APV_PROBE_OCCLUSION
  179. #define SAMPLE_GI(shName, absolutePositionWS, normalWS, viewDir, positionSS, vertexProbeOcclusion, probeOcclusion) SampleProbeVolumePixel(shName, absolutePositionWS, normalWS, viewDir, positionSS, vertexProbeOcclusion, probeOcclusion)
  180. #else
  181. #define SAMPLE_GI(shName, absolutePositionWS, normalWS, viewDir, positionSS, vertexProbeOcclusion, probeOcclusion) SampleProbeVolumePixel(shName, absolutePositionWS, normalWS, viewDir, positionSS)
  182. #endif
  183. #else
  184. #define SAMPLE_GI(staticLmName, shName, normalWSName) SampleSHPixel(shName, normalWSName)
  185. #endif
  186. half3 BoxProjectedCubemapDirection(half3 reflectionWS, float3 positionWS, float4 cubemapPositionWS, float4 boxMin, float4 boxMax)
  187. {
  188. // Is this probe using box projection?
  189. if (cubemapPositionWS.w > 0.0f)
  190. {
  191. float3 boxMinMax = (reflectionWS > 0.0f) ? boxMax.xyz : boxMin.xyz;
  192. half3 rbMinMax = half3(boxMinMax - positionWS) / reflectionWS;
  193. half fa = half(min(min(rbMinMax.x, rbMinMax.y), rbMinMax.z));
  194. half3 worldPos = half3(positionWS - cubemapPositionWS.xyz);
  195. half3 result = worldPos + reflectionWS * fa;
  196. return result;
  197. }
  198. else
  199. {
  200. return reflectionWS;
  201. }
  202. }
  203. float CalculateProbeWeight(float3 positionWS, float4 probeBoxMin, float4 probeBoxMax)
  204. {
  205. float blendDistance = probeBoxMax.w;
  206. float3 weightDir = min(positionWS - probeBoxMin.xyz, probeBoxMax.xyz - positionWS) / blendDistance;
  207. return saturate(min(weightDir.x, min(weightDir.y, weightDir.z)));
  208. }
  209. half CalculateProbeVolumeSqrMagnitude(float4 probeBoxMin, float4 probeBoxMax)
  210. {
  211. half3 maxToMin = half3(probeBoxMax.xyz - probeBoxMin.xyz);
  212. return dot(maxToMin, maxToMin);
  213. }
  214. half3 CalculateIrradianceFromReflectionProbes(half3 reflectVector, float3 positionWS, half perceptualRoughness, float2 normalizedScreenSpaceUV)
  215. {
  216. half3 irradiance = half3(0.0h, 0.0h, 0.0h);
  217. half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
  218. #if USE_FORWARD_PLUS
  219. float totalWeight = 0.0f;
  220. uint probeIndex;
  221. ClusterIterator it = ClusterInit(normalizedScreenSpaceUV, positionWS, 1);
  222. [loop] while (ClusterNext(it, probeIndex) && totalWeight < 0.99f)
  223. {
  224. probeIndex -= URP_FP_PROBES_BEGIN;
  225. float weight = CalculateProbeWeight(positionWS, urp_ReflProbes_BoxMin[probeIndex], urp_ReflProbes_BoxMax[probeIndex]);
  226. weight = min(weight, 1.0f - totalWeight);
  227. half3 sampleVector = reflectVector;
  228. #ifdef _REFLECTION_PROBE_BOX_PROJECTION
  229. sampleVector = BoxProjectedCubemapDirection(reflectVector, positionWS, urp_ReflProbes_ProbePosition[probeIndex], urp_ReflProbes_BoxMin[probeIndex], urp_ReflProbes_BoxMax[probeIndex]);
  230. #endif // _REFLECTION_PROBE_BOX_PROJECTION
  231. uint maxMip = (uint)abs(urp_ReflProbes_ProbePosition[probeIndex].w) - 1;
  232. half probeMip = min(mip, maxMip);
  233. float2 uv = saturate(PackNormalOctQuadEncode(sampleVector) * 0.5 + 0.5);
  234. float mip0 = floor(probeMip);
  235. float mip1 = mip0 + 1;
  236. float mipBlend = probeMip - mip0;
  237. float4 scaleOffset0 = urp_ReflProbes_MipScaleOffset[probeIndex * 7 + (uint)mip0];
  238. float4 scaleOffset1 = urp_ReflProbes_MipScaleOffset[probeIndex * 7 + (uint)mip1];
  239. half3 irradiance0 = half4(SAMPLE_TEXTURE2D_LOD(urp_ReflProbes_Atlas, sampler_LinearClamp, uv * scaleOffset0.xy + scaleOffset0.zw, 0.0)).rgb;
  240. half3 irradiance1 = half4(SAMPLE_TEXTURE2D_LOD(urp_ReflProbes_Atlas, sampler_LinearClamp, uv * scaleOffset1.xy + scaleOffset1.zw, 0.0)).rgb;
  241. irradiance += weight * lerp(irradiance0, irradiance1, mipBlend);
  242. totalWeight += weight;
  243. }
  244. #else
  245. half probe0Volume = CalculateProbeVolumeSqrMagnitude(unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
  246. half probe1Volume = CalculateProbeVolumeSqrMagnitude(unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
  247. half volumeDiff = probe0Volume - probe1Volume;
  248. float importanceSign = unity_SpecCube1_BoxMin.w;
  249. // A probe is dominant if its importance is higher
  250. // Or have equal importance but smaller volume
  251. bool probe0Dominant = importanceSign > 0.0f || (importanceSign == 0.0f && volumeDiff < -0.0001h);
  252. bool probe1Dominant = importanceSign < 0.0f || (importanceSign == 0.0f && volumeDiff > 0.0001h);
  253. float desiredWeightProbe0 = CalculateProbeWeight(positionWS, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
  254. float desiredWeightProbe1 = CalculateProbeWeight(positionWS, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
  255. // Subject the probes weight if the other probe is dominant
  256. float weightProbe0 = probe1Dominant ? min(desiredWeightProbe0, 1.0f - desiredWeightProbe1) : desiredWeightProbe0;
  257. float weightProbe1 = probe0Dominant ? min(desiredWeightProbe1, 1.0f - desiredWeightProbe0) : desiredWeightProbe1;
  258. float totalWeight = weightProbe0 + weightProbe1;
  259. // If either probe 0 or probe 1 is dominant the sum of weights is guaranteed to be 1.
  260. // If neither is dominant this is not guaranteed - only normalize weights if totalweight exceeds 1.
  261. weightProbe0 /= max(totalWeight, 1.0f);
  262. weightProbe1 /= max(totalWeight, 1.0f);
  263. // Sample the first reflection probe
  264. if (weightProbe0 > 0.01f)
  265. {
  266. half3 reflectVector0 = reflectVector;
  267. #ifdef _REFLECTION_PROBE_BOX_PROJECTION
  268. reflectVector0 = BoxProjectedCubemapDirection(reflectVector, positionWS, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
  269. #endif // _REFLECTION_PROBE_BOX_PROJECTION
  270. half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector0, mip));
  271. irradiance += weightProbe0 * DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
  272. }
  273. // Sample the second reflection probe
  274. if (weightProbe1 > 0.01f)
  275. {
  276. half3 reflectVector1 = reflectVector;
  277. #ifdef _REFLECTION_PROBE_BOX_PROJECTION
  278. reflectVector1 = BoxProjectedCubemapDirection(reflectVector, positionWS, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
  279. #endif // _REFLECTION_PROBE_BOX_PROJECTION
  280. half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube1, samplerunity_SpecCube1, reflectVector1, mip));
  281. irradiance += weightProbe1 * DecodeHDREnvironment(encodedIrradiance, unity_SpecCube1_HDR);
  282. }
  283. #endif
  284. // Use any remaining weight to blend to environment reflection cube map
  285. if (totalWeight < 0.99f)
  286. {
  287. half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(_GlossyEnvironmentCubeMap, sampler_GlossyEnvironmentCubeMap, reflectVector, mip));
  288. irradiance += (1.0f - totalWeight) * DecodeHDREnvironment(encodedIrradiance, _GlossyEnvironmentCubeMap_HDR);
  289. }
  290. return irradiance;
  291. }
  292. #if !USE_FORWARD_PLUS
  293. half3 CalculateIrradianceFromReflectionProbes(half3 reflectVector, float3 positionWS, half perceptualRoughness)
  294. {
  295. return CalculateIrradianceFromReflectionProbes(reflectVector, positionWS, perceptualRoughness, float2(0.0f, 0.0f));
  296. }
  297. #endif
  298. half3 GlossyEnvironmentReflection(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion, float2 normalizedScreenSpaceUV)
  299. {
  300. #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
  301. half3 irradiance;
  302. #if defined(_REFLECTION_PROBE_BLENDING) || USE_FORWARD_PLUS
  303. irradiance = CalculateIrradianceFromReflectionProbes(reflectVector, positionWS, perceptualRoughness, normalizedScreenSpaceUV);
  304. #else
  305. #ifdef _REFLECTION_PROBE_BOX_PROJECTION
  306. reflectVector = BoxProjectedCubemapDirection(reflectVector, positionWS, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
  307. #endif // _REFLECTION_PROBE_BOX_PROJECTION
  308. half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
  309. half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
  310. irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
  311. #endif // _REFLECTION_PROBE_BLENDING
  312. return irradiance * occlusion;
  313. #else
  314. return _GlossyEnvironmentColor.rgb * occlusion;
  315. #endif // _ENVIRONMENTREFLECTIONS_OFF
  316. }
  317. #if !USE_FORWARD_PLUS
  318. half3 GlossyEnvironmentReflection(half3 reflectVector, float3 positionWS, half perceptualRoughness, half occlusion)
  319. {
  320. return GlossyEnvironmentReflection(reflectVector, positionWS, perceptualRoughness, occlusion, float2(0.0f, 0.0f));
  321. }
  322. #endif
  323. half3 GlossyEnvironmentReflection(half3 reflectVector, half perceptualRoughness, half occlusion)
  324. {
  325. #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
  326. half3 irradiance;
  327. half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);
  328. half4 encodedIrradiance = half4(SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip));
  329. irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
  330. return irradiance * occlusion;
  331. #else
  332. return _GlossyEnvironmentColor.rgb * occlusion;
  333. #endif // _ENVIRONMENTREFLECTIONS_OFF
  334. }
  335. half3 SubtractDirectMainLightFromLightmap(Light mainLight, half3 normalWS, half3 bakedGI)
  336. {
  337. // Let's try to make realtime shadows work on a surface, which already contains
  338. // baked lighting and shadowing from the main sun light.
  339. // Summary:
  340. // 1) Calculate possible value in the shadow by subtracting estimated light contribution from the places occluded by realtime shadow:
  341. // a) preserves other baked lights and light bounces
  342. // b) eliminates shadows on the geometry facing away from the light
  343. // 2) Clamp against user defined ShadowColor.
  344. // 3) Pick original lightmap value, if it is the darkest one.
  345. // 1) Gives good estimate of illumination as if light would've been shadowed during the bake.
  346. // We only subtract the main direction light. This is accounted in the contribution term below.
  347. half shadowStrength = GetMainLightShadowStrength();
  348. half contributionTerm = saturate(dot(mainLight.direction, normalWS));
  349. half3 lambert = mainLight.color * contributionTerm;
  350. half3 estimatedLightContributionMaskedByInverseOfShadow = lambert * (1.0 - mainLight.shadowAttenuation);
  351. half3 subtractedLightmap = bakedGI - estimatedLightContributionMaskedByInverseOfShadow;
  352. // 2) Allows user to define overall ambient of the scene and control situation when realtime shadow becomes too dark.
  353. half3 realtimeShadow = max(subtractedLightmap, _SubtractiveShadowColor.xyz);
  354. realtimeShadow = lerp(bakedGI, realtimeShadow, shadowStrength);
  355. // 3) Pick darkest color
  356. return min(bakedGI, realtimeShadow);
  357. }
  358. half3 GlobalIllumination(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
  359. half3 bakedGI, half occlusion, float3 positionWS,
  360. half3 normalWS, half3 viewDirectionWS, float2 normalizedScreenSpaceUV)
  361. {
  362. half3 reflectVector = reflect(-viewDirectionWS, normalWS);
  363. half NoV = saturate(dot(normalWS, viewDirectionWS));
  364. half fresnelTerm = Pow4(1.0 - NoV);
  365. half3 indirectDiffuse = bakedGI;
  366. half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, positionWS, brdfData.perceptualRoughness, 1.0h, normalizedScreenSpaceUV);
  367. half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
  368. if (IsOnlyAOLightingFeatureEnabled())
  369. {
  370. color = half3(1,1,1); // "Base white" for AO debug lighting mode
  371. }
  372. #if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
  373. half3 coatIndirectSpecular = GlossyEnvironmentReflection(reflectVector, positionWS, brdfDataClearCoat.perceptualRoughness, 1.0h, normalizedScreenSpaceUV);
  374. // TODO: "grazing term" causes problems on full roughness
  375. half3 coatColor = EnvironmentBRDFClearCoat(brdfDataClearCoat, clearCoatMask, coatIndirectSpecular, fresnelTerm);
  376. // Blend with base layer using khronos glTF recommended way using NoV
  377. // Smooth surface & "ambiguous" lighting
  378. // NOTE: fresnelTerm (above) is pow4 instead of pow5, but should be ok as blend weight.
  379. half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * fresnelTerm;
  380. return (color * (1.0 - coatFresnel * clearCoatMask) + coatColor) * occlusion;
  381. #else
  382. return color * occlusion;
  383. #endif
  384. }
  385. #if !USE_FORWARD_PLUS
  386. half3 GlobalIllumination(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
  387. half3 bakedGI, half occlusion, float3 positionWS,
  388. half3 normalWS, half3 viewDirectionWS)
  389. {
  390. return GlobalIllumination(brdfData, brdfDataClearCoat, clearCoatMask, bakedGI, occlusion, positionWS, normalWS, viewDirectionWS, float2(0.0f, 0.0f));
  391. }
  392. #endif
  393. // Backwards compatiblity
  394. half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, float3 positionWS, half3 normalWS, half3 viewDirectionWS)
  395. {
  396. const BRDFData noClearCoat = (BRDFData)0;
  397. return GlobalIllumination(brdfData, noClearCoat, 0.0, bakedGI, occlusion, positionWS, normalWS, viewDirectionWS, 0);
  398. }
  399. half3 GlobalIllumination(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
  400. half3 bakedGI, half occlusion,
  401. half3 normalWS, half3 viewDirectionWS)
  402. {
  403. half3 reflectVector = reflect(-viewDirectionWS, normalWS);
  404. half NoV = saturate(dot(normalWS, viewDirectionWS));
  405. half fresnelTerm = Pow4(1.0 - NoV);
  406. half3 indirectDiffuse = bakedGI;
  407. half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, half(1.0));
  408. half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
  409. #if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
  410. half3 coatIndirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfDataClearCoat.perceptualRoughness, half(1.0));
  411. // TODO: "grazing term" causes problems on full roughness
  412. half3 coatColor = EnvironmentBRDFClearCoat(brdfDataClearCoat, clearCoatMask, coatIndirectSpecular, fresnelTerm);
  413. // Blend with base layer using khronos glTF recommended way using NoV
  414. // Smooth surface & "ambiguous" lighting
  415. // NOTE: fresnelTerm (above) is pow4 instead of pow5, but should be ok as blend weight.
  416. half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * fresnelTerm;
  417. return (color * (1.0 - coatFresnel * clearCoatMask) + coatColor) * occlusion;
  418. #else
  419. return color * occlusion;
  420. #endif
  421. }
  422. half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS)
  423. {
  424. const BRDFData noClearCoat = (BRDFData)0;
  425. return GlobalIllumination(brdfData, noClearCoat, 0.0, bakedGI, occlusion, normalWS, viewDirectionWS);
  426. }
  427. void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI)
  428. {
  429. #if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
  430. bakedGI = SubtractDirectMainLightFromLightmap(light, normalWS, bakedGI);
  431. #endif
  432. }
  433. // Backwards compatibility
  434. void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, half4 shadowMask)
  435. {
  436. MixRealtimeAndBakedGI(light, normalWS, bakedGI);
  437. }
  438. void MixRealtimeAndBakedGI(inout Light light, half3 normalWS, inout half3 bakedGI, AmbientOcclusionFactor aoFactor)
  439. {
  440. if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
  441. {
  442. bakedGI *= aoFactor.indirectAmbientOcclusion;
  443. }
  444. MixRealtimeAndBakedGI(light, normalWS, bakedGI);
  445. }
  446. #endif