SsRaymarching.glsl 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // Screen space ray marching
  6. #pragma once
  7. #include <AnKi/Shaders/Common.glsl>
  8. // Find the intersection of a ray and a AABB when the ray is inside the AABB
  9. void rayAabbIntersectionInside2d(Vec2 rayOrigin, Vec2 rayDir, Vec2 aabbMin, Vec2 aabbMax, out F32 t)
  10. {
  11. // Find the boundary of the AABB that the rayDir points at
  12. Vec2 boundary;
  13. boundary.x = (rayDir.x > 0.0) ? aabbMax.x : aabbMin.x;
  14. boundary.y = (rayDir.y > 0.0) ? aabbMax.y : aabbMin.y;
  15. // Find the intersection of the ray with the line y=boundary.y
  16. // The intersection is: rayOrigin + T * rayDir
  17. // For y it's: rayOrigin.y + T * rayDir.y
  18. // And it's equal to the boundary.y: rayOrigin.y + T * rayDir.y = boundary.y
  19. const F32 ty = (boundary.y - rayOrigin.y) / rayDir.y;
  20. // Same for x=boundary.x
  21. const F32 tx = (boundary.x - rayOrigin.x) / rayDir.x;
  22. // Chose the shortest t
  23. t = min(ty, tx);
  24. }
  25. // Find the cell the rayOrigin is in and push it outside that cell towards the direction of the rayDir
  26. void stepToNextCell(Vec3 rayOrigin, Vec3 rayDir, U32 mipLevel, UVec2 hizSize, out Vec3 newRayOrigin)
  27. {
  28. const UVec2 mipSize = hizSize >> mipLevel;
  29. const Vec2 mipSizef = Vec2(mipSize);
  30. // Position in texture space
  31. const Vec2 texPos = rayOrigin.xy * mipSizef;
  32. // Compute the boundaries of the cell in UV space
  33. const Vec2 cellMin = floor(texPos) / mipSizef;
  34. const Vec2 cellMax = ceil(texPos) / mipSizef;
  35. // Find the intersection
  36. F32 t;
  37. rayAabbIntersectionInside2d(rayOrigin.xy, rayDir.xy, cellMin, cellMax, t);
  38. // Bump t a bit to stop touching the cell
  39. const F32 texelSizeX = 1.0 / mipSizef.x;
  40. t += texelSizeX / 10.0;
  41. // Compute the new origin
  42. newRayOrigin = rayOrigin + rayDir * t;
  43. }
  44. // Note: All calculations in view space
  45. void raymarch(Vec3 rayOrigin, // Ray origin in view space
  46. Vec3 rayDir, // Ray dir in view space
  47. F32 tmin, // Shoot rays from
  48. Vec2 uv, // UV the ray starts
  49. F32 depthRef, // Depth the ray starts
  50. Mat4 projMat, // Projection matrix
  51. U32 randFrom0To3, U32 maxIterations, texture2D hizTex, sampler hizSampler, U32 hizMipCount,
  52. UVec2 hizMip0Size, out Vec3 hitPoint, out F32 attenuation)
  53. {
  54. attenuation = 0.0;
  55. // Check for view facing reflections [sakibsaikia]
  56. const Vec3 viewDir = normalize(rayOrigin);
  57. const F32 cameraContribution = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, rayDir));
  58. ANKI_BRANCH if(cameraContribution <= 0.0)
  59. {
  60. return;
  61. }
  62. // Dither and set starting pos
  63. const F32 bayerMat[4] = F32[](1.0, 4.0, 2.0, 3.0);
  64. const Vec3 p0 = rayOrigin + rayDir * (tmin * bayerMat[randFrom0To3]);
  65. // p1
  66. const F32 tmax = 10.0;
  67. const Vec3 p1 = rayOrigin + rayDir * tmax;
  68. // Compute start & end in clip space (well not clip space since x,y are in [0, 1])
  69. Vec4 v4 = projMat * Vec4(p0, 1.0);
  70. Vec3 start = v4.xyz / v4.w;
  71. start.xy = NDC_TO_UV(start.xy);
  72. v4 = projMat * Vec4(p1, 1.0);
  73. Vec3 end = v4.xyz / v4.w;
  74. end.xy = NDC_TO_UV(end.xy);
  75. // Ray
  76. Vec3 origin = start;
  77. const Vec3 dir = normalize(end - start);
  78. // Start looping
  79. I32 mipLevel = 0;
  80. while(mipLevel > -1 && maxIterations > 0u)
  81. {
  82. // Step to the next cell
  83. Vec3 newOrigin;
  84. stepToNextCell(origin, dir, U32(mipLevel), hizMip0Size, newOrigin);
  85. origin = newOrigin;
  86. if(all(greaterThan(origin.xy, Vec2(0.0))) && all(lessThan(origin.xy, Vec2(1.0))))
  87. {
  88. const F32 newDepth = textureLod(hizTex, hizSampler, origin.xy, F32(mipLevel)).r;
  89. if(origin.z < newDepth)
  90. {
  91. // In front of depth
  92. mipLevel = min(mipLevel + 1, I32(hizMipCount - 1u));
  93. }
  94. else
  95. {
  96. // Behind depth
  97. const F32 t = (origin.z - newDepth) / dir.z;
  98. origin -= dir * t;
  99. --mipLevel;
  100. }
  101. --maxIterations;
  102. }
  103. else
  104. {
  105. // Out of the screen
  106. break;
  107. }
  108. }
  109. // Write the values
  110. const F32 blackMargin = 0.05 / 4.0;
  111. const F32 whiteMargin = 0.1 / 2.0;
  112. const Vec2 marginAttenuation2d = smoothstep(blackMargin, whiteMargin, origin.xy)
  113. * (1.0 - smoothstep(1.0 - whiteMargin, 1.0 - blackMargin, origin.xy));
  114. const F32 marginAttenuation = marginAttenuation2d.x * marginAttenuation2d.y;
  115. attenuation = marginAttenuation * cameraContribution;
  116. hitPoint = origin;
  117. }
  118. // Note: All calculations in view space
  119. void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
  120. Vec3 rayDir, // Ray dir in view space
  121. Vec2 uv, // UV the ray starts
  122. F32 depthRef, // Depth the ray starts
  123. Mat4 projMat, // Projection matrix
  124. U32 maxSteps, // The max iterations of the base algorithm
  125. texture2D depthTex, // Depth tex
  126. sampler depthSampler, // Sampler for depthTex
  127. F32 depthLod, // LOD to pass to the textureLod
  128. UVec2 depthTexSize, // Size of the depthTex
  129. U32 initialStepIncrement, // Initial step increment
  130. U32 randInitialStep, // The initial step
  131. out Vec3 hitPoint, // Hit point in UV coordinates
  132. out F32 attenuation)
  133. {
  134. attenuation = 0.0;
  135. // Check for view facing reflections [sakibsaikia]
  136. const Vec3 viewDir = normalize(rayOrigin);
  137. const F32 cameraContribution = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, rayDir));
  138. if(cameraContribution <= 0.0)
  139. {
  140. return;
  141. }
  142. // Start point
  143. const Vec3 p0 = rayOrigin;
  144. const Vec3 start = Vec3(uv, depthRef);
  145. // Project end point
  146. const Vec3 p1 = rayOrigin + rayDir * 0.1;
  147. const Vec4 end4 = projMat * Vec4(p1, 1.0);
  148. Vec3 end = end4.xyz / end4.w;
  149. end.xy = NDC_TO_UV(end.xy);
  150. // Compute the ray and step size
  151. Vec3 dir = end - start;
  152. const Vec2 texelSize = abs(dir.xy) * Vec2(depthTexSize);
  153. const F32 stepSize = length(dir.xy) / max(texelSize.x, texelSize.y);
  154. dir = normalize(dir);
  155. // Compute step
  156. I32 stepIncrement = I32(initialStepIncrement);
  157. I32 crntStep = I32(randInitialStep);
  158. // Search
  159. Vec3 origin;
  160. ANKI_LOOP while(maxSteps-- != 0u)
  161. {
  162. origin = start + dir * (F32(crntStep) * stepSize);
  163. // Check if it's out of the view
  164. if(origin.x <= 0.0 || origin.y <= 0.0 || origin.x >= 1.0 || origin.y >= 1.0)
  165. {
  166. break;
  167. }
  168. const F32 depth = textureLod(depthTex, depthSampler, origin.xy, depthLod).r;
  169. const Bool hit = origin.z - depth >= 0.0;
  170. if(!hit)
  171. {
  172. crntStep += stepIncrement;
  173. }
  174. else if(stepIncrement > 1)
  175. {
  176. // There is a hit but the step increment is a bit high, need a more fine-grained search
  177. crntStep = max(1, crntStep - stepIncrement + 1);
  178. stepIncrement = stepIncrement / 2;
  179. }
  180. else
  181. {
  182. // Found it
  183. // Compute attenuation
  184. const F32 blackMargin = 0.05 / 4.0;
  185. const F32 whiteMargin = 0.1 / 2.0;
  186. const Vec2 marginAttenuation2d = smoothstep(blackMargin, whiteMargin, origin.xy)
  187. * (1.0 - smoothstep(1.0 - whiteMargin, 1.0 - blackMargin, origin.xy));
  188. const F32 marginAttenuation = marginAttenuation2d.x * marginAttenuation2d.y;
  189. attenuation = marginAttenuation * cameraContribution;
  190. // ...and hit point
  191. hitPoint = origin;
  192. break;
  193. }
  194. }
  195. }
  196. void rejectBackFaces(Vec3 reflection, Vec3 normalAtHitPoint, out F32 attenuation)
  197. {
  198. attenuation = smoothstep(-0.17, 0.0, dot(normalAtHitPoint, -reflection));
  199. }