SAO.hx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package h3d.shader;
  2. class SAO extends ScreenShader {
  3. static var SRC = {
  4. @const var numSamples : Int;
  5. @const var numSpiralTurns : Int;
  6. @param var depthTexture : Sampler2D;
  7. @param var normalTexture : Sampler2D;
  8. @param var noiseTexture : Sampler2D;
  9. @param var noiseScale : Vec2;
  10. @param var sampleRadius : Float;
  11. @param var intensity : Float;
  12. @param var bias : Float;
  13. @param var cameraView : Mat3x4;
  14. @param var cameraInverseViewProj : Mat4;
  15. @param var screenRatio : Vec2;
  16. @param var fovTan : Float;
  17. function sampleAO(uv : Vec2, position : Vec3, normal : Vec3, radiusSS : Float, tapIndex : Int, rotationAngle : Float) : Float {
  18. // returns a unit vector and a screen-space radius for the tap on a unit disk
  19. // (the caller should scale by the actual disk radius)
  20. var alpha = (float(tapIndex) + 0.5) * (1.0 / float(numSamples));
  21. var angle = alpha * (float(numSpiralTurns) * 6.28) + rotationAngle;
  22. var unitOffset = vec2(cos(angle), sin(angle));
  23. var targetUV = uv + radiusSS * alpha * unitOffset * screenRatio;
  24. var Q = getPosition(targetUV);
  25. var v = Q - position;
  26. var vv = dot(v, v);
  27. var vn = dot(v, normal) - (bias * sampleRadius);
  28. // Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
  29. var radius2 = sampleRadius * sampleRadius;
  30. var f = max(radius2 - vv, 0.0) / radius2;
  31. var epsilon = 0.01;
  32. return f * f * f * max(vn / (epsilon + vv), 0.0);
  33. }
  34. function getPosition( uv : Vec2 ) : Vec3 {
  35. var depth = unpack(depthTexture.get(uv));
  36. var uv2 = (uv - 0.5) * vec2(2, -2);
  37. var temp = vec4(uv2, depth, 1) * cameraInverseViewProj;
  38. var originWS = temp.xyz / temp.w;
  39. return originWS;
  40. }
  41. function fragment() {
  42. var vUV = input.uv;
  43. var occlusion = 0.0;
  44. var origin = getPosition(vUV);
  45. var normal = unpackNormal(normalTexture.get(vUV));
  46. var sampleNoise = noiseTexture.get(vUV * noiseScale / screenRatio).x;
  47. var randomPatternRotationAngle = 2.0 * PI * sampleNoise;
  48. // change from WS to DepthUV space
  49. var radiusSS = (sampleRadius * fovTan) / (origin * cameraView).z;
  50. for( i in 0...numSamples )
  51. occlusion += sampleAO(vUV, origin, normal, radiusSS, i, randomPatternRotationAngle);
  52. occlusion = 1.0 - occlusion / float(numSamples);
  53. occlusion = clamp(pow(occlusion, 1.0 + intensity), 0.0, 1.0);
  54. output.color = vec4(occlusion.xxx, 1.);
  55. }
  56. };
  57. public function new() {
  58. super();
  59. numSamples = 20;
  60. sampleRadius = 1;
  61. intensity = 1;
  62. numSpiralTurns = 7;
  63. bias = 0.01;
  64. noiseScale.set(10, 10);
  65. noiseTexture = h3d.mat.Texture.genNoise(128);
  66. noiseTexture.wrap = Repeat;
  67. }
  68. }