TessellatorCS40_EdgeFactorCS.hlsl 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
  2. // CHECK: threadId
  3. // CHECK: bufferLoad
  4. // CHECK: dot2
  5. // CHECK: dot2
  6. // CHECK: FAbs
  7. // CHECK: FMin
  8. // CHECK: FMax
  9. // CHECK: dot3
  10. // CHECK: dot3
  11. // CHECK: dot3
  12. // CHECK: Sqrt
  13. // CHECK: bufferStore
  14. //--------------------------------------------------------------------------------------
  15. // File: TessellatorCS40_EdgeFactorCS.hlsl
  16. //
  17. // The CS to compute edge tessellation factor acoording to current world, view, projection matrix
  18. //
  19. // Copyright (c) Microsoft Corporation. All rights reserved.
  20. //--------------------------------------------------------------------------------------
  21. // http://jgt.akpeters.com/papers/akeninemoller01/tribox.html
  22. bool planeBoxOverlap(float3 normal, float d, float3 maxbox)
  23. {
  24. float3 vmin = maxbox, vmax = maxbox;
  25. [unroll]
  26. for (int q = 0;q <= 2; ++ q)
  27. {
  28. if (normal[q] > 0.0f)
  29. {
  30. vmin[q] *= -1;
  31. }
  32. else
  33. {
  34. vmax[q] *= -1;
  35. }
  36. }
  37. if (dot(normal, vmin) + d > 0.0f)
  38. {
  39. return false;
  40. }
  41. if (dot(normal, vmax) + d >= 0.0f)
  42. {
  43. return true;
  44. }
  45. return false;
  46. }
  47. /*======================== X-tests ========================*/
  48. bool AXISTEST_X01(float3 v0, float3 v2, float3 boxhalfsize, float2 ab, float2 fab)
  49. {
  50. float p0 = ab.x * v0.y - ab.y * v0.z;
  51. float p2 = ab.x * v2.y - ab.y * v2.z;
  52. float min_v = min(p0, p2);
  53. float max_v = max(p0, p2);
  54. float rad = dot(fab, boxhalfsize.yz);
  55. return (min_v < rad) && (max_v > -rad);
  56. }
  57. bool AXISTEST_X2(float3 v0, float3 v1, float3 boxhalfsize, float2 ab, float2 fab)
  58. {
  59. float p0 = ab.x * v0.y - ab.y * v0.z;
  60. float p1 = ab.x * v1.y - ab.y * v1.z;
  61. float min_v = min(p0, p1);
  62. float max_v = max(p0, p1);
  63. float rad = dot(fab, boxhalfsize.yz);
  64. return (min_v < rad) && (max_v > -rad);
  65. }
  66. /*======================== Y-tests ========================*/
  67. bool AXISTEST_Y02(float3 v0, float3 v2, float3 boxhalfsize, float2 ab, float2 fab)
  68. {
  69. float p0 = -ab.x * v0.x + ab.y * v0.z;
  70. float p2 = -ab.x * v2.x + ab.y * v2.z;
  71. float min_v = min(p0, p2);
  72. float max_v = max(p0, p2);
  73. float rad = dot(fab, boxhalfsize.xz);
  74. return (min_v < rad) && (max_v > -rad);
  75. }
  76. bool AXISTEST_Y1(float3 v0, float3 v1, float3 boxhalfsize, float2 ab, float2 fab)
  77. {
  78. float p0 = -ab.x * v0.x + ab.y * v0.z;
  79. float p1 = -ab.x * v1.x + ab.y * v1.z;
  80. float min_v = min(p0, p1);
  81. float max_v = max(p0, p1);
  82. float rad = dot(fab, boxhalfsize.xz);
  83. return (min_v < rad) && (max_v > -rad);
  84. }
  85. /*======================== Z-tests ========================*/
  86. bool AXISTEST_Z12(float3 v1, float3 v2, float3 boxhalfsize, float2 ab, float2 fab)
  87. {
  88. float p1 = ab.x * v1.x - ab.y * v1.y;
  89. float p2 = ab.x * v2.x - ab.y * v2.y;
  90. float min_v = min(p1, p2);
  91. float max_v = max(p1, p2);
  92. float rad = dot(fab, boxhalfsize.xy);
  93. return (min_v < rad) && (max_v > -rad);
  94. }
  95. bool AXISTEST_Z0(float3 v0, float3 v1, float3 boxhalfsize, float2 ab, float2 fab)
  96. {
  97. float p0 = ab.x * v0.x - ab.y * v0.y;
  98. float p1 = ab.x * v1.x - ab.y * v1.y;
  99. float min_v = min(p0, p1);
  100. float max_v = max(p0, p1);
  101. float rad = dot(fab, boxhalfsize.xy);
  102. return (min_v < rad) && (max_v > -rad);
  103. }
  104. bool triBoxOverlap(float3 boxcenter,float3 boxhalfsize,float3 triverts0, float3 triverts1, float3 triverts2)
  105. {
  106. /* use separating axis theorem to test overlap between triangle and box */
  107. /* need to test for overlap in these directions: */
  108. /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
  109. /* we do not even need to test these) */
  110. /* 2) normal of the triangle */
  111. /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
  112. /* this gives 3x3=9 more tests */
  113. /* This is the fastest branch on Sun */
  114. /* move everything so that the boxcenter is in (0,0,0) */
  115. float3 v0 = triverts0 - boxcenter;
  116. float3 v1 = triverts1 - boxcenter;
  117. float3 v2 = triverts2 - boxcenter;
  118. /* compute triangle edges */
  119. float3 e0 = v1 - v0; /* tri edge 0 */
  120. float3 e1 = v2 - v1; /* tri edge 1 */
  121. float3 e2 = v0 - v2; /* tri edge 2 */
  122. /* Bullet 3: */
  123. /* test the 9 tests first (this was faster) */
  124. float3 fe = abs(e0);
  125. if (!AXISTEST_X01(v0, v2, boxhalfsize, e0.zy, fe.zy)
  126. || !AXISTEST_Y02(v0, v2, boxhalfsize, e0.zx, fe.zx)
  127. || !AXISTEST_Z12(v1, v2, boxhalfsize, e0.yx, fe.yx))
  128. {
  129. return false;
  130. }
  131. fe = abs(e1);
  132. if (!AXISTEST_X01(v0, v2, boxhalfsize, e1.zy, fe.zy)
  133. || !AXISTEST_Y02(v0, v2, boxhalfsize, e1.zx, fe.zx)
  134. || !AXISTEST_Z0(v0, v1, boxhalfsize, e1.yx, fe.yx))
  135. {
  136. return false;
  137. }
  138. fe = abs(e2);
  139. if (!AXISTEST_X2(v0, v1, boxhalfsize, e2.zy, fe.zy)
  140. || !AXISTEST_Y1(v0, v1, boxhalfsize, e2.zx, fe.zx)
  141. || !AXISTEST_Z12(v1, v2, boxhalfsize, e2.yx, fe.yx))
  142. {
  143. return false;
  144. }
  145. /* Bullet 1: */
  146. /* first test overlap in the {x,y,z}-directions */
  147. /* find min, max of the triangle each direction, and test for overlap in */
  148. /* that direction -- this is equivalent to testing a minimal AABB around */
  149. /* the triangle against the AABB */
  150. float3 min_v = min(min(v0, v1), v2);
  151. float3 max_v = max(max(v0, v1), v2);
  152. if ((min_v.x > boxhalfsize.x || max_v.x < -boxhalfsize.x)
  153. || (min_v.y > boxhalfsize.y || max_v.y < -boxhalfsize.y)
  154. || (min_v.z > boxhalfsize.z || max_v.z < -boxhalfsize.z))
  155. {
  156. return false;
  157. }
  158. /* Bullet 2: */
  159. /* test if the box intersects the plane of the triangle */
  160. /* compute plane equation of triangle: normal*x+d=0 */
  161. float3 normal = cross(e0, e1);
  162. float d = -dot(normal, v0); /* plane eq: normal.x+d=0 */
  163. if (!planeBoxOverlap(normal, d, boxhalfsize))
  164. {
  165. return false;
  166. }
  167. return true; /* box and triangle overlaps */
  168. }
  169. Buffer<float4> InputVertices : register(t0);
  170. RWStructuredBuffer<float4> EdgeFactorBufOut : register(u0);
  171. cbuffer cb
  172. {
  173. row_major matrix g_matWVP;
  174. float2 g_tess_edge_length_scale;
  175. int num_triangles;
  176. float dummy;
  177. }
  178. [numthreads(128, 1, 1)]
  179. void main( uint3 DTid : SV_DispatchThreadID )
  180. {
  181. if (DTid.x < num_triangles)
  182. {
  183. float4 p0 = mul(InputVertices[DTid.x*3+0], g_matWVP);
  184. float4 p1 = mul(InputVertices[DTid.x*3+1], g_matWVP);
  185. float4 p2 = mul(InputVertices[DTid.x*3+2], g_matWVP);
  186. p0 = p0 / p0.w;
  187. p1 = p1 / p1.w;
  188. p2 = p2 / p2.w;
  189. float4 factor;
  190. // Only triangles which are completely inside or intersect with the view frustum are taken into account
  191. if ( triBoxOverlap( float3(0, 0, 0.5), float3(1.02, 1.02, 0.52), p0.xyz, p1.xyz, p2.xyz ) )
  192. {
  193. factor.x = length((p0.xy - p2.xy) * g_tess_edge_length_scale);
  194. factor.y = length((p1.xy - p0.xy) * g_tess_edge_length_scale);
  195. factor.z = length((p2.xy - p1.xy) * g_tess_edge_length_scale);
  196. factor.w = min(min(factor.x, factor.y), factor.z);
  197. factor = clamp(factor, 0, 9);
  198. } else
  199. {
  200. factor = 0;
  201. }
  202. EdgeFactorBufOut[DTid.x] = factor;
  203. }
  204. }