説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

NormalSurfaceGradient.hlsl 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #ifndef NORMAL_SURFACE_GRADIENT_HLSL
  2. #define NORMAL_SURFACE_GRADIENT_HLSL
  3. // this produces an orthonormal basis of the tangent and bitangent WITHOUT vertex level tangent/bitangent for any UV including procedurally generated
  4. // method released with the demo for publication of "bump mapping unparametrized surfaces on the GPU"
  5. // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
  6. void SurfaceGradientGenBasisTB(float3 nrmVertexNormal, float3 sigmaX, float3 sigmaY, float flipSign, float2 texST, out float3 vT, out float3 vB)
  7. {
  8. float2 dSTdx = ddx_fine(texST), dSTdy = ddy_fine(texST);
  9. float det = dot(dSTdx, float2(dSTdy.y, -dSTdy.x));
  10. float sign_det = det < 0 ? -1 : 1;
  11. // invC0 represents (dXds, dYds); but we don't divide by determinant (scale by sign instead)
  12. float2 invC0 = sign_det * float2(dSTdy.y, -dSTdx.y);
  13. vT = sigmaX * invC0.x + sigmaY * invC0.y;
  14. if (abs(det) > 0.0)
  15. vT = normalize(vT);
  16. vB = (sign_det * flipSign) * cross(nrmVertexNormal, vT);
  17. }
  18. // surface gradient from an on the fly TBN (deriv obtained using tspaceNormalToDerivative()) or from conventional vertex level TBN (mikktspace compliant and deriv obtained using tspaceNormalToDerivative())
  19. real3 SurfaceGradientFromTBN(real2 deriv, real3 vT, real3 vB)
  20. {
  21. return deriv.x * vT + deriv.y * vB;
  22. }
  23. // surface gradient from an already generated "normal" such as from an object or world space normal map
  24. // CAUTION: nrmVertexNormal and v must be in the same space. i.e world or object
  25. // this allows us to mix the contribution together with a series of other contributions including tangent space normals
  26. // v does not need to be unit length as long as it establishes the direction.
  27. real3 SurfaceGradientFromPerturbedNormal(real3 nrmVertexNormal, real3 v)
  28. {
  29. real3 n = nrmVertexNormal;
  30. real s = 1.0 / max(REAL_EPS, abs(dot(n, v)));
  31. return s * (dot(n, v) * n - v);
  32. }
  33. // used to produce a surface gradient from the gradient of a volume bump function such as a volume of perlin noise.
  34. // equation 2. in "bump mapping unparametrized surfaces on the GPU".
  35. // Observe the difference in figure 2. between using the gradient vs. the surface gradient to do bump mapping (the original method is proved wrong in the paper!).
  36. real3 SurfaceGradientFromVolumeGradient(real3 nrmVertexNormal, real3 grad)
  37. {
  38. return grad - dot(nrmVertexNormal, grad) * nrmVertexNormal;
  39. }
  40. // triplanar projection considered special case of volume bump map
  41. // described here: http://mmikkelsen3d.blogspot.com/2013/10/volume-height-maps-and-triplanar-bump.html
  42. // derivs obtained using tspaceNormalToDerivative() and weights using computeTriplanarWeights().
  43. real3 SurfaceGradientFromTriplanarProjection(real3 nrmVertexNormal, real3 triplanarWeights, real2 deriv_xplane, real2 deriv_yplane, real2 deriv_zplane)
  44. {
  45. const real w0 = triplanarWeights.x, w1 = triplanarWeights.y, w2 = triplanarWeights.z;
  46. // Assume derivXplane, derivYPlane and derivZPlane sampled using (z,y), (x,z) and (x,y) respectively
  47. // (ie using Morten's convention http://jcgt.org/published/0009/03/04/ p80-81 for left handed worldspace)
  48. // positive scales of the look-up coordinate will work as well but for negative scales the derivative components will need to be negated accordingly.
  49. real3 volumeGrad = real3(w2 * deriv_zplane.x + w1 * deriv_yplane.x, w2 * deriv_zplane.y + w0 * deriv_xplane.y, w0 * deriv_xplane.x + w1 * deriv_yplane.y);
  50. return SurfaceGradientFromVolumeGradient(nrmVertexNormal, volumeGrad);
  51. }
  52. real3 SurfaceGradientResolveNormal(real3 nrmVertexNormal, real3 surfGrad)
  53. {
  54. return SafeNormalize(nrmVertexNormal - surfGrad);
  55. }
  56. real2 ConvertTangentSpaceNormalToHeightMapGradient(real2 normalXY, real rcpNormalZ, real scale)
  57. {
  58. // scale * (-normal.xy / normal.z)
  59. return normalXY * (-rcpNormalZ * scale);
  60. }
  61. real3 SurfaceGradientFromTangentSpaceNormalAndFromTBN(real3 normalTS, real3 vT, real3 vB, real scale = 1.0)
  62. {
  63. float2 deriv = ConvertTangentSpaceNormalToHeightMapGradient(normalTS.xy, rcp(max(normalTS.z, REAL_EPS)), scale);
  64. return SurfaceGradientFromTBN(deriv, vT, vB);
  65. }
  66. // Converts tangent space normal to slopes (height map gradient).
  67. real2 UnpackDerivativeNormalRGB(real4 packedNormal, real scale = 1.0)
  68. {
  69. real3 vT = packedNormal.rgb * 2.0 - 1.0; // Unsigned to signed
  70. real rcpZ = rcp(max(vT.z, REAL_EPS)); // Clamp to avoid INF
  71. return ConvertTangentSpaceNormalToHeightMapGradient(vT.xy, rcpZ, scale);
  72. }
  73. // Converts tangent space normal to slopes (height map gradient).
  74. real2 UnpackDerivativeNormalAG(real4 packedNormal, real scale = 1.0)
  75. {
  76. real2 vT = packedNormal.ag * 2.0 - 1.0; // Unsigned to signed
  77. real rcpZ = rsqrt(max(1 - Sq(vT.x) - Sq(vT.y), HALF_MIN_SQRT)); // Clamp to avoid INF
  78. return ConvertTangentSpaceNormalToHeightMapGradient(vT.xy, rcpZ, scale);
  79. }
  80. // Unpack normal as DXT5nm (1, y, 0, x) or BC5 (x, y, 0, 1)
  81. real2 UnpackDerivativeNormalRGorAG(real4 packedNormal, real scale = 1.0)
  82. {
  83. // Convert to (?, y, 0, x)
  84. packedNormal.a *= packedNormal.r;
  85. return UnpackDerivativeNormalAG(packedNormal, scale);
  86. }
  87. #endif // NORMAL_SURFACE_GRADIENT_HLSL