csg_test.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * DoRayMe - a quick and dirty Raytracer
  3. * CSG unit tests
  4. *
  5. * Created by Manoël Trapier
  6. * Copyright (c) 2020 986-Studio.
  7. *
  8. */
  9. #include <intersect.h>
  10. #include <intersection.h>
  11. #include <sphere.h>
  12. #include <cube.h>
  13. #include <csg.h>
  14. #include <transformation.h>
  15. #include <gtest/gtest.h>
  16. /* Proxy class to get access to protected functions / members */
  17. class CSGTest : public CSG
  18. {
  19. public:
  20. void doLocalIntersect(Ray r, Intersect &xs) {
  21. return this->localIntersect(r, xs);
  22. };
  23. Tuple doLocalNormalAt(Tuple point, Intersection *hit = nullptr) {
  24. return this->localNormalAt(point, hit);
  25. };
  26. BoundingBox doGetLocalBounds() {
  27. return this->getLocalBounds();
  28. };
  29. bool doIntersectionAllowed(bool leftHit, bool inLeft, bool inRight) {
  30. return this->intersectionAllowed(leftHit, inLeft, inRight);
  31. };
  32. void doFilterIntersections(Intersect &xs, Intersect &ret) {
  33. this->filterIntersections(xs, ret);
  34. }
  35. CSGTest(OperationType operation, Shape *left, Shape *right) : CSG(operation, left, right) {};
  36. Shape *getLeft() { return this->left; };
  37. Shape *getRight() { return this->right; };
  38. OperationType getOperation() { return this->operation; };
  39. void setOperation(OperationType operation) { this->operation = operation; };
  40. };
  41. TEST(CSGTest, Csg_is_created_with_an_operation_and_two_shape)
  42. {
  43. Sphere s1 = Sphere();
  44. Cube s2 = Cube();
  45. CSGTest c = CSGTest(CSG::UNION, &s1, &s2);
  46. ASSERT_EQ(c.getOperation(), CSG::UNION);
  47. ASSERT_EQ(*c.getLeft(), s1);
  48. ASSERT_EQ(*c.getRight(), s2);
  49. ASSERT_EQ(*s1.parent, c);
  50. ASSERT_EQ(*s2.parent, c);
  51. }
  52. TEST(CSGTest, Evaluating_the_rules_for_a_csg_operation)
  53. {
  54. Sphere s1 = Sphere();
  55. Cube s2 = Cube();
  56. CSGTest c = CSGTest(CSG::UNION, &s1, &s2);
  57. CSG::OperationType testList2[] = {
  58. CSG::UNION, CSG::UNION,
  59. CSG::UNION, CSG::UNION,
  60. CSG::UNION, CSG::UNION,
  61. CSG::UNION, CSG::UNION,
  62. CSG::INTERSECTION, CSG::INTERSECTION,
  63. CSG::INTERSECTION, CSG::INTERSECTION,
  64. CSG::INTERSECTION, CSG::INTERSECTION,
  65. CSG::INTERSECTION, CSG::INTERSECTION,
  66. CSG::DIFFERENCE, CSG::DIFFERENCE,
  67. CSG::DIFFERENCE, CSG::DIFFERENCE,
  68. CSG::DIFFERENCE, CSG::DIFFERENCE,
  69. CSG::DIFFERENCE, CSG::DIFFERENCE,
  70. };
  71. bool testList[][3] = {
  72. /* lhit, inl, inr */
  73. /* UNION */ { true, true, true },
  74. { true, true, false },
  75. { true, false, true },
  76. { true, false, false },
  77. { false, true, true },
  78. { false, true, false },
  79. { false, false, true },
  80. { false, false, false },
  81. /* INTER */ { true, true, true },
  82. { true, true, false },
  83. { true, false, true },
  84. { true, false, false },
  85. { false, true, true },
  86. { false, true, false },
  87. { false, false, true },
  88. { false, false, false },
  89. /* DIFFE */ { true, true, true },
  90. { true, true, false },
  91. { true, false, true },
  92. { true, false, false },
  93. { false, true, true },
  94. { false, true, false },
  95. { false, false, true },
  96. { false, false, false },
  97. };
  98. bool testResults[] {
  99. /* Unions */
  100. false,
  101. true,
  102. false,
  103. true,
  104. false,
  105. false,
  106. true,
  107. true,
  108. /* Intersection */
  109. true,
  110. false,
  111. true,
  112. false,
  113. true,
  114. true,
  115. false,
  116. false,
  117. /* difference */
  118. false,
  119. true,
  120. false,
  121. true,
  122. true,
  123. true,
  124. false,
  125. false
  126. };
  127. int testCount = sizeof(testList)/sizeof((testList)[0]);
  128. int i;
  129. for(i = 0; i < testCount; i++)
  130. {
  131. c.setOperation(testList2[i]);
  132. ASSERT_EQ(c.doIntersectionAllowed(testList[i][0], testList[i][1], testList[i][2]), testResults[i]);
  133. }
  134. }
  135. TEST(CSGTest, Filtering_a_list_of_intersections)
  136. {
  137. Sphere s1 = Sphere();
  138. Cube s2 = Cube();
  139. CSGTest c = CSGTest(CSG::UNION, &s1, &s2);
  140. CSG::OperationType testList[] = {
  141. CSG::UNION,
  142. CSG::INTERSECTION,
  143. CSG::DIFFERENCE,
  144. };
  145. uint32_t testResults[][2] = {
  146. {0, 3},
  147. {1, 2},
  148. {0, 1},
  149. };
  150. int testCount = sizeof(testList)/sizeof((testList)[0]);
  151. int i;
  152. Intersect xs = Intersect();
  153. Intersection i1 = Intersection(1, &s1);
  154. Intersection i2 = Intersection(2, &s2);
  155. Intersection i3 = Intersection(3, &s1);
  156. Intersection i4 = Intersection(4, &s2);
  157. xs.add(i1);
  158. xs.add(i2);
  159. xs.add(i3);
  160. xs.add(i4);
  161. for(i = 0; i < testCount; i++)
  162. {
  163. c.setOperation(testList[i]);
  164. Intersect result = Intersect();
  165. c.doFilterIntersections(xs, result);
  166. ASSERT_EQ(result.count(), 2);
  167. ASSERT_EQ(result[0], xs[testResults[i][0]]);
  168. ASSERT_EQ(result[1], xs[testResults[i][1]]);
  169. }
  170. }
  171. TEST(CSGTest, A_ray_misses_a_csg_object)
  172. {
  173. Sphere s1 = Sphere();
  174. Cube s2 = Cube();
  175. CSGTest c = CSGTest(CSG::UNION, &s1, &s2);
  176. Ray r = Ray(Point(0, 2, -5), Vector(0, 0, 1));
  177. Intersect xs; c.doLocalIntersect(r, xs);
  178. ASSERT_EQ(xs.count(), 0);
  179. }
  180. TEST(CSGTest, A_ray_hits_a_csg_object)
  181. {
  182. Sphere s1 = Sphere();
  183. Sphere s2 = Sphere();
  184. s2.setTransform(translation(0, 0, 0.5));
  185. CSGTest c = CSGTest(CSG::UNION, &s1, &s2);
  186. Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
  187. Intersect xs; c.doLocalIntersect(r, xs);
  188. ASSERT_EQ(xs.count(), 2);
  189. ASSERT_TRUE(double_equal(xs[0].t, 4));
  190. ASSERT_EQ(xs[0].object, &s1);
  191. ASSERT_TRUE(double_equal(xs[1].t, 6.5));
  192. ASSERT_EQ(xs[1].object, &s2);
  193. }