Clusterer.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <tests/framework/Framework.h>
  6. #include <anki/renderer/Clusterer.h>
  7. #include <anki/Collision.h>
  8. #include <anki/util/ThreadPool.h>
  9. #include "anki/util/HighRezTimer.h"
  10. namespace anki
  11. {
  12. ANKI_TEST(Renderer, Clusterer)
  13. {
  14. const U CLUSTER_COUNT_X = 32;
  15. const U CLUSTER_COUNT_Y = 24;
  16. const U CLUSTER_COUNT_Z = 32;
  17. const U ITERATION_COUNT = 32;
  18. const U SPHERE_COUNT = 1024;
  19. const F32 SPHERE_MAX_RADIUS = 1000.0;
  20. const F32 E = 0.01;
  21. const U FRUSTUM_COUNT = 1024;
  22. const F32 FRUSTUM_MAX_ANGLE = toRad(70.0);
  23. const F32 FRUSTUM_MAX_DIST = 200.0;
  24. HeapAllocator<U8> alloc(allocAligned, nullptr);
  25. Clusterer c;
  26. c.init(alloc, CLUSTER_COUNT_X, CLUSTER_COUNT_Y, CLUSTER_COUNT_Z);
  27. PerspectiveFrustum fr(toRad(70.0), toRad(60.0), 0.1, 1000.0);
  28. Mat4 projMat = fr.calculateProjectionMatrix();
  29. Vec4 unprojParams = projMat.extractPerspectiveUnprojectionParams();
  30. ThreadPool threadpool(4);
  31. // Gen spheres
  32. DynamicArrayAuto<Sphere> spheres(alloc);
  33. spheres.create(SPHERE_COUNT);
  34. DynamicArrayAuto<Aabb> sphereBoxes(alloc);
  35. sphereBoxes.create(SPHERE_COUNT);
  36. for(U i = 0; i < SPHERE_COUNT; ++i)
  37. {
  38. Vec2 ndc;
  39. ndc.x() = clamp((i % 64) / 64.0f, E, 1.0f - E) * 2.0f - 1.0f;
  40. ndc.y() = ndc.x();
  41. F32 depth = clamp((i % 128) / 128.0f, E, 1.0f - E);
  42. F32 z = unprojParams.z() / (unprojParams.w() + depth);
  43. Vec2 xy = ndc.xy() * unprojParams.xy() * z;
  44. Vec4 sphereC(xy, z, 0.0);
  45. F32 radius = max((i % 64) / 64.0f, 0.1f) * SPHERE_MAX_RADIUS;
  46. spheres[i] = Sphere(sphereC, radius);
  47. spheres[i].computeAabb(sphereBoxes[i]);
  48. }
  49. // Bin spheres
  50. HighRezTimer timer;
  51. timer.start();
  52. U clusterBinCount = 0;
  53. for(U i = 0; i < ITERATION_COUNT; ++i)
  54. {
  55. Transform camTrf(Vec4(0.1, 0.1, 0.1, 0.0), Mat3x4::getIdentity(), 1.0);
  56. ClustererPrepareInfo pinf;
  57. pinf.m_viewMat = Mat4(camTrf).getInverse();
  58. pinf.m_projMat = projMat;
  59. pinf.m_camTrf = camTrf;
  60. c.prepare(threadpool, pinf);
  61. ClustererTestResult rez;
  62. c.initTestResults(alloc, rez);
  63. for(U s = 0; s < SPHERE_COUNT; ++s)
  64. {
  65. c.bin(spheres[s], sphereBoxes[s], rez);
  66. ANKI_TEST_EXPECT_GT(rez.getClusterCount(), 0);
  67. clusterBinCount += rez.getClusterCount();
  68. }
  69. }
  70. timer.stop();
  71. F64 ms = timer.getElapsedTime() * 1000.0;
  72. printf("Cluster count: %u.\n"
  73. "Binned %f spheres/ms.\n"
  74. "Avg clusters per sphere %f\n",
  75. unsigned(c.getClusterCount()),
  76. F64(SPHERE_COUNT) * F64(ITERATION_COUNT) / ms,
  77. clusterBinCount / F32(ITERATION_COUNT * SPHERE_COUNT));
  78. // Gen spheres
  79. DynamicArrayAuto<PerspectiveFrustum> frs(alloc);
  80. frs.create(FRUSTUM_COUNT);
  81. DynamicArrayAuto<Aabb> frBoxes(alloc);
  82. frBoxes.create(FRUSTUM_COUNT);
  83. for(U i = 0; i < FRUSTUM_COUNT; ++i)
  84. {
  85. Vec2 ndc;
  86. ndc.x() = clamp((i % 64) / 64.0f, E, 1.0f - E) * 2.0f - 1.0f;
  87. ndc.y() = ndc.x();
  88. F32 depth = clamp((i % 128) / 128.0f, E, 1.0f - E);
  89. F32 z = unprojParams.z() / (unprojParams.w() + depth);
  90. Vec2 xy = ndc.xy() * unprojParams.xy() * z;
  91. Vec4 c(xy, z, 0.0);
  92. F32 dist = max((i % 64) / 64.0f, 0.1f) * FRUSTUM_MAX_DIST;
  93. F32 ang = max((i % 64) / 64.0f, 0.2f) * FRUSTUM_MAX_ANGLE;
  94. frs[i] = PerspectiveFrustum(ang, ang, 0.1, dist);
  95. frs[i].transform(Transform(c, Mat3x4::getIdentity(), 1.0));
  96. frs[i].computeAabb(frBoxes[i]);
  97. }
  98. // Bin frustums
  99. timer.start();
  100. clusterBinCount = 0;
  101. for(U i = 0; i < ITERATION_COUNT; ++i)
  102. {
  103. Transform camTrf(Vec4(0.1, 0.1, 0.1, 0.0), Mat3x4::getIdentity(), 1.0);
  104. ClustererPrepareInfo pinf;
  105. pinf.m_viewMat = Mat4(camTrf).getInverse();
  106. pinf.m_projMat = projMat;
  107. pinf.m_camTrf = camTrf;
  108. c.prepare(threadpool, pinf);
  109. ClustererTestResult rez;
  110. c.initTestResults(alloc, rez);
  111. for(U s = 0; s < FRUSTUM_COUNT; ++s)
  112. {
  113. c.binPerspectiveFrustum(frs[s], frBoxes[s], rez);
  114. ANKI_TEST_EXPECT_GT(rez.getClusterCount(), 0);
  115. clusterBinCount += rez.getClusterCount();
  116. }
  117. }
  118. timer.stop();
  119. ms = timer.getElapsedTime() * 1000.0;
  120. printf("Binned %f frustums/ms.\n"
  121. "Avg clusters per frustum %f\n",
  122. F64(FRUSTUM_COUNT) * F64(ITERATION_COUNT) / ms,
  123. clusterBinCount / F32(ITERATION_COUNT * FRUSTUM_COUNT));
  124. }
  125. } // end namespace anki