SsRaymarching.glsl 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (C) 2009-2020, 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 <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 > 0)
  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 maxIterations, texture2D depthTex, sampler depthSampler, F32 depthLod, UVec2 depthTexSize,
  125. U32 bigStep, U32 randInitialStep, out Vec3 hitPoint, out F32 attenuation)
  126. {
  127. attenuation = 0.0;
  128. // Check for view facing reflections [sakibsaikia]
  129. const Vec3 viewDir = normalize(rayOrigin);
  130. const F32 cameraContribution = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, rayDir));
  131. if(cameraContribution <= 0.0)
  132. {
  133. return;
  134. }
  135. // Start point
  136. const Vec3 p0 = rayOrigin;
  137. const Vec3 start = Vec3(uv, depthRef);
  138. // Project end point
  139. const Vec3 p1 = rayOrigin + rayDir * 0.1;
  140. const Vec4 end4 = projMat * Vec4(p1, 1.0);
  141. Vec3 end = end4.xyz / end4.w;
  142. end.xy = NDC_TO_UV(end.xy);
  143. // Compute the ray and step size
  144. Vec3 dir = end - start;
  145. const Vec2 texelSize = abs(dir.xy) * Vec2(depthTexSize);
  146. const F32 stepSize = length(dir.xy) / max(texelSize.x, texelSize.y);
  147. dir = normalize(dir);
  148. // Compute step
  149. I32 stepSkip = I32(bigStep);
  150. I32 step = I32(randInitialStep);
  151. // Iterate
  152. Vec3 origin;
  153. ANKI_LOOP while(maxIterations-- != 0)
  154. {
  155. origin = start + dir * (F32(step) * stepSize);
  156. // Check if it's out of the view
  157. if(origin.x <= 0.0 || origin.y <= 0.0 || origin.x >= 1.0 || origin.y >= 1.0)
  158. {
  159. break;
  160. }
  161. const F32 depth = textureLod(depthTex, depthSampler, origin.xy, depthLod).r;
  162. const Bool hit = origin.z - depth >= 0.0;
  163. if(!hit)
  164. {
  165. step += stepSkip;
  166. }
  167. else if(stepSkip > 1)
  168. {
  169. step = max(1, step - stepSkip + 1);
  170. stepSkip = stepSkip / 2;
  171. }
  172. else
  173. {
  174. // Found it
  175. // Compute attenuation
  176. const F32 blackMargin = 0.05 / 4.0;
  177. const F32 whiteMargin = 0.1 / 2.0;
  178. const Vec2 marginAttenuation2d = smoothstep(blackMargin, whiteMargin, origin.xy)
  179. * (1.0 - smoothstep(1.0 - whiteMargin, 1.0 - blackMargin, origin.xy));
  180. const F32 marginAttenuation = marginAttenuation2d.x * marginAttenuation2d.y;
  181. attenuation = marginAttenuation * cameraContribution;
  182. // ...and hit point
  183. hitPoint = origin;
  184. break;
  185. }
  186. }
  187. }
  188. void rejectBackFaces(Vec3 reflection, Vec3 normalAtHitPoint, out F32 attenuation)
  189. {
  190. attenuation = smoothstep(-0.17, 0.0, dot(normalAtHitPoint, -reflection));
  191. }