hbao.chunk 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. precision highp float;
  2. #include <builtin/uniforms/cc-global>
  3. #include <common/common-define>
  4. #include <common/math/coordinates>
  5. #include <common/math/number>
  6. #include <builtin/functionalities/fog>
  7. uniform hbaoUBO {
  8. vec4 uvDepthToEyePosParams;
  9. vec4 radiusParam;
  10. vec4 miscParam;
  11. vec4 randomTexSize;
  12. vec4 blurParam;
  13. };
  14. #define NUM_STEPS 8.0
  15. #define NUM_STEPS_LOOP NUM_STEPS*2.0
  16. #define INV_NUM_DIRECTIONS 0.125
  17. #define NUM_DIRECTIONS 8
  18. #define CONSTANT_2PI 6.2831852
  19. #define g_AOResolution cc_screenSize.xy
  20. #define g_InvAOResolution cc_screenSize.zw
  21. #define g_UVToViewA uvDepthToEyePosParams.xy
  22. #define g_UVToViewB uvDepthToEyePosParams.zw
  23. #define g_R radiusParam.x
  24. #define g_R2 radiusParam.y
  25. #define g_NegInvR2 radiusParam.z
  26. #define g_MaxRadiusPixels radiusParam.w
  27. #define g_FocalLen miscParam.xy
  28. #define g_TanAngleBias miscParam.z
  29. #define g_Strength miscParam.w
  30. #pragma rate DepthTex pass
  31. uniform sampler2D DepthTex; //Sample_Point_Clamp
  32. #pragma rate RandomTex
  33. uniform sampler2D RandomTex; //Sample_Point_Wrap
  34. // force clamped sample
  35. vec2 fixUV(vec2 uv)
  36. {
  37. return saturate(uv);
  38. }
  39. //----------------------------------------------------------------------------------
  40. float InvLength(vec2 v)
  41. {
  42. return rsqrt(dot(v,v));
  43. }
  44. //----------------------------------------------------------------------------------
  45. float Tangent(vec3 P, vec3 S)
  46. {
  47. return (P.z - S.z) * InvLength(S.xy - P.xy);
  48. }
  49. //----------------------------------------------------------------------------------
  50. vec3 UVToEye(vec2 uv, float eye_z)
  51. {
  52. uv = g_UVToViewA * uv + g_UVToViewB;
  53. return vec3(uv * eye_z, eye_z);
  54. }
  55. //----------------------------------------------------------------------------------
  56. float GetLinearDepth(vec2 uv) {
  57. float depthHS = 0.0;
  58. #if defined(CC_USE_WGPU)
  59. depthHS = textureLod(DepthTex, fixUV(uv), 0.0).r * 2.0 - 1.0;
  60. #else
  61. depthHS = texture(DepthTex, fixUV(uv)).r * 2.0 - 1.0; // -1.0 ~ +1.0
  62. #endif
  63. return -GetCameraDepthRH(depthHS, cc_matProj);
  64. }
  65. vec3 FetchEyePos(vec2 uv)
  66. {
  67. float depth = GetLinearDepth(uv);
  68. return UVToEye(uv, depth);
  69. }
  70. //----------------------------------------------------------------------------------
  71. float Length2(vec3 v)
  72. {
  73. return dot(v, v);
  74. }
  75. //----------------------------------------------------------------------------------
  76. vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl)
  77. {
  78. vec3 V1 = Pr - P;
  79. vec3 V2 = P - Pl;
  80. return (Length2(V1) < Length2(V2)) ? V1 : V2;
  81. }
  82. //----------------------------------------------------------------------------------
  83. float Falloff(float d2)
  84. {
  85. // 1 scalar mad instruction
  86. return d2 * g_NegInvR2 + 1.0;
  87. }
  88. //----------------------------------------------------------------------------------
  89. vec2 SnapUVOffset(vec2 uv)
  90. {
  91. return round(uv * g_AOResolution) * g_InvAOResolution;
  92. }
  93. //----------------------------------------------------------------------------------
  94. float TanToSin(float x)
  95. {
  96. return x * rsqrt(x*x + 1.0);
  97. }
  98. //----------------------------------------------------------------------------------
  99. vec3 TangentVector(vec2 deltaUV, vec3 dPdu, vec3 dPdv)
  100. {
  101. return deltaUV.x * dPdu + deltaUV.y * dPdv;
  102. }
  103. //----------------------------------------------------------------------------------
  104. float Tangent(vec3 T)
  105. {
  106. return -T.z * InvLength(T.xy);
  107. }
  108. //----------------------------------------------------------------------------------
  109. float BiasedTangent(vec3 T)
  110. {
  111. // Do not use atan() because it gets expanded by fxc to many math instructions
  112. return Tangent(T) + g_TanAngleBias;
  113. }
  114. //----------------------------------------------------------------------------------
  115. vec2 RotateDirections(vec2 Dir, vec2 CosSin)
  116. {
  117. return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y,
  118. Dir.x*CosSin.y + Dir.y*CosSin.x);
  119. }
  120. //----------------------------------------------------------------------------------
  121. float IntegerateOcclusion(vec2 uv0,
  122. vec2 snapped_duv,
  123. vec3 P,
  124. vec3 dPdu,
  125. vec3 dPdv,
  126. inout float tanH)
  127. {
  128. float ao = 0.0;
  129. // Compute a tangent vector for snapped_duv
  130. vec3 T1 = TangentVector(snapped_duv, dPdu, dPdv);
  131. float tanT = BiasedTangent(T1);
  132. float sinT = TanToSin(tanT);
  133. vec3 S = FetchEyePos(uv0 + snapped_duv);
  134. float tanS = Tangent(P, S);
  135. float sinS = TanToSin(tanS);
  136. float d2 = Length2(S - P);
  137. if ((d2 < g_R2) && (tanS > tanT))
  138. {
  139. // Compute AO between the tangent plane and the sample
  140. ao = Falloff(d2) * (sinS - sinT);
  141. // Update the horizon angle
  142. tanH = max(tanH, tanS);
  143. }
  144. return ao;
  145. }
  146. //----------------------------------------------------------------------------------
  147. float HorizonOcclusion(vec2 deltaUV,
  148. vec2 texelDeltaUV,
  149. vec2 uv0,
  150. vec3 P,
  151. float numSteps,
  152. float randstep,
  153. vec3 dPdu,
  154. vec3 dPdv)
  155. {
  156. float ao = 0.0;
  157. // Randomize starting point within the first sample distance
  158. vec2 uv = uv0 + SnapUVOffset( randstep * deltaUV );
  159. // Snap increments to pixels to avoid disparities between xy
  160. // and z sample locations and sample along a line
  161. deltaUV = SnapUVOffset( deltaUV );
  162. // Compute tangent vector using the tangent plane
  163. vec3 T = deltaUV.x * dPdu + deltaUV.y * dPdv;
  164. float tanH = BiasedTangent(T);
  165. #if SAMPLE_FIRST_STEP
  166. // Take a first sample between uv0 and uv0 + deltaUV
  167. vec2 snapped_duv = SnapUVOffset( randstep * deltaUV + texelDeltaUV );
  168. ao = IntegerateOcclusion(uv0, snapped_duv, P, dPdu, dPdv, tanH);
  169. --numSteps;
  170. #endif
  171. float sinH = tanH / sqrt(1.0 + tanH*tanH);
  172. // for (int j = 1; j <= numSteps; ++j)
  173. for (float j = 1.0; j <= NUM_STEPS_LOOP; j += 1.0)
  174. {
  175. if (j <= numSteps)
  176. {
  177. uv += deltaUV;
  178. vec3 S = FetchEyePos(uv);
  179. float tanS = Tangent(P, S);
  180. float d2 = Length2(S - P);
  181. if ((d2 < g_R2) && (tanS > tanH))
  182. {
  183. // Accumulate AO between the horizon and the sample
  184. float sinS = tanS / sqrt(1.0 + tanS*tanS);
  185. ao += Falloff(d2) * (sinS - sinH);
  186. // Update the current horizon angle
  187. tanH = tanS;
  188. sinH = sinS;
  189. }
  190. }
  191. }
  192. return ao;
  193. }
  194. //----------------------------------------------------------------------------------
  195. void ComputeSteps(inout vec2 step_size_uv, inout float numSteps, float ray_radius_pix, float rand)
  196. {
  197. // Avoid oversampling if NUM_STEPS is greater than the kernel radius in pixels
  198. numSteps = min(NUM_STEPS, ray_radius_pix);
  199. // Divide by Ns+1 so that the farthest samples are not fully attenuated
  200. float step_size_pix = ray_radius_pix / (numSteps + 1.0);
  201. // Clamp numSteps if it is greater than the max kernel footprint
  202. float maxNumSteps = g_MaxRadiusPixels / step_size_pix;
  203. if (maxNumSteps < numSteps)
  204. {
  205. // Use dithering to avoid AO discontinuities
  206. numSteps = floor(maxNumSteps + rand);
  207. numSteps = max(numSteps, 1.0);
  208. step_size_pix = g_MaxRadiusPixels / numSteps;
  209. }
  210. // Step size in uv space
  211. step_size_uv = step_size_pix * g_InvAOResolution;
  212. }
  213. //----------------------------------------------------------------------------------
  214. float CalculateAO(vec2 uv)
  215. {
  216. vec3 P = FetchEyePos(uv);
  217. // (cos(alpha),sin(alpha),jitter)
  218. vec3 rand = texture(RandomTex, uv * g_AOResolution.xy * randomTexSize.zw).xyz;
  219. // Compute projection of disk of radius g_R into uv space
  220. // Multiply by 0.5 to scale from [-1,1]^2 to [0,1]^2
  221. vec2 ray_radius_uv = 0.5 * g_R * g_FocalLen / P.z;
  222. float ray_radius_pix = ray_radius_uv.x * g_AOResolution.x;
  223. if (ray_radius_pix < 1.0)
  224. {
  225. return 1.0;
  226. }
  227. float numSteps;
  228. vec2 step_size;
  229. ComputeSteps(step_size, numSteps, ray_radius_pix, rand.z);
  230. // Nearest neighbor pixels on the tangent plane
  231. vec3 Pr = FetchEyePos(uv + vec2(g_InvAOResolution.x, 0.0));
  232. vec3 Pl = FetchEyePos(uv + vec2(-g_InvAOResolution.x, 0.0));
  233. vec3 Pt = FetchEyePos(uv + vec2(0.0, g_InvAOResolution.y));
  234. vec3 Pb = FetchEyePos(uv + vec2(0.0, -g_InvAOResolution.y));
  235. // Screen-aligned basis for the tangent plane
  236. vec3 dPdu = MinDiff(P, Pr, Pl);
  237. vec3 dPdv = MinDiff(P, Pt, Pb) * (g_AOResolution.y * g_InvAOResolution.x);
  238. float ao = 0.0;
  239. float alpha = CONSTANT_2PI * INV_NUM_DIRECTIONS;
  240. // this switch gets unrolled by the HLSL compiler
  241. for (int d = 0; d < NUM_DIRECTIONS; ++d)
  242. {
  243. float angle = alpha * float(d);
  244. vec2 dir = RotateDirections(vec2(cos(angle), sin(angle)), rand.xy);
  245. vec2 deltaUV = dir * step_size.xy;
  246. vec2 texelDeltaUV = dir * g_InvAOResolution;
  247. ao += HorizonOcclusion(deltaUV, texelDeltaUV, uv, P, numSteps, rand.z, dPdu, dPdv);
  248. }
  249. ao = 1.0 - ao * INV_NUM_DIRECTIONS * g_Strength;
  250. #if CC_USE_FOG != CC_FOG_NONE && !CC_USE_FLOAT_OUTPUT
  251. float fogFactor = 1.0; // no fog
  252. float depth = 0.0;
  253. #if defined(CC_USE_WGPU)
  254. depth = textureLod(DepthTex, uv, 0.0).r;
  255. #else
  256. depth = texture(DepthTex, uv).r;
  257. #endif
  258. vec3 posHS = vec3(uv, depth) * 2.0 - vec3(1.0);
  259. CC_HANDLE_GET_CLIP_FLIP(posHS.xy);
  260. vec4 worldPos = GetWorldPosFromNDCPosRH(posHS, cc_matProj, cc_matViewProjInv);
  261. CC_TRANSFER_FOG_BASE(vec4(worldPos.xyz, 1.0), fogFactor);
  262. // ao has less effect while fogFactor value is small
  263. ao = mix(1.0, ao, pow(fogFactor * 0.9, 4.0));
  264. #endif
  265. return ao;
  266. //return vec4(ao, P.z, 0, 0);
  267. }
  268. ///////////////////////////////////////Blur
  269. #define KERNEL_FALLOFF 3.0f
  270. #define KERNEL_RADIUS 8
  271. //#define HALF_KERNEL_RADIUS (KERNEL_RADIUS/2)
  272. #define HALF_KERNEL_RADIUS 4 // should as same as ubo parameter calculation
  273. #define g_InvFullResolution cc_screenSize.zw
  274. #define g_BlurFallOff blurParam.x
  275. #define g_BlurDepthThreshold blurParam.y
  276. #define g_BlurSimpleRadius blurParam.z
  277. #pragma rate AOTexNearest pass
  278. uniform sampler2D AOTexNearest; //Sample_Point_Clamp
  279. // todo: maybe need bilinear filter
  280. #define AOTexBilinear AOTexNearest
  281. #define GetLinearDepthBilinear GetLinearDepth
  282. float CrossBilateralWeight(float r, float d, float d0, float blurFalloff, float blurDepthThreshold)
  283. {
  284. return exp2(-r*r*blurFalloff) * (abs(d - d0) < blurDepthThreshold ? 1.0 : 0.0);
  285. }
  286. vec2 SumWeightedAO(int i, float centerCameraDepth, vec2 centerUV, vec2 sampleDir, float blurFalloff, float blurDepthThreshold)
  287. {
  288. // step = 2
  289. float r = 2.0 * float(i) + 0.5;
  290. vec2 sampleUV = centerUV + r * sampleDir * g_InvFullResolution;
  291. float d = GetLinearDepthBilinear(sampleUV);
  292. float sampledAO = texture(AOTexNearest/*AOTexBilinear*/, fixUV(sampleUV)).x;
  293. float w = CrossBilateralWeight(r, d, centerCameraDepth, blurFalloff, blurDepthThreshold);
  294. return vec2(w * sampledAO, w);
  295. }
  296. float BlurCore(vec2 uv, vec2 sampleDir)
  297. {
  298. float ao = texture(AOTexNearest, uv).x;
  299. float weight = 1.0;
  300. float centerCameraDepth = GetLinearDepth(uv);
  301. for(int i = -HALF_KERNEL_RADIUS; i <= HALF_KERNEL_RADIUS; i++)
  302. {
  303. vec2 aoAndW = SumWeightedAO(i, centerCameraDepth, uv, sampleDir, g_BlurFallOff, g_BlurDepthThreshold);
  304. ao += aoAndW.x;
  305. weight += aoAndW.y;
  306. }
  307. return ao / weight;
  308. }
  309. ///////////////////////////////////////Composite
  310. #define g_AOSaturation blurParam.w
  311. float Combine(vec2 uv)
  312. {
  313. float ao = texture(AOTexNearest, uv).x;
  314. return g_AOSaturation > 1.0 ? pow(ao, g_AOSaturation) : mix(1.0, ao, g_AOSaturation);
  315. }