NormalReconstruction.hlsl 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #ifndef UNIVERSAL_NORMAL_RECONSTRUCTION
  2. #define UNIVERSAL_NORMAL_RECONSTRUCTION
  3. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
  4. #if defined(USING_STEREO_MATRICES)
  5. #define unity_eyeIndex unity_StereoEyeIndex
  6. #else
  7. #define unity_eyeIndex 0
  8. #endif
  9. float4x4 _NormalReconstructionMatrix[2];
  10. float GetRawDepth(float2 uv)
  11. {
  12. return SampleSceneDepth(uv.xy).r;
  13. }
  14. // inspired by keijiro's depth inverse projection
  15. // https://github.com/keijiro/DepthInverseProjection
  16. // constructs view space ray at the far clip plane from the screen uv
  17. // then multiplies that ray by the linear 01 depth
  18. float3 ViewSpacePosAtScreenUV(float2 uv)
  19. {
  20. float3 viewSpaceRay = mul(_NormalReconstructionMatrix[unity_eyeIndex], float4(uv * 2.0 - 1.0, 1.0, 1.0) * _ProjectionParams.z).xyz;
  21. float rawDepth = GetRawDepth(uv);
  22. return viewSpaceRay * Linear01Depth(rawDepth, _ZBufferParams);
  23. }
  24. float3 ViewSpacePosAtPixelPosition(float2 positionSS)
  25. {
  26. float2 uv = positionSS * _ScreenSize.zw;
  27. return ViewSpacePosAtScreenUV(uv);
  28. }
  29. half3 ReconstructNormalDerivative(float2 positionSS)
  30. {
  31. float3 viewSpacePos = ViewSpacePosAtPixelPosition(positionSS);
  32. float3 hDeriv = ddy(viewSpacePos);
  33. float3 vDeriv = ddx(viewSpacePos);
  34. return half3(normalize(cross(hDeriv, vDeriv)));
  35. }
  36. // Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
  37. // unity's compiled fragment shader stats: 33 math, 3 tex
  38. half3 ReconstructNormalTap3(float2 positionSS)
  39. {
  40. // get current pixel's view space position
  41. float3 viewSpacePos_c = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 0.0));
  42. // get view space position at 1 pixel offsets in each major direction
  43. float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
  44. float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
  45. // get the difference between the current and each offset position
  46. float3 hDeriv = viewSpacePos_r - viewSpacePos_c;
  47. float3 vDeriv = viewSpacePos_u - viewSpacePos_c;
  48. // get view space normal from the cross product of the diffs
  49. half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
  50. return viewNormal;
  51. }
  52. // Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
  53. // unity's compiled fragment shader stats: 50 math, 4 tex
  54. half3 ReconstructNormalTap4(float2 positionSS)
  55. {
  56. // get view space position at 1 pixel offsets in each major direction
  57. float3 viewSpacePos_l = ViewSpacePosAtPixelPosition(positionSS + float2(-1.0, 0.0));
  58. float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
  59. float3 viewSpacePos_d = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, -1.0));
  60. float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
  61. // get the difference between the current and each offset position
  62. float3 hDeriv = viewSpacePos_r - viewSpacePos_l;
  63. float3 vDeriv = viewSpacePos_u - viewSpacePos_d;
  64. // get view space normal from the cross product of the diffs
  65. half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
  66. return viewNormal;
  67. }
  68. // Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
  69. // unity's compiled fragment shader stats: 54 math, 5 tex
  70. half3 ReconstructNormalTap5(float2 positionSS)
  71. {
  72. // get current pixel's view space position
  73. half3 viewSpacePos_c = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 0.0));
  74. // get view space position at 1 pixel offsets in each major direction
  75. float3 viewSpacePos_l = ViewSpacePosAtPixelPosition(positionSS + float2(-1.0, 0.0));
  76. float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
  77. float3 viewSpacePos_d = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, -1.0));
  78. float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
  79. // get the difference between the current and each offset position
  80. float3 l = viewSpacePos_c - viewSpacePos_l;
  81. float3 r = viewSpacePos_r - viewSpacePos_c;
  82. float3 d = viewSpacePos_c - viewSpacePos_d;
  83. float3 u = viewSpacePos_u - viewSpacePos_c;
  84. // pick horizontal and vertical diff with the smallest z difference
  85. float3 hDeriv = abs(l.z) < abs(r.z) ? l : r;
  86. float3 vDeriv = abs(d.z) < abs(u.z) ? d : u;
  87. // get view space normal from the cross product of the two smallest offsets
  88. half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
  89. return viewNormal;
  90. }
  91. // Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
  92. // unity's compiled fragment shader stats: 66 math, 9 tex
  93. half3 ReconstructNormalTap9(float2 positionSS)
  94. {
  95. // screen uv from positionSS
  96. float2 uv = positionSS * _ScreenSize.zw;
  97. // current pixel's depth
  98. float c = GetRawDepth(uv);
  99. // get current pixel's view space position
  100. float3 viewSpacePos_c = ViewSpacePosAtScreenUV(uv);
  101. // get view space position at 1 pixel offsets in each major direction
  102. float3 viewSpacePos_l = ViewSpacePosAtScreenUV(uv + float2(-1.0, 0.0) * _ScreenSize.zw);
  103. float3 viewSpacePos_r = ViewSpacePosAtScreenUV(uv + float2(1.0, 0.0) * _ScreenSize.zw);
  104. float3 viewSpacePos_d = ViewSpacePosAtScreenUV(uv + float2(0.0, -1.0) * _ScreenSize.zw);
  105. float3 viewSpacePos_u = ViewSpacePosAtScreenUV(uv + float2(0.0, 1.0) * _ScreenSize.zw);
  106. // get the difference between the current and each offset position
  107. float3 l = viewSpacePos_c - viewSpacePos_l;
  108. float3 r = viewSpacePos_r - viewSpacePos_c;
  109. float3 d = viewSpacePos_c - viewSpacePos_d;
  110. float3 u = viewSpacePos_u - viewSpacePos_c;
  111. // get depth values at 1 & 2 pixels offsets from current along the horizontal axis
  112. half4 H = half4(
  113. GetRawDepth(uv + float2(-1.0, 0.0) * _ScreenSize.zw.xy),
  114. GetRawDepth(uv + float2(1.0, 0.0) * _ScreenSize.zw.xy),
  115. GetRawDepth(uv + float2(-2.0, 0.0) * _ScreenSize.zw.xy),
  116. GetRawDepth(uv + float2(2.0, 0.0) * _ScreenSize.zw.xy)
  117. );
  118. // get depth values at 1 & 2 pixels offsets from current along the vertical axis
  119. half4 V = half4(
  120. GetRawDepth(uv + float2(0.0, -1.0) * _ScreenSize.zw.xy),
  121. GetRawDepth(uv + float2(0.0, 1.0) * _ScreenSize.zw.xy),
  122. GetRawDepth(uv + float2(0.0, -2.0) * _ScreenSize.zw.xy),
  123. GetRawDepth(uv + float2(0.0, 2.0) * _ScreenSize.zw.xy)
  124. );
  125. // current pixel's depth difference from slope of offset depth samples
  126. // differs from original article because we're using non-linear depth values
  127. // see article's comments
  128. half2 he = abs((2 * H.xy - H.zw) - c);
  129. half2 ve = abs((2 * V.xy - V.zw) - c);
  130. // pick horizontal and vertical diff with the smallest depth difference from slopes
  131. float3 hDeriv = he.x < he.y ? l : r;
  132. float3 vDeriv = ve.x < ve.y ? d : u;
  133. // get view space normal from the cross product of the best derivatives
  134. half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
  135. return viewNormal;
  136. }
  137. #endif // UNIVERSAL_NORMAL_RECONSTRUCTION