WhiteBoxUVTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "Util/WhiteBoxTextureUtil.h"
  9. #include "WhiteBoxTestFixtures.h"
  10. #include "Rendering/Atom/WhiteBoxMeshAtomData.h"
  11. #include <AzCore/Casting/lossy_cast.h>
  12. #include <AzCore/Casting/numeric_cast.h>
  13. #include <AzCore/UnitTest/TestTypes.h>
  14. #include <AzCore/std/containers/array.h>
  15. #include <AzCore/std/containers/vector.h>
  16. #include <AzTest/AzTest.h>
  17. #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
  18. #include <WhiteBox/WhiteBoxToolApi.h>
  19. #include <cmath>
  20. #include <iostream>
  21. #include <random>
  22. #include <vector>
  23. namespace UnitTest
  24. {
  25. std::random_device rd;
  26. std::mt19937 gen(rd());
  27. // rngs for the first and subsequent significant figures of the random numbers
  28. std::uniform_real_distribution<> rndFirstSigFig(1.0, 10.0);
  29. std::uniform_real_distribution<> rndOtherSigFigs(0.0, 1.0);
  30. // generate noise after the specified decimal place with the first significant
  31. // figure always being one decimal place after afterDecimalPlace
  32. float GenerateNoiseWithSignificantFigures(AZ::u32 afterDecimalPlace)
  33. {
  34. // number of significant figures of randomness to generate
  35. const double numSigFigs = 8;
  36. // scaling factor to push the noise back into the desired range
  37. const double sigFactor = std::pow(10.0, numSigFigs + afterDecimalPlace);
  38. // random value for first guaranteed significant digit
  39. const auto firstSigFig = azlossy_cast<AZ::u64>(rndFirstSigFig(gen)) * std::pow(10.0, numSigFigs - 1);
  40. // random value for the other significant digits
  41. const auto otherSigFigs = azlossy_cast<AZ::u64>(rndOtherSigFigs(gen) * std::pow(10.0, numSigFigs - 1));
  42. // unscaled random value with rndSigFigs significant figures
  43. const auto fixedLengthRandom = firstSigFig + otherSigFigs;
  44. // scaled random value to push the noise into the desired significant digit range
  45. const float noise = aznumeric_cast<float>(fixedLengthRandom / sigFactor);
  46. return noise;
  47. }
  48. // generates a vector of Vector3s with noise for in specified range decimal places
  49. std::vector<Vector3> GenerateNoiseForSignificantFigureRange(AZ::u32 startDecimalPlace, AZ::u32 endDecimalPlace)
  50. {
  51. std::vector<Vector3> noise(endDecimalPlace - startDecimalPlace + 1);
  52. for (AZ::u32 decimal = startDecimalPlace, i = 0; decimal <= endDecimalPlace; decimal++, i++)
  53. {
  54. float x = GenerateNoiseWithSignificantFigures(decimal);
  55. float y = GenerateNoiseWithSignificantFigures(decimal);
  56. float z = GenerateNoiseWithSignificantFigures(decimal);
  57. noise[i] = Vector3{x, y, z};
  58. }
  59. return noise;
  60. }
  61. // vector of noise vectors with between 3 and 6 significat figures
  62. const std::vector<Vector3> Noise = GenerateNoiseForSignificantFigureRange(3, 6);
  63. // noise source permutations to be applied to each test
  64. const std::vector<NoiseSource> Source = {
  65. NoiseSource::None, NoiseSource::XComponent, NoiseSource::YComponent, NoiseSource::ZComponent,
  66. NoiseSource::XYComponent, NoiseSource::XZComponent, NoiseSource::YZComponent, NoiseSource::XYZComponent};
  67. enum CubeVertex : AZ::u32
  68. {
  69. FrontTopLeft,
  70. FrontTopRight,
  71. BackTopLeft,
  72. BackTopRight,
  73. FrontBottomLeft,
  74. FrontBottomRight,
  75. BackBottomLeft,
  76. BackBottomRight
  77. };
  78. const std::vector<AZ::Vector3> UnitCube = {
  79. AZ::Vector3(-0.5f, 0.5f, 0.5f), // FrontTopLeft
  80. AZ::Vector3(0.5f, 0.5f, 0.5f), // FrontTopRight
  81. AZ::Vector3(-0.5f, -0.5f, 0.5f), // BackTopLeft
  82. AZ::Vector3(0.5f, -0.5f, 0.5f), // BackTopRight
  83. AZ::Vector3(-0.5f, 0.5f, -0.5f), // FrontBottomLeft
  84. AZ::Vector3(0.5f, 0.5f, -0.5f), // FrontBottomRight
  85. AZ::Vector3(-0.5f, -0.5f, -0.5f), // BackBottomLeft
  86. AZ::Vector3(0.5f, -0.5f, -0.5f) // BackBottomRight
  87. };
  88. // returns a vector with noise applied to it as determined by the source
  89. AZ::Vector3 GenerateNoiseyVector(const AZ::Vector3& in, const Vector3& noise, NoiseSource source)
  90. {
  91. switch (source)
  92. {
  93. case NoiseSource::None:
  94. return in;
  95. case NoiseSource::XComponent:
  96. return AZ::Vector3(in.GetX() + noise.x, in.GetY(), in.GetZ());
  97. case NoiseSource::YComponent:
  98. return AZ::Vector3(in.GetX(), in.GetY() + noise.y, in.GetZ());
  99. case NoiseSource::ZComponent:
  100. return AZ::Vector3(in.GetX(), in.GetY(), in.GetZ() + noise.z);
  101. case NoiseSource::XYComponent:
  102. return AZ::Vector3(in.GetX() + noise.x, in.GetY() + noise.y, in.GetZ());
  103. case NoiseSource::XZComponent:
  104. return AZ::Vector3(in.GetX() + noise.x, in.GetY(), in.GetZ() + noise.z);
  105. case NoiseSource::YZComponent:
  106. return AZ::Vector3(in.GetX(), in.GetY() + noise.y, in.GetZ() + noise.z);
  107. case NoiseSource::XYZComponent:
  108. return AZ::Vector3(in.GetX() + noise.x, in.GetY() + noise.y, in.GetZ() + noise.z);
  109. default:
  110. return in;
  111. }
  112. }
  113. // returns a quaternion with the specified rotation
  114. AZ::Quaternion GetQuaternionFromRotation(Rotation rotation)
  115. {
  116. static const AZ::Quaternion qXAxis = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), 45);
  117. static const AZ::Quaternion qZAxis = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), 45);
  118. static const AZ::Quaternion qXZAxis = qXAxis + qZAxis;
  119. switch (rotation)
  120. {
  121. case Rotation::Identity:
  122. return AZ::Quaternion::CreateIdentity();
  123. case Rotation::XAxis:
  124. return qXAxis;
  125. case Rotation::ZAxis:
  126. return qZAxis;
  127. case Rotation::XZAxis:
  128. return qXZAxis;
  129. default:
  130. return AZ::Quaternion::CreateIdentity();
  131. }
  132. }
  133. TEST_P(WhiteBoxUVTestFixture, FrontFaceCorners)
  134. {
  135. using WhiteBox::CreatePlanarUVFromVertex;
  136. const auto& [noise, source, rotation] = GetParam();
  137. const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation);
  138. const AZ::Vector3 normal =
  139. GenerateNoiseyVector(qRotation.TransformVector(AZ::Vector3(0.0f, -1.0f, 0.0f)), noise, source);
  140. const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopLeft]);
  141. const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopRight]);
  142. const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomLeft]);
  143. const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomRight]);
  144. EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f)));
  145. EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f)));
  146. EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f)));
  147. EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f)));
  148. }
  149. TEST_P(WhiteBoxUVTestFixture, BackFaceCorners)
  150. {
  151. using WhiteBox::CreatePlanarUVFromVertex;
  152. const auto& [noise, source, rotation] = GetParam();
  153. const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation);
  154. const AZ::Vector3 normal =
  155. GenerateNoiseyVector(qRotation.TransformVector(AZ::Vector3(0.0f, 1.0f, 0.0f)), noise, source);
  156. const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopLeft]);
  157. const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopRight]);
  158. const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomLeft]);
  159. const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomRight]);
  160. EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f)));
  161. EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f)));
  162. EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f)));
  163. EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f)));
  164. }
  165. TEST_P(WhiteBoxUVTestFixture, LeftFaceCorners)
  166. {
  167. using WhiteBox::CreatePlanarUVFromVertex;
  168. const auto& [noise, source, rotation] = GetParam();
  169. const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation);
  170. const AZ::Vector3 normal =
  171. GenerateNoiseyVector(qRotation.TransformVector(AZ::Vector3(-1.0f, 0.0f, 0.0f)), noise, source);
  172. const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopLeft]);
  173. const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopLeft]);
  174. const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomLeft]);
  175. const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomLeft]);
  176. EXPECT_THAT(uv00, IsClose(AZ::Vector2(0.0f, 0.0f)));
  177. EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 1.0f)));
  178. EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 0.0f)));
  179. EXPECT_THAT(uv11, IsClose(AZ::Vector2(1.0f, 1.0f)));
  180. }
  181. TEST_P(WhiteBoxUVTestFixture, RightFaceCorners)
  182. {
  183. using WhiteBox::CreatePlanarUVFromVertex;
  184. const auto& [noise, source, rotation] = GetParam();
  185. const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation);
  186. const AZ::Vector3 normal =
  187. GenerateNoiseyVector(qRotation.TransformVector(AZ::Vector3(1.0f, 0.0f, 0.0f)), noise, source);
  188. const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopRight]);
  189. const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopRight]);
  190. const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomRight]);
  191. const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomRight]);
  192. EXPECT_THAT(uv00, IsClose(AZ::Vector2(0.0f, 0.0f)));
  193. EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 1.0f)));
  194. EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 0.0f)));
  195. EXPECT_THAT(uv11, IsClose(AZ::Vector2(1.0f, 1.0f)));
  196. }
  197. TEST_P(WhiteBoxUVTestFixture, TopFaceCorners)
  198. {
  199. using WhiteBox::CreatePlanarUVFromVertex;
  200. const auto& [noise, source, rotation] = GetParam();
  201. const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation);
  202. const AZ::Vector3 normal =
  203. GenerateNoiseyVector(qRotation.TransformVector(AZ::Vector3(0.0f, 0.0f, 1.0f)), noise, source);
  204. const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopLeft]);
  205. const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[FrontTopRight]);
  206. const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopLeft]);
  207. const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackTopRight]);
  208. EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f)));
  209. EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f)));
  210. EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f)));
  211. EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f)));
  212. }
  213. TEST_P(WhiteBoxUVTestFixture, BottomFaceCorners)
  214. {
  215. using WhiteBox::CreatePlanarUVFromVertex;
  216. const auto& [noise, source, rotation] = GetParam();
  217. const AZ::Quaternion qRotation = GetQuaternionFromRotation(rotation);
  218. const AZ::Vector3 normal =
  219. GenerateNoiseyVector(qRotation.TransformVector(AZ::Vector3(0.0f, 0.0f, -1.0f)), noise, source);
  220. const AZ::Vector2 uv00 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomLeft]);
  221. const AZ::Vector2 uv10 = CreatePlanarUVFromVertex(normal, UnitCube[FrontBottomRight]);
  222. const AZ::Vector2 uv01 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomLeft]);
  223. const AZ::Vector2 uv11 = CreatePlanarUVFromVertex(normal, UnitCube[BackBottomRight]);
  224. EXPECT_THAT(uv00, IsClose(AZ::Vector2(1.0f, 0.0f)));
  225. EXPECT_THAT(uv10, IsClose(AZ::Vector2(0.0f, 0.0f)));
  226. EXPECT_THAT(uv01, IsClose(AZ::Vector2(1.0f, 1.0f)));
  227. EXPECT_THAT(uv11, IsClose(AZ::Vector2(0.0f, 1.0f)));
  228. }
  229. // test with permutations of all noise values and sources with rotations around the x and z axis
  230. INSTANTIATE_TEST_CASE_P(
  231. , WhiteBoxUVTestFixture,
  232. ::testing::Combine(
  233. ::testing::ValuesIn(Noise), ::testing::ValuesIn(Source),
  234. ::testing::Values(Rotation::Identity, Rotation::XZAxis)));
  235. TEST(WhiteBoxRenderTest, WhiteBoxMeshAtomDataAabbIsInitializedToNull)
  236. {
  237. WhiteBox::WhiteBoxMeshAtomData atomData(WhiteBox::WhiteBoxFaces{});
  238. EXPECT_EQ(atomData.GetAabb(), AZ::Aabb::CreateNull());
  239. }
  240. } // namespace UnitTest