IndirectDiffuseClipmaps.hlsl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Shaders/Common.hlsl>
  7. #include <AnKi/Shaders/Include/MiscRendererTypes.h>
  8. /// Flags to fine tune the probe selection in sampleClipmapCommon
  9. enum SampleClipmapFlag : U32
  10. {
  11. kSampleClipmapFlagAccurateClipmapSelection = 1 << 0,
  12. kSampleClipmapFlagBiasSamplePointTowardsCamera = 1 << 1,
  13. kSampleClipmapFlagBiasSamplePointSurfaceNormal = 1 << 2,
  14. kSampleClipmapFlagInvalidProbeRejection = 1 << 3,
  15. kSampleClipmapFlagChebyshevOcclusion = 1 << 4,
  16. kSampleClipmapFlagBackfacingProbeRejection = 1 << 5,
  17. kSampleClipmapFlagUsePreviousFrame = 1 << 6,
  18. kSampleClipmapFlagFullQuality = kSampleClipmapFlagAccurateClipmapSelection | kSampleClipmapFlagInvalidProbeRejection
  19. | kSampleClipmapFlagChebyshevOcclusion | kSampleClipmapFlagBackfacingProbeRejection,
  20. kSampleClipmapFlagNone = 0
  21. };
  22. F32 computeClipmapFade(IndirectDiffuseClipmapConstants consts, U32 clipmapIdx, Vec3 cameraPos, Vec3 worldPos, SampleClipmapFlag flags)
  23. {
  24. Vec3 aabbMin;
  25. Vec3 aabbMax;
  26. if(flags & kSampleClipmapFlagUsePreviousFrame)
  27. {
  28. aabbMin = consts.m_previousFrameAabbMins[clipmapIdx].xyz;
  29. aabbMax = consts.m_previousFrameAabbMins[clipmapIdx].xyz + consts.m_sizes[clipmapIdx].xyz;
  30. }
  31. else
  32. {
  33. aabbMin = consts.m_aabbMins[clipmapIdx].xyz;
  34. aabbMax = consts.m_aabbMins[clipmapIdx].xyz + consts.m_sizes[clipmapIdx].xyz;
  35. }
  36. const Vec3 distances = select(worldPos > cameraPos, aabbMax - cameraPos, cameraPos - aabbMin);
  37. Vec3 a = abs(worldPos - cameraPos) / distances;
  38. a = min(1.0, a);
  39. a = pow(a, 32.0);
  40. a = 1.0 - a;
  41. F32 fade = a.x * a.y * a.z;
  42. return fade;
  43. }
  44. Bool insideClipmap(IndirectDiffuseClipmapConstants consts, U32 clipmapIdx, Vec3 worldPos, SampleClipmapFlag flags)
  45. {
  46. Vec3 aabbMin;
  47. Vec3 aabbMax;
  48. if(flags & kSampleClipmapFlagUsePreviousFrame)
  49. {
  50. aabbMin = consts.m_previousFrameAabbMins[clipmapIdx].xyz;
  51. aabbMax = consts.m_previousFrameAabbMins[clipmapIdx].xyz + consts.m_sizes[clipmapIdx].xyz;
  52. }
  53. else
  54. {
  55. aabbMin = consts.m_aabbMins[clipmapIdx].xyz;
  56. aabbMax = consts.m_aabbMins[clipmapIdx].xyz + consts.m_sizes[clipmapIdx].xyz;
  57. }
  58. return (all(worldPos < aabbMax) && all(worldPos > aabbMin));
  59. }
  60. U16 findClipmapOnPosition(IndirectDiffuseClipmapConstants consts, Vec3 cameraPos, Vec3 worldPos, F32 randFactor, SampleClipmapFlag flags)
  61. {
  62. for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
  63. {
  64. const F32 fade = computeClipmapFade(consts, i, cameraPos, worldPos, flags);
  65. if(fade > randFactor)
  66. {
  67. return i;
  68. }
  69. }
  70. return kIndirectDiffuseClipmapCount;
  71. }
  72. U16 findClipmapOnPositionCheap(IndirectDiffuseClipmapConstants consts, Vec3 worldPos, SampleClipmapFlag flags)
  73. {
  74. for(U32 i = 0; i < kIndirectDiffuseClipmapCount; ++i)
  75. {
  76. if(insideClipmap(consts, i, worldPos, flags))
  77. {
  78. return i;
  79. }
  80. }
  81. return kIndirectDiffuseClipmapCount;
  82. }
  83. struct SampleClipmapsArgs
  84. {
  85. SampleClipmapFlag m_flags;
  86. U32 m_primaryVolume; // 0: Irradiance, 1: radiance, 2: avgIrradiance
  87. F32 m_clipmapSelectionRandFactor;
  88. Vec3 m_samplePoint;
  89. Vec3 m_normal;
  90. Vec3 m_cameraPos;
  91. };
  92. Vec3 computeBiasedSamplePoint(Vec3 samplePoint, Vec3 normal, Vec3 cameraPos, SampleClipmapFlag flags, F32 bias)
  93. {
  94. constexpr SampleClipmapFlag bothBiases = kSampleClipmapFlagBiasSamplePointTowardsCamera | kSampleClipmapFlagBiasSamplePointSurfaceNormal;
  95. if(flags & bothBiases)
  96. {
  97. Vec3 biasDir = 0.0;
  98. if(flags & kSampleClipmapFlagBiasSamplePointTowardsCamera)
  99. {
  100. biasDir = normalize(cameraPos - samplePoint);
  101. }
  102. if(flags & kSampleClipmapFlagBiasSamplePointSurfaceNormal)
  103. {
  104. biasDir += normal;
  105. }
  106. if((flags & bothBiases) == bothBiases)
  107. {
  108. // Normalize if both biases have been applied
  109. biasDir = normalize(biasDir);
  110. }
  111. return samplePoint + biasDir * bias;
  112. }
  113. else
  114. {
  115. return samplePoint;
  116. }
  117. }
  118. /// Find out the clipmap for a given sample point and sample the probes in the volumes.
  119. Vec3 sampleClipmapCommon(SampleClipmapsArgs args, SamplerState linearAnyRepeatSampler, IndirectDiffuseClipmapConstants consts)
  120. {
  121. const SampleClipmapFlag flags = args.m_flags;
  122. #if 1
  123. const U16 clipmapIdx = (flags & kSampleClipmapFlagAccurateClipmapSelection)
  124. ? findClipmapOnPosition(consts, args.m_cameraPos, args.m_samplePoint, args.m_clipmapSelectionRandFactor, flags)
  125. : findClipmapOnPositionCheap(consts, args.m_samplePoint, flags);
  126. #else
  127. U16 clipmapIdx = 0;
  128. if(!insideClipmap(consts, clipmapIdx, args.m_samplePoint, flags))
  129. {
  130. clipmapIdx = 10;
  131. }
  132. #endif
  133. #if 0
  134. if(clipmapIdx == 0)
  135. {
  136. return Vec3(1, 0, 0);
  137. }
  138. else if(clipmapIdx == 1)
  139. {
  140. return Vec3(0, 1, 0);
  141. }
  142. else if(clipmapIdx == 2)
  143. {
  144. return Vec3(0, 0, 1);
  145. }
  146. else
  147. {
  148. return Vec3(1, 0, 1);
  149. }
  150. #endif
  151. if(clipmapIdx >= kIndirectDiffuseClipmapCount)
  152. {
  153. return 0.0;
  154. }
  155. const Vec3 clipmapSize = consts.m_sizes[clipmapIdx].xyz;
  156. const Vec3 probeCountsf = consts.m_probeCounts;
  157. const IndirectDiffuseClipmapTextures textures = consts.m_textures[clipmapIdx];
  158. const Vec3 probeSize = clipmapSize / probeCountsf;
  159. const Vec3 fakeVolumeSize = probeCountsf; // Volume size without the octahedron
  160. const Vec3 biasedWorldPos = computeBiasedSamplePoint(args.m_samplePoint, args.m_normal, args.m_cameraPos, flags, min3(probeSize) * 0.2);
  161. const Bool primaryVolumesHaveOctMap = args.m_primaryVolume != 2;
  162. const F32 octahedronSize =
  163. (primaryVolumesHaveOctMap) ? ((args.m_primaryVolume == 0) ? textures.m_irradianceOctMapSize : textures.m_radianceOctMapSize) : 1.0;
  164. const Vec3 realVolumeSize = probeCountsf.xzy * Vec3(octahedronSize + 2.0, octahedronSize + 2.0, 1.0);
  165. const F32 distMomentsOctSize = textures.m_distanceMomentsOctMapSize;
  166. const Vec3 distMomentsRealVolumeSize = probeCountsf.xzy * Vec3(distMomentsOctSize + 2.0, distMomentsOctSize + 2.0, 1.0);
  167. const Vec3 samplePointUvw = frac(biasedWorldPos / clipmapSize);
  168. const Vec3 icoord = floor(samplePointUvw * fakeVolumeSize - 0.5);
  169. const Vec3 fcoord = frac(samplePointUvw * fakeVolumeSize - 0.5);
  170. const Vec3 firstProbePosition = floor((biasedWorldPos - probeSize / 2.0) / probeSize) * probeSize + probeSize / 2.0;
  171. F32 weightSum = 0.0;
  172. Vec3 value = 0.0;
  173. for(U32 i = 0u; i < 8u; ++i)
  174. {
  175. const Vec3 xyz = Vec3(UVec3(i, i >> 1u, i >> 2u) & 1u);
  176. Vec3 coords = icoord + xyz;
  177. // Repeat
  178. coords = select(coords >= 0.0, coords, fakeVolumeSize + coords);
  179. coords = select(coords < fakeVolumeSize, coords, coords - fakeVolumeSize);
  180. if(flags & kSampleClipmapFlagInvalidProbeRejection)
  181. {
  182. const Bool valid = TEX(getBindlessTextureNonUniformIndex3DVec4(textures.m_probeValidityTexture), coords.xzy).x > 0.8;
  183. if(!valid)
  184. {
  185. continue;
  186. }
  187. }
  188. // Reject probes outside the current clipmap
  189. const Vec3 probePosition = firstProbePosition + xyz * probeSize;
  190. if(!insideClipmap(consts, clipmapIdx, probePosition, flags))
  191. {
  192. continue;
  193. }
  194. // Filtering weight
  195. const Vec3 w3 = select(xyz == 0.0, 1.0 - fcoord, fcoord);
  196. F32 w = w3.x * w3.y * w3.z;
  197. // Normal weight
  198. if(flags & kSampleClipmapFlagBackfacingProbeRejection)
  199. {
  200. const Vec3 dir = normalize(probePosition - args.m_samplePoint);
  201. const F32 wNormal = (dot(dir, args.m_normal) + 1.0) * 0.5;
  202. w *= (wNormal * wNormal) + 0.2;
  203. }
  204. // Chebyshev occlusion
  205. if(flags & kSampleClipmapFlagChebyshevOcclusion)
  206. {
  207. Vec3 uvw = coords.xzy;
  208. uvw.xy *= distMomentsOctSize + 2.0;
  209. uvw.xy += 1.0;
  210. uvw.xy += octahedronEncode(normalize(biasedWorldPos - probePosition)) * distMomentsOctSize;
  211. uvw.z += 0.5;
  212. uvw /= distMomentsRealVolumeSize;
  213. const Vec2 distMoments =
  214. getBindlessTextureNonUniformIndex3DVec4(textures.m_distanceMomentsTexture).SampleLevel(linearAnyRepeatSampler, uvw, 0.0);
  215. const F32 variance = abs(distMoments.x * distMoments.x - distMoments.y);
  216. const F32 posToProbeDist = length(biasedWorldPos - probePosition);
  217. F32 chebyshevWeight = 1.0;
  218. if(posToProbeDist > distMoments.x) // occluded
  219. {
  220. // v must be greater than 0, which is guaranteed by the if condition above.
  221. const F32 v = posToProbeDist - distMoments.x;
  222. chebyshevWeight = variance / (variance + (v * v));
  223. // Increase the contrast in the weight
  224. chebyshevWeight = chebyshevWeight * chebyshevWeight * chebyshevWeight;
  225. chebyshevWeight = max(chebyshevWeight, 0.05);
  226. }
  227. w *= chebyshevWeight;
  228. }
  229. // Compute the actual coords and sample
  230. U32 bindlessIndex;
  231. switch(args.m_primaryVolume)
  232. {
  233. case 0:
  234. bindlessIndex = textures.m_irradianceTexture;
  235. break;
  236. case 1:
  237. bindlessIndex = textures.m_radianceTexture;
  238. break;
  239. default:
  240. bindlessIndex = textures.m_averageIrradianceTexture;
  241. }
  242. Vec3 v;
  243. if(primaryVolumesHaveOctMap)
  244. {
  245. Vec3 uvw = coords.xzy;
  246. uvw.xy *= octahedronSize + 2.0;
  247. uvw.xy += 1.0;
  248. uvw.xy += octahedronEncode(args.m_normal) * octahedronSize;
  249. uvw.z += 0.5;
  250. uvw /= realVolumeSize;
  251. v = getBindlessTextureNonUniformIndex3DVec4(bindlessIndex).SampleLevel(linearAnyRepeatSampler, uvw, 0.0);
  252. }
  253. else
  254. {
  255. v = TEX(getBindlessTextureNonUniformIndex3DVec4(bindlessIndex), coords.xzy);
  256. }
  257. value += v * w;
  258. weightSum += w;
  259. }
  260. if(weightSum > kEpsilonF32)
  261. {
  262. value /= weightSum;
  263. }
  264. else
  265. {
  266. value = 0.0;
  267. }
  268. return value;
  269. }
  270. Vec3 sampleClipmapIrradiance(Vec3 samplePoint, Vec3 normal, Vec3 cameraPos, IndirectDiffuseClipmapConstants consts,
  271. SamplerState linearAnyRepeatSampler, SampleClipmapFlag flags, F32 randFactor = 0.5)
  272. {
  273. SampleClipmapsArgs args;
  274. args.m_primaryVolume = 0;
  275. args.m_flags = flags;
  276. args.m_cameraPos = cameraPos;
  277. args.m_clipmapSelectionRandFactor = randFactor;
  278. args.m_normal = normal;
  279. args.m_samplePoint = samplePoint;
  280. return sampleClipmapCommon(args, linearAnyRepeatSampler, consts);
  281. }
  282. Vec3 sampleClipmapRadiance(Vec3 samplePoint, Vec3 normal, Vec3 cameraPos, IndirectDiffuseClipmapConstants consts, SamplerState linearAnyRepeatSampler,
  283. SampleClipmapFlag flags, F32 randFactor = 0.5)
  284. {
  285. SampleClipmapsArgs args;
  286. args.m_primaryVolume = 1;
  287. args.m_flags = flags;
  288. args.m_cameraPos = cameraPos;
  289. args.m_clipmapSelectionRandFactor = randFactor;
  290. args.m_normal = normal;
  291. args.m_samplePoint = samplePoint;
  292. return sampleClipmapCommon(args, linearAnyRepeatSampler, consts);
  293. }
  294. Vec3 sampleClipmapAvgIrradianceCheap(Vec3 samplePoint, Vec3 cameraPos, IndirectDiffuseClipmapConstants consts, F32 randFactor,
  295. SamplerState linearAnyRepeatSampler, SampleClipmapFlag flags)
  296. {
  297. const U16 clipmapIdx = (flags & kSampleClipmapFlagAccurateClipmapSelection)
  298. ? findClipmapOnPosition(consts, cameraPos, samplePoint, randFactor, flags)
  299. : findClipmapOnPositionCheap(consts, samplePoint, flags);
  300. if(clipmapIdx >= kIndirectDiffuseClipmapCount)
  301. {
  302. return 0.0;
  303. }
  304. const Vec3 clipmapSize = consts.m_sizes[clipmapIdx].xyz;
  305. const Vec3 probeCountsf = consts.m_probeCounts;
  306. const Vec3 probeSize = clipmapSize / probeCountsf;
  307. const Vec3 biasedWorldPos = computeBiasedSamplePoint(samplePoint, 0.0, cameraPos, flags, min3(probeSize) * 0.2);
  308. const Vec3 samplePointUvw = (biasedWorldPos / clipmapSize).xzy;
  309. return getBindlessTextureNonUniformIndex3DVec4(consts.m_textures[clipmapIdx].m_averageIrradianceTexture)
  310. .SampleLevel(linearAnyRepeatSampler, samplePointUvw, 0.0)
  311. .xyz;
  312. }
  313. Vec3 sampleClipmapAvgIrradiance(Vec3 samplePoint, Vec3 normal, Vec3 cameraPos, IndirectDiffuseClipmapConstants consts,
  314. SamplerState linearAnyRepeatSampler, SampleClipmapFlag flags, F32 randFactor = 0.5)
  315. {
  316. const SampleClipmapFlag requireManualTrilinearFiltering =
  317. kSampleClipmapFlagInvalidProbeRejection | kSampleClipmapFlagBackfacingProbeRejection | kSampleClipmapFlagChebyshevOcclusion;
  318. if(flags & requireManualTrilinearFiltering)
  319. {
  320. SampleClipmapsArgs args;
  321. args.m_primaryVolume = 2;
  322. args.m_flags = flags;
  323. args.m_cameraPos = cameraPos;
  324. args.m_clipmapSelectionRandFactor = randFactor;
  325. args.m_normal = normal;
  326. args.m_samplePoint = samplePoint;
  327. return sampleClipmapCommon(args, linearAnyRepeatSampler, consts);
  328. }
  329. else
  330. {
  331. return sampleClipmapAvgIrradianceCheap(samplePoint, cameraPos, consts, randFactor, linearAnyRepeatSampler, flags);
  332. }
  333. }