Calneon

Inverse trilerp with bilinear coords

Oct 20th, 2021 (edited)
355
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.96 KB | None | 0 0
  1. /*
  2. * Create rotation matrix
  3. */
  4. float3x3 rotMat(float angle, float3 axis)
  5. {
  6. float c, s;
  7. sincos(angle, s, c);
  8.  
  9. float t = 1 - c;
  10. float x = axis.x;
  11. float y = axis.y;
  12. float z = axis.z;
  13.  
  14. return float3x3(
  15. t * x * x + c, t * x * y - s * z, t * x * z + s * y,
  16. t * x * y + s * z, t * y * y + c, t * y * z - s * x,
  17. t * x * z - s * y, t * y * z + s * x, t * z * z + c
  18. );
  19. }
  20.  
  21. /*
  22. * Calculate barycentric coordinates from the 4 tetrahedron verts.
  23. */
  24. float4 doBary(float3 p, float3 a, float3 b, float3 c, float3 d)
  25. {
  26. float3 vap = p - a;
  27. float3 vbp = p - b;
  28. float3 vab = b - a;
  29. float3 vac = c - a;
  30. float3 vad = d - a;
  31. float3 vbc = c - b;
  32. float3 vbd = d - b;
  33. float v6 = 1.0 / dot(vab, cross(vac, vad));
  34. float va6 = dot(vbp, cross(vbd, vbc)) * v6;
  35. float vb6 = dot(vap, cross(vac, vad)) * v6;
  36. float vc6 = dot(vap, cross(vad, vab)) * v6;
  37. return float4(va6, vb6, vc6, 1.0 - va6 - vb6 - vc6);
  38. }
  39.  
  40. /*
  41. * Calculate cartesian from barycentric coordinates using 4 tetrahedron verts.
  42. */
  43. float3 invBary(float4 bary, float3 a, float3 b, float3 c, float3 d)
  44. {
  45. float3 ret = float3(0.0, 0.0, 0.0);
  46. ret.x = bary.x * a.x + bary.y * b.x + bary.z * c.x + bary.w * d.x;
  47. ret.y = bary.x * a.y + bary.y * b.y + bary.z * c.y + bary.w * d.y;
  48. ret.z = bary.x * a.z + bary.y * b.z + bary.z * c.z + bary.w * d.z;
  49. return ret;
  50. }
  51.  
  52. struct Tetrahedra
  53. {
  54. float3 p0;
  55. float3 p1;
  56. float3 p2;
  57. float3 p3;
  58. };
  59.  
  60. Tetrahedra makeTet(float4 p0, float4 p1, float4 p2, float4 p3)
  61. {
  62. Tetrahedra t;
  63. t.p0 = p0.xyz;
  64. t.p1 = p1.xyz;
  65. t.p2 = p2.xyz;
  66. t.p3 = p3.xyz;
  67. return t;
  68. }
  69.  
  70. void tetrahedralizeCube(float4 t[4], float4 b[4], out Tetrahedra tet[5])
  71. {
  72. tet[0] = makeTet(t[0], b[2], t[3], b[0]); // centre
  73. tet[1] = makeTet(t[0], t[1], t[3], b[0]); // t0
  74. tet[2] = makeTet(t[2], t[3], t[1], b[2]); // t2
  75. tet[3] = makeTet(b[1], b[0], b[2], t[1]); // b1
  76. tet[4] = makeTet(b[3], b[2], b[0], t[3]); // b3
  77. }
  78.  
  79. /*
  80. * Map cartesian coordinate onto unit cube using barycentric coordinates.
  81. */
  82. float3 mapToUnitCube(float3 pos, float4 t[4], float4 b[4], int rot)
  83. {
  84. Tetrahedra tet[5], uTet[5];
  85.  
  86. float3x3 mRot = rotMat(PI * 0.5 * float(rot), float3(0.0, 1.0, 0.0));
  87. float4 uTop[4];
  88. uTop[0] = float4(mul(float3(1.0, 1.0, 1.0), mRot), 0.0);
  89. uTop[1] = float4(mul(float3(-1.0, 1.0, 1.0), mRot), 0.0);
  90. uTop[2] = float4(mul(float3(-1.0, 1.0, -1.0), mRot), 0.0);
  91. uTop[3] = float4(mul(float3(1.0, 1.0, -1.0), mRot), 0.0);
  92. float4 uBot[4];
  93. uBot[0] = float4(mul(float3(1.0, -1.0, 1.0), mRot), 0.0);
  94. uBot[1] = float4(mul(float3(-1.0, -1.0, 1.0), mRot), 0.0);
  95. uBot[2] = float4(mul(float3(-1.0, -1.0, -1.0), mRot), 0.0);
  96. uBot[3] = float4(mul(float3(1.0, -1.0, -1.0), mRot), 0.0);
  97.  
  98. tetrahedralizeCube(t, b, tet);
  99. tetrahedralizeCube(uTop, uBot, uTet);
  100.  
  101. float highest = -999.9;
  102. float4 bary = float4(0.0, 0.0, 0.0, 0.0);
  103. int iT = -1;
  104.  
  105. // determine which tetrahedron the point is closest to (if not inside)
  106. // by finding the barycentric coords of each tetrahedron with the largest
  107. // minimum.
  108. for (int i = 0; i < 5; i++)
  109. {
  110. float4 bTest = doBary(pos, tet[i].p0, tet[i].p1, tet[i].p2, tet[i].p3);
  111. float low = min(min(min(bTest.x, bTest.y), bTest.z), bTest.w);
  112. if (low >= 0.0)
  113. {
  114. // if all barycentric coords are positive, point is definitely within
  115. // that tetrahedra.
  116. bary = bTest;
  117. iT = i;
  118. break;
  119. }
  120. else if (low > highest)
  121. {
  122. bary = bTest;
  123. highest = low;
  124. iT = i;
  125. }
  126. }
  127. // take the barycentric coords of point on the nearest tetrahedron, and
  128. // convert back into cartesian coords using the corresponding unit tetrahedron.
  129. return invBary(bary, uTet[iT].p0, uTet[iT].p1, uTet[iT].p2, uTet[iT].p3);
  130. }
Advertisement
Add Comment
Please, Sign In to add comment