TerrainBulkQueryTests.cpp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  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 <AzCore/std/parallel/semaphore.h>
  9. #include <AzTest/AzTest.h>
  10. #include <TerrainSystem/TerrainSystem.h>
  11. #include <TerrainTestFixtures.h>
  12. namespace UnitTest::TerrainTest
  13. {
  14. /* The TerrainBulkQueryTest suite of tests exist to verify that all of our different query APIs produce the same results.
  15. * These tests were added after discovering that the async queries could sometimes produce intermittently incorrect results due
  16. * to a lack of proper thread safety. However, it's also possible that optimizations to the different queries could accidentally
  17. * produce different results as well, so it's good to have this safety net here.
  18. */
  19. class TerrainBulkQueryTest
  20. : public TerrainTestFixture
  21. {
  22. protected:
  23. // Use the ProcessHeightsFromRegion API as our baseline that we'll compare the other query APIs against.
  24. void GenerateBaselineHeightData(
  25. const AZ::Aabb& inputQueryRegion,
  26. const AZ::Vector2& inputQueryStepSize,
  27. AzFramework::Terrain::TerrainDataRequests::Sampler sampler,
  28. AZStd::vector<AZ::Vector3>& queryPositions,
  29. AZStd::vector<AZ::Vector3>& resultPositions,
  30. AZStd::vector<bool>& resultExistsFlags)
  31. {
  32. queryPositions.clear();
  33. resultPositions.clear();
  34. resultExistsFlags.clear();
  35. auto perPositionCallback = [&queryPositions, &resultPositions, &resultExistsFlags](
  36. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  37. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  38. {
  39. queryPositions.emplace_back(surfacePoint.m_position.GetX(), surfacePoint.m_position.GetY(), 0.0f);
  40. resultPositions.emplace_back(surfacePoint.m_position);
  41. resultExistsFlags.emplace_back(terrainExists);
  42. };
  43. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  44. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(inputQueryRegion, inputQueryStepSize);
  45. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  46. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  47. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, perPositionCallback, sampler);
  48. EXPECT_EQ(queryPositions.size(), resultPositions.size());
  49. }
  50. // Compare two sets of output data and verify that they match.
  51. void ComparePositionData(const AZStd::vector<AZ::Vector3>& baselineValues, const AZStd::vector<bool>& baselineExistsFlags,
  52. const AZStd::vector<AZ::Vector3>& comparisonValues, const AZStd::vector<bool>& comparisonExistsFlags)
  53. {
  54. // Verify that we have the same quantity of results in both sets.
  55. ASSERT_EQ(baselineValues.size(), comparisonValues.size());
  56. // Verify that every value is found exactly once in each set. The two sets might not have the values in the same order though,
  57. // so we need to search for each value, verify it's found, and verify that it hadn't previously been found.
  58. AZStd::vector<bool> matchFound(baselineValues.size(), false);
  59. for (size_t comparisonIndex = 0; comparisonIndex < comparisonValues.size(); comparisonIndex++)
  60. {
  61. auto foundValue = AZStd::find(baselineValues.begin(), baselineValues.end(), comparisonValues[comparisonIndex]);
  62. EXPECT_NE(foundValue, baselineValues.end());
  63. if (foundValue != baselineValues.end())
  64. {
  65. size_t foundIndex = foundValue - baselineValues.begin();
  66. EXPECT_FALSE(matchFound[foundIndex]);
  67. EXPECT_EQ(baselineExistsFlags[foundIndex], comparisonExistsFlags[comparisonIndex]);
  68. matchFound[foundIndex] = true;
  69. }
  70. }
  71. }
  72. // Use the ProcessNormalsFromRegion API as our baseline that we'll compare the other query APIs against.
  73. void GenerateBaselineNormalData(
  74. const AZ::Aabb& inputQueryRegion,
  75. const AZ::Vector2& inputQueryStepSize,
  76. AzFramework::Terrain::TerrainDataRequests::Sampler sampler,
  77. AZStd::vector<AZ::Vector3>& queryPositions,
  78. AZStd::vector<AZ::Vector3>& resultNormals,
  79. AZStd::vector<bool>& resultExistsFlags)
  80. {
  81. queryPositions.clear();
  82. resultNormals.clear();
  83. resultExistsFlags.clear();
  84. auto perPositionCallback = [&queryPositions, &resultNormals, &resultExistsFlags](
  85. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  86. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  87. {
  88. queryPositions.emplace_back(surfacePoint.m_position.GetX(), surfacePoint.m_position.GetY(), 0.0f);
  89. resultNormals.emplace_back(surfacePoint.m_normal);
  90. resultExistsFlags.emplace_back(terrainExists);
  91. };
  92. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  93. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(inputQueryRegion, inputQueryStepSize);
  94. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  95. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  96. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, perPositionCallback, sampler);
  97. EXPECT_EQ(queryPositions.size(), resultNormals.size());
  98. }
  99. // Compare two sets of output data and verify that they match.
  100. void CompareNormalData(
  101. const AZStd::vector<AZ::Vector3>& baselineQueryPositions,
  102. const AZStd::vector<AZ::Vector3>& baselineValues,
  103. const AZStd::vector<bool>& baselineExistsFlags,
  104. const AZStd::vector<AZ::Vector3>& comparisonQueryPositions,
  105. const AZStd::vector<AZ::Vector3>& comparisonValues,
  106. const AZStd::vector<bool>& comparisonExistsFlags)
  107. {
  108. // Verify that we have the same quantity of results in both sets.
  109. ASSERT_EQ(baselineValues.size(), comparisonValues.size());
  110. // Verify that every value is found exactly once in each set. The two sets might not have the values in the same order though,
  111. // so we need to search for each value, verify it's found, and verify that it hadn't previously been found.
  112. // Also, since normals are easy to duplicate, we'll search by query positions to find the normals to compare.
  113. AZStd::vector<bool> matchFound(baselineValues.size(), false);
  114. for (size_t comparisonIndex = 0; comparisonIndex < comparisonQueryPositions.size(); comparisonIndex++)
  115. {
  116. auto& comparisonPosition = comparisonQueryPositions[comparisonIndex];
  117. auto foundPosition = AZStd::find(baselineQueryPositions.begin(), baselineQueryPositions.end(), comparisonPosition);
  118. EXPECT_NE(foundPosition, baselineQueryPositions.end());
  119. if (foundPosition != baselineQueryPositions.end())
  120. {
  121. size_t foundIndex = foundPosition - baselineQueryPositions.begin();
  122. EXPECT_FALSE(matchFound[foundIndex]);
  123. EXPECT_EQ(baselineValues[foundIndex], comparisonValues[comparisonIndex]);
  124. EXPECT_EQ(baselineExistsFlags[foundIndex], comparisonExistsFlags[comparisonIndex]);
  125. matchFound[foundIndex] = true;
  126. }
  127. }
  128. }
  129. // Use the ProcessSurfaceWeightsFromRegion API as our baseline that we'll compare the other query APIs against.
  130. void GenerateBaselineSurfaceWeightData(
  131. const AZ::Aabb& inputQueryRegion,
  132. const AZ::Vector2& inputQueryStepSize,
  133. AzFramework::Terrain::TerrainDataRequests::Sampler sampler,
  134. AZStd::vector<AZ::Vector3>& queryPositions,
  135. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList>& resultWeights)
  136. {
  137. queryPositions.clear();
  138. resultWeights.clear();
  139. auto perPositionCallback = [&queryPositions, &resultWeights](
  140. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  141. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  142. {
  143. queryPositions.emplace_back(surfacePoint.m_position.GetX(), surfacePoint.m_position.GetY(), 0.0f);
  144. resultWeights.emplace_back(surfacePoint.m_surfaceTags);
  145. // For these unit tests, we expect every point queried to have valid terrain data.
  146. EXPECT_TRUE(terrainExists);
  147. };
  148. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  149. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(inputQueryRegion, inputQueryStepSize);
  150. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  151. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  152. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, perPositionCallback, sampler);
  153. EXPECT_EQ(queryPositions.size(), resultWeights.size());
  154. }
  155. // Compare two sets of output data and verify that they match.
  156. void CompareSurfaceWeightData(
  157. const AZStd::vector<AZ::Vector3>& baselineQueryPositions,
  158. const AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList>& baselineValues,
  159. const AZStd::vector<AZ::Vector3>& comparisonQueryPositions,
  160. const AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList>& comparisonValues)
  161. {
  162. // Verify that we have the same quantity of results in both sets.
  163. ASSERT_EQ(baselineValues.size(), comparisonValues.size());
  164. // Verify that every value is found exactly once in each set. The two sets might not have the values in the same order though,
  165. // so we need to search for each value, verify it's found, and verify that it hadn't previously been found.
  166. // Also, since surface weight lists are easy to duplicate, we'll search by query positions to find the weight lists to compare.
  167. AZStd::vector<bool> matchFound(baselineValues.size(), false);
  168. for (size_t comparisonIndex = 0; comparisonIndex < comparisonQueryPositions.size(); comparisonIndex++)
  169. {
  170. auto& comparisonPosition = comparisonQueryPositions[comparisonIndex];
  171. auto foundPosition = AZStd::find(baselineQueryPositions.begin(), baselineQueryPositions.end(), comparisonPosition);
  172. EXPECT_NE(foundPosition, baselineQueryPositions.end());
  173. if (foundPosition != baselineQueryPositions.end())
  174. {
  175. size_t foundIndex = foundPosition - baselineQueryPositions.begin();
  176. EXPECT_FALSE(matchFound[foundIndex]);
  177. EXPECT_EQ(baselineValues[foundIndex], comparisonValues[comparisonIndex]);
  178. matchFound[foundIndex] = true;
  179. }
  180. }
  181. }
  182. // Use the ProcessSurfacePointsFromRegion API as our baseline that we'll compare the other query APIs against.
  183. void GenerateBaselineSurfacePointData(
  184. const AZ::Aabb& inputQueryRegion,
  185. const AZ::Vector2& inputQueryStepSize,
  186. AzFramework::Terrain::TerrainDataRequests::Sampler sampler,
  187. AZStd::vector<AZ::Vector3>& queryPositions,
  188. AZStd::vector<AzFramework::SurfaceData::SurfacePoint>& resultPoints,
  189. AZStd::vector<bool>& resultExistsFlags)
  190. {
  191. queryPositions.clear();
  192. resultPoints.clear();
  193. resultExistsFlags.clear();
  194. auto perPositionCallback = [&queryPositions, &resultPoints, &resultExistsFlags](
  195. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  196. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  197. {
  198. queryPositions.emplace_back(surfacePoint.m_position.GetX(), surfacePoint.m_position.GetY(), 0.0f);
  199. resultPoints.emplace_back(surfacePoint);
  200. resultExistsFlags.emplace_back(terrainExists);
  201. };
  202. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  203. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(inputQueryRegion, inputQueryStepSize);
  204. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  205. &AzFramework::Terrain::TerrainDataRequests::QueryRegion, queryRegion,
  206. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, perPositionCallback, sampler);
  207. EXPECT_EQ(queryPositions.size(), resultPoints.size());
  208. }
  209. // Compare two sets of output data and verify that they match.
  210. void CompareSurfacePointData(
  211. const AZStd::vector<AzFramework::SurfaceData::SurfacePoint>& baselineValues,
  212. const AZStd::vector<bool>& baselineExistsFlags,
  213. const AZStd::vector<AzFramework::SurfaceData::SurfacePoint>& comparisonValues,
  214. const AZStd::vector<bool>& comparisonExistsFlags)
  215. {
  216. // Verify that we have the same quantity of results in both sets.
  217. ASSERT_EQ(baselineValues.size(), comparisonValues.size());
  218. // Verify that every value is found exactly once in each set. The two sets might not have the values in the same order though,
  219. // so we need to search for each value, verify it's found, and verify that it hadn't previously been found.
  220. AZStd::vector<bool> matchFound(baselineValues.size(), false);
  221. for (size_t comparisonIndex = 0; comparisonIndex < comparisonValues.size(); comparisonIndex++)
  222. {
  223. const auto& comparisonValue = comparisonValues[comparisonIndex];
  224. auto foundValue = AZStd::find_if(
  225. baselineValues.begin(), baselineValues.end(),
  226. [&comparisonValue](const AzFramework::SurfaceData::SurfacePoint& baselineValue) -> bool
  227. {
  228. return (baselineValue.m_position == comparisonValue.m_position)
  229. && (baselineValue.m_normal == comparisonValue.m_normal)
  230. && (baselineValue.m_surfaceTags == comparisonValue.m_surfaceTags);
  231. });
  232. EXPECT_NE(foundValue, baselineValues.end());
  233. if (foundValue != baselineValues.end())
  234. {
  235. size_t foundIndex = foundValue - baselineValues.begin();
  236. EXPECT_FALSE(matchFound[foundIndex]);
  237. EXPECT_EQ(baselineExistsFlags[foundIndex], comparisonExistsFlags[comparisonIndex]);
  238. matchFound[foundIndex] = true;
  239. if (baselineExistsFlags[foundIndex] != comparisonExistsFlags[comparisonIndex])
  240. {
  241. matchFound[foundIndex] = true;
  242. }
  243. }
  244. }
  245. }
  246. AZStd::shared_ptr<AzFramework::Terrain::QueryAsyncParams> CreateTestAsyncParams()
  247. {
  248. auto params = AZStd::make_shared<AzFramework::Terrain::QueryAsyncParams>();
  249. // Set the number of jobs > 1 so that we have parallel queries that execute.
  250. params->m_desiredNumberOfJobs = 4;
  251. params->m_completionCallback =
  252. [this]([[maybe_unused]] AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> context)
  253. {
  254. // Notify the main test thread that the query has completed.
  255. m_queryCompletionEvent.release();
  256. };
  257. return params;
  258. }
  259. // Set up the arbitrary terrain world parameters that we'll use for verifying our queries match.
  260. const static inline float TerrainSize = 32.0f;
  261. const static inline float TerrainQueryResolution = 1.0f;
  262. const static inline uint32_t TerrainNumSurfaces = 3;
  263. const static inline AZ::Aabb TerrainWorldBounds =
  264. AZ::Aabb::CreateFromMinMax(AZ::Vector3(-TerrainSize / 2.0f), AZ::Vector3(TerrainSize / 2.0f));
  265. // Set up the query parameters that we'll use for all our queries
  266. const static inline AZ::Aabb QueryBounds = TerrainWorldBounds;
  267. const static inline AZ::Vector2 QueryStepSize = AZ::Vector2(TerrainQueryResolution / 2.0f);
  268. const static inline uint32_t ExpectedResultCount =
  269. aznumeric_cast<uint32_t>((TerrainSize / QueryStepSize.GetX()) * (TerrainSize / QueryStepSize.GetY()));
  270. // Semaphore for use in async tests.
  271. AZStd::binary_semaphore m_queryCompletionEvent;
  272. };
  273. // -----------------------------------------------------------------------------
  274. // Compare Height Query APIs
  275. TEST_F(TerrainBulkQueryTest, ProcessHeightsFromRegionAndProcessHeightsFromListProduceSameResults)
  276. {
  277. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  278. for (auto sampler : {
  279. AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR,
  280. AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  281. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT
  282. })
  283. {
  284. // Gather all our initial results from calling Process*FromRegion
  285. AZStd::vector<AZ::Vector3> queryPositions;
  286. AZStd::vector<AZ::Vector3> baselineResultPositions;
  287. AZStd::vector<bool> baselineExistsFlags;
  288. GenerateBaselineHeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPositions, baselineExistsFlags);
  289. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  290. // Gather results from Process*FromList
  291. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  292. AZStd::vector<bool> comparisonExistsFlags;
  293. auto listPositionCallback = [&comparisonResultPositions, &comparisonExistsFlags]
  294. (const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  295. {
  296. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  297. comparisonExistsFlags.emplace_back(terrainExists);
  298. };
  299. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  300. &AzFramework::Terrain::TerrainDataRequests::QueryList,
  301. queryPositions, AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, listPositionCallback, sampler);
  302. // Compare the results
  303. ComparePositionData(baselineResultPositions, baselineExistsFlags, comparisonResultPositions, comparisonExistsFlags);
  304. }
  305. DestroyTestTerrainSystem();
  306. }
  307. TEST_F(TerrainBulkQueryTest, ProcessHeightsFromRegionAndGetHeightProduceSameResults)
  308. {
  309. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  310. for (auto sampler :
  311. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  312. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  313. {
  314. // Gather all our initial results from calling Process*FromRegion
  315. AZStd::vector<AZ::Vector3> queryPositions;
  316. AZStd::vector<AZ::Vector3> baselineResultPositions;
  317. AZStd::vector<bool> baselineExistsFlags;
  318. GenerateBaselineHeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPositions, baselineExistsFlags);
  319. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  320. // Gather results from Get*
  321. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  322. AZStd::vector<bool> comparisonExistsFlags;
  323. float worldMinZ = TerrainWorldBounds.GetMin().GetZ();
  324. for (auto& position : queryPositions)
  325. {
  326. float terrainHeight = worldMinZ;
  327. bool terrainExists = false;
  328. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  329. terrainHeight, &AzFramework::Terrain::TerrainDataRequests::GetHeight, position, sampler, &terrainExists);
  330. comparisonResultPositions.emplace_back(position.GetX(), position.GetY(), terrainHeight);
  331. comparisonExistsFlags.emplace_back(terrainExists);
  332. }
  333. // Compare the results
  334. ComparePositionData(baselineResultPositions, baselineExistsFlags, comparisonResultPositions, comparisonExistsFlags);
  335. }
  336. DestroyTestTerrainSystem();
  337. }
  338. TEST_F(TerrainBulkQueryTest, ProcessHeightsFromRegionAndProcessHeightsFromRegionAsyncProduceSameResults)
  339. {
  340. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  341. for (auto sampler :
  342. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  343. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  344. {
  345. // Gather all our initial results from calling Process*FromRegion
  346. AZStd::vector<AZ::Vector3> queryPositions;
  347. AZStd::vector<AZ::Vector3> baselineResultPositions;
  348. AZStd::vector<bool> baselineExistsFlags;
  349. GenerateBaselineHeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPositions, baselineExistsFlags);
  350. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  351. // Gather results from Process*FromRegionAsync
  352. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  353. AZStd::vector<bool> comparisonExistsFlags;
  354. AZStd::mutex outputMutex;
  355. auto regionPositionCallback = [&comparisonResultPositions, &comparisonExistsFlags, &outputMutex](
  356. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  357. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  358. {
  359. // Make sure only one thread can add its result at a time.
  360. AZStd::scoped_lock lock(outputMutex);
  361. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  362. comparisonExistsFlags.emplace_back(terrainExists);
  363. };
  364. auto params = CreateTestAsyncParams();
  365. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  366. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  367. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(QueryBounds, QueryStepSize);
  368. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  369. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  370. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights, regionPositionCallback, sampler, params);
  371. // Wait for the async query to complete
  372. m_queryCompletionEvent.acquire();
  373. // Compare the results
  374. ComparePositionData(baselineResultPositions, baselineExistsFlags, comparisonResultPositions, comparisonExistsFlags);
  375. }
  376. DestroyTestTerrainSystem();
  377. }
  378. TEST_F(TerrainBulkQueryTest, ProcessHeightsFromRegionAndProcessHeightsFromListAsyncProduceSameResults)
  379. {
  380. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  381. for (auto sampler :
  382. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  383. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  384. {
  385. // Gather all our initial results from calling Process*FromRegion
  386. AZStd::vector<AZ::Vector3> queryPositions;
  387. AZStd::vector<AZ::Vector3> baselineResultPositions;
  388. AZStd::vector<bool> baselineExistsFlags;
  389. GenerateBaselineHeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPositions, baselineExistsFlags);
  390. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  391. // Gather results from Process*FromListAsync
  392. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  393. AZStd::vector<bool> comparisonExistsFlags;
  394. AZStd::mutex outputMutex;
  395. auto listPositionCallback = [&comparisonResultPositions, &comparisonExistsFlags, &outputMutex](
  396. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  397. {
  398. // Make sure only one thread can add its result at a time.
  399. AZStd::scoped_lock lock(outputMutex);
  400. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  401. comparisonExistsFlags.emplace_back(terrainExists);
  402. };
  403. auto params = CreateTestAsyncParams();
  404. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  405. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  406. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, queryPositions,
  407. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Heights,
  408. listPositionCallback, sampler, params);
  409. // Wait for the async query to complete
  410. m_queryCompletionEvent.acquire();
  411. // Compare the results
  412. ComparePositionData(baselineResultPositions, baselineExistsFlags, comparisonResultPositions, comparisonExistsFlags);
  413. }
  414. DestroyTestTerrainSystem();
  415. }
  416. // -----------------------------------------------------------------------------
  417. // Compare Normal Query APIs
  418. TEST_F(TerrainBulkQueryTest, ProcessNormalsFromRegionAndProcessNormalsFromListProduceSameResults)
  419. {
  420. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  421. for (auto sampler :
  422. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  423. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  424. {
  425. // Gather all our initial results from calling Process*FromRegion
  426. AZStd::vector<AZ::Vector3> queryPositions;
  427. AZStd::vector<AZ::Vector3> baselineResultNormals;
  428. AZStd::vector<bool> baselineExistsFlags;
  429. GenerateBaselineNormalData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultNormals, baselineExistsFlags);
  430. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  431. // Gather results from Process*FromList
  432. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  433. AZStd::vector<AZ::Vector3> comparisonResultNormals;
  434. AZStd::vector<bool> comparisonExistsFlags;
  435. auto listNormalCallback = [&comparisonResultPositions, &comparisonResultNormals, &comparisonExistsFlags](
  436. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  437. {
  438. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  439. comparisonResultNormals.emplace_back(surfacePoint.m_normal);
  440. comparisonExistsFlags.emplace_back(terrainExists);
  441. };
  442. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  443. &AzFramework::Terrain::TerrainDataRequests::QueryList, queryPositions,
  444. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, listNormalCallback, sampler);
  445. // Compare the results
  446. CompareNormalData(queryPositions, baselineResultNormals, baselineExistsFlags,
  447. comparisonResultPositions, comparisonResultNormals, comparisonExistsFlags);
  448. }
  449. DestroyTestTerrainSystem();
  450. }
  451. TEST_F(TerrainBulkQueryTest, ProcessNormalsFromRegionAndGetNormalProduceSameResults)
  452. {
  453. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  454. for (auto sampler :
  455. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  456. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  457. {
  458. // Gather all our initial results from calling Process*FromRegion
  459. AZStd::vector<AZ::Vector3> queryPositions;
  460. AZStd::vector<AZ::Vector3> baselineResultNormals;
  461. AZStd::vector<bool> baselineExistsFlags;
  462. GenerateBaselineNormalData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultNormals, baselineExistsFlags);
  463. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  464. // Gather results from Get*
  465. AZStd::vector<AZ::Vector3> comparisonResultNormals;
  466. AZStd::vector<bool> comparisonExistsFlags;
  467. for (auto& position : queryPositions)
  468. {
  469. AZ::Vector3 terrainNormal = AZ::Vector3::CreateZero();
  470. bool terrainExists = false;
  471. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  472. terrainNormal, &AzFramework::Terrain::TerrainDataRequests::GetNormal, position, sampler, &terrainExists);
  473. comparisonResultNormals.emplace_back(terrainNormal);
  474. comparisonExistsFlags.emplace_back(terrainExists);
  475. }
  476. // Compare the results
  477. CompareNormalData(queryPositions, baselineResultNormals, baselineExistsFlags,
  478. queryPositions, comparisonResultNormals, comparisonExistsFlags);
  479. }
  480. DestroyTestTerrainSystem();
  481. }
  482. TEST_F(TerrainBulkQueryTest, ProcessNormalsFromRegionAndProcessNormalsFromRegionAsyncProduceSameResults)
  483. {
  484. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  485. for (auto sampler :
  486. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  487. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  488. {
  489. // Gather all our initial results from calling Process*FromRegion
  490. AZStd::vector<AZ::Vector3> queryPositions;
  491. AZStd::vector<AZ::Vector3> baselineResultNormals;
  492. AZStd::vector<bool> baselineExistsFlags;
  493. GenerateBaselineNormalData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultNormals, baselineExistsFlags);
  494. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  495. // Gather results from Process*FromRegionAsync
  496. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  497. AZStd::vector<AZ::Vector3> comparisonResultNormals;
  498. AZStd::vector<bool> comparisonExistsFlags;
  499. AZStd::mutex outputMutex;
  500. auto regionPositionCallback = [&comparisonResultPositions, &comparisonResultNormals, &comparisonExistsFlags, &outputMutex](
  501. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  502. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  503. {
  504. // Make sure only one thread can add its result at a time.
  505. AZStd::scoped_lock lock(outputMutex);
  506. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  507. comparisonResultNormals.emplace_back(surfacePoint.m_normal);
  508. comparisonExistsFlags.emplace_back(terrainExists);
  509. };
  510. auto params = CreateTestAsyncParams();
  511. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  512. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  513. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(QueryBounds, QueryStepSize);
  514. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  515. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  516. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, regionPositionCallback, sampler, params);
  517. // Wait for the async query to complete
  518. m_queryCompletionEvent.acquire();
  519. // Compare the results
  520. CompareNormalData(queryPositions, baselineResultNormals, baselineExistsFlags,
  521. comparisonResultPositions, comparisonResultNormals, comparisonExistsFlags);
  522. }
  523. DestroyTestTerrainSystem();
  524. }
  525. TEST_F(TerrainBulkQueryTest, ProcessNormalsFromRegionAndProcessNormalsFromListAsyncProduceSameResults)
  526. {
  527. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  528. for (auto sampler :
  529. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  530. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  531. {
  532. // Gather all our initial results from calling Process*FromRegion
  533. AZStd::vector<AZ::Vector3> queryPositions;
  534. AZStd::vector<AZ::Vector3> baselineResultNormals;
  535. AZStd::vector<bool> baselineExistsFlags;
  536. GenerateBaselineNormalData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultNormals, baselineExistsFlags);
  537. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  538. // Gather results from Process*FromListAsync
  539. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  540. AZStd::vector<AZ::Vector3> comparisonResultNormals;
  541. AZStd::vector<bool> comparisonExistsFlags;
  542. AZStd::mutex outputMutex;
  543. auto listPositionCallback = [&comparisonResultPositions, &comparisonResultNormals, &comparisonExistsFlags, &outputMutex](
  544. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  545. {
  546. // Make sure only one thread can add its result at a time.
  547. AZStd::scoped_lock lock(outputMutex);
  548. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  549. comparisonResultNormals.emplace_back(surfacePoint.m_normal);
  550. comparisonExistsFlags.emplace_back(terrainExists);
  551. };
  552. auto params = CreateTestAsyncParams();
  553. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  554. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  555. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, queryPositions,
  556. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::Normals, listPositionCallback,
  557. sampler, params);
  558. // Wait for the async query to complete
  559. m_queryCompletionEvent.acquire();
  560. // Compare the results
  561. CompareNormalData(queryPositions, baselineResultNormals, baselineExistsFlags,
  562. comparisonResultPositions, comparisonResultNormals, comparisonExistsFlags);
  563. }
  564. DestroyTestTerrainSystem();
  565. }
  566. // -----------------------------------------------------------------------------
  567. // Compare Surface Weight Query APIs
  568. TEST_F(TerrainBulkQueryTest, ProcessSurfaceWeightsFromRegionAndProcessSurfaceWeightsFromListProduceSameResults)
  569. {
  570. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  571. for (auto sampler :
  572. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  573. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  574. {
  575. // Gather all our initial results from calling Process*FromRegion
  576. AZStd::vector<AZ::Vector3> queryPositions;
  577. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> baselineResultWeights;
  578. GenerateBaselineSurfaceWeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultWeights);
  579. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  580. // Gather results from Process*FromList
  581. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  582. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> comparisonResultWeights;
  583. auto listWeightsCallback = [&comparisonResultPositions, &comparisonResultWeights](
  584. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  585. {
  586. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  587. comparisonResultWeights.emplace_back(surfacePoint.m_surfaceTags);
  588. EXPECT_TRUE(terrainExists);
  589. };
  590. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  591. &AzFramework::Terrain::TerrainDataRequests::QueryList, queryPositions,
  592. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, listWeightsCallback, sampler);
  593. // Compare the results
  594. CompareSurfaceWeightData(queryPositions, baselineResultWeights, comparisonResultPositions, comparisonResultWeights);
  595. }
  596. DestroyTestTerrainSystem();
  597. }
  598. TEST_F(TerrainBulkQueryTest, ProcessSurfaceWeightsFromRegionAndGetSurfaceWeightsProduceSameResults)
  599. {
  600. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  601. for (auto sampler :
  602. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  603. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  604. {
  605. // Gather all our initial results from calling Process*FromRegion
  606. AZStd::vector<AZ::Vector3> queryPositions;
  607. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> baselineResultWeights;
  608. GenerateBaselineSurfaceWeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultWeights);
  609. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  610. // Gather results from Get*
  611. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> comparisonResultWeights;
  612. AzFramework::SurfaceData::SurfaceTagWeightList terrainWeights;
  613. for (auto& position : queryPositions)
  614. {
  615. bool terrainExists = false;
  616. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  617. &AzFramework::Terrain::TerrainDataRequests::GetSurfaceWeights, position, terrainWeights, sampler, &terrainExists);
  618. comparisonResultWeights.emplace_back(terrainWeights);
  619. EXPECT_TRUE(terrainExists);
  620. }
  621. // Compare the results
  622. CompareSurfaceWeightData(queryPositions, baselineResultWeights, queryPositions, comparisonResultWeights);
  623. }
  624. DestroyTestTerrainSystem();
  625. }
  626. TEST_F(TerrainBulkQueryTest, ProcessSurfaceWeightsFromRegionAndProcessSurfaceWeightsFromRegionAsyncProduceSameResults)
  627. {
  628. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  629. for (auto sampler :
  630. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  631. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  632. {
  633. // Gather all our initial results from calling Process*FromRegion
  634. AZStd::vector<AZ::Vector3> queryPositions;
  635. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> baselineResultWeights;
  636. GenerateBaselineSurfaceWeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultWeights);
  637. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  638. // Gather results from Process*FromRegionAsync
  639. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  640. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> comparisonResultWeights;
  641. AZStd::mutex outputMutex;
  642. auto perPositionCallback = [&comparisonResultPositions, &comparisonResultWeights, &outputMutex](
  643. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  644. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  645. {
  646. // Make sure only one thread can add its result at a time.
  647. AZStd::scoped_lock lock(outputMutex);
  648. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  649. comparisonResultWeights.emplace_back(surfacePoint.m_surfaceTags);
  650. EXPECT_TRUE(terrainExists);
  651. };
  652. auto params = CreateTestAsyncParams();
  653. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  654. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  655. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(QueryBounds, QueryStepSize);
  656. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  657. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  658. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, perPositionCallback, sampler, params);
  659. // Wait for the async query to complete
  660. m_queryCompletionEvent.acquire();
  661. // Compare the results
  662. CompareSurfaceWeightData(queryPositions, baselineResultWeights, comparisonResultPositions, comparisonResultWeights);
  663. }
  664. DestroyTestTerrainSystem();
  665. }
  666. TEST_F(TerrainBulkQueryTest, ProcessSurfaceWeightsFromRegionAndProcessSurfaceWeightsFromListAsyncProduceSameResults)
  667. {
  668. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  669. for (auto sampler :
  670. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  671. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  672. {
  673. // Gather all our initial results from calling Process*FromRegion
  674. AZStd::vector<AZ::Vector3> queryPositions;
  675. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> baselineResultWeights;
  676. GenerateBaselineSurfaceWeightData(QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultWeights);
  677. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  678. // Gather results from Process*FromListAsync
  679. AZStd::vector<AZ::Vector3> comparisonResultPositions;
  680. AZStd::vector<AzFramework::SurfaceData::SurfaceTagWeightList> comparisonResultWeights;
  681. AZStd::mutex outputMutex;
  682. auto listPositionCallback = [&comparisonResultPositions, &comparisonResultWeights, &outputMutex](
  683. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  684. {
  685. // Make sure only one thread can add its result at a time.
  686. AZStd::scoped_lock lock(outputMutex);
  687. comparisonResultPositions.emplace_back(surfacePoint.m_position);
  688. comparisonResultWeights.emplace_back(surfacePoint.m_surfaceTags);
  689. EXPECT_TRUE(terrainExists);
  690. };
  691. auto params = CreateTestAsyncParams();
  692. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  693. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  694. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, queryPositions,
  695. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::SurfaceData, listPositionCallback, sampler, params);
  696. // Wait for the async query to complete
  697. m_queryCompletionEvent.acquire();
  698. // Compare the results
  699. CompareSurfaceWeightData(queryPositions, baselineResultWeights, comparisonResultPositions, comparisonResultWeights);
  700. }
  701. DestroyTestTerrainSystem();
  702. }
  703. // -----------------------------------------------------------------------------
  704. // Compare Surface Point Query APIs
  705. TEST_F(TerrainBulkQueryTest, ProcessSurfacePointsFromRegionAndProcessSurfacePointsFromListProduceSameResults)
  706. {
  707. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  708. for (auto sampler :
  709. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  710. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  711. {
  712. // Gather all our initial results from calling Process*FromRegion
  713. AZStd::vector<AZ::Vector3> queryPositions;
  714. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> baselineResultPoints;
  715. AZStd::vector<bool> baselineExistsFlags;
  716. GenerateBaselineSurfacePointData(
  717. QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPoints, baselineExistsFlags);
  718. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  719. // Gather results from Process*FromList
  720. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> comparisonResultPoints;
  721. AZStd::vector<bool> comparisonExistsFlags;
  722. auto listPositionCallback = [&comparisonResultPoints, &comparisonExistsFlags](
  723. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  724. {
  725. comparisonResultPoints.emplace_back(surfacePoint);
  726. comparisonExistsFlags.emplace_back(terrainExists);
  727. };
  728. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  729. &AzFramework::Terrain::TerrainDataRequests::QueryList, queryPositions,
  730. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, listPositionCallback, sampler);
  731. // Compare the results
  732. CompareSurfacePointData(baselineResultPoints, baselineExistsFlags, comparisonResultPoints, comparisonExistsFlags);
  733. }
  734. DestroyTestTerrainSystem();
  735. }
  736. TEST_F(TerrainBulkQueryTest, ProcessSurfacePointsFromRegionAndGetSurfacePointProduceSameResults)
  737. {
  738. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  739. for (auto sampler :
  740. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  741. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  742. {
  743. // Gather all our initial results from calling Process*FromRegion
  744. AZStd::vector<AZ::Vector3> queryPositions;
  745. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> baselineResultPoints;
  746. AZStd::vector<bool> baselineExistsFlags;
  747. GenerateBaselineSurfacePointData(
  748. QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPoints, baselineExistsFlags);
  749. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  750. // Gather results from Get*
  751. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> comparisonResultPoints;
  752. AZStd::vector<bool> comparisonExistsFlags;
  753. AzFramework::SurfaceData::SurfacePoint surfacePoint;
  754. for (auto& position : queryPositions)
  755. {
  756. bool terrainExists = false;
  757. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  758. &AzFramework::Terrain::TerrainDataRequests::GetSurfacePoint, position, surfacePoint, sampler, &terrainExists);
  759. comparisonResultPoints.emplace_back(surfacePoint);
  760. comparisonExistsFlags.emplace_back(terrainExists);
  761. }
  762. // Compare the results
  763. CompareSurfacePointData(baselineResultPoints, baselineExistsFlags, comparisonResultPoints, comparisonExistsFlags);
  764. }
  765. DestroyTestTerrainSystem();
  766. }
  767. TEST_F(TerrainBulkQueryTest, ProcessSurfacePointsFromRegionAndProcessSurfacePointsFromRegionAsyncProduceSameResults)
  768. {
  769. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  770. for (auto sampler :
  771. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  772. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  773. {
  774. // Gather all our initial results from calling Process*FromRegion
  775. AZStd::vector<AZ::Vector3> queryPositions;
  776. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> baselineResultPoints;
  777. AZStd::vector<bool> baselineExistsFlags;
  778. GenerateBaselineSurfacePointData(
  779. QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPoints, baselineExistsFlags);
  780. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  781. // Gather results from Process*FromRegionAsync
  782. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> comparisonResultPoints;
  783. AZStd::vector<bool> comparisonExistsFlags;
  784. AZStd::mutex outputMutex;
  785. auto regionPositionCallback = [&comparisonResultPoints, &comparisonExistsFlags, &outputMutex](
  786. [[maybe_unused]] size_t xIndex, [[maybe_unused]] size_t yIndex,
  787. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  788. {
  789. // Make sure only one thread can add its result at a time.
  790. AZStd::scoped_lock lock(outputMutex);
  791. comparisonResultPoints.emplace_back(surfacePoint);
  792. comparisonExistsFlags.emplace_back(terrainExists);
  793. };
  794. auto params = CreateTestAsyncParams();
  795. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  796. AzFramework::Terrain::TerrainQueryRegion queryRegion =
  797. AzFramework::Terrain::TerrainQueryRegion::CreateFromAabbAndStepSize(QueryBounds, QueryStepSize);
  798. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  799. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryRegionAsync, queryRegion,
  800. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, regionPositionCallback, sampler, params);
  801. // Wait for the async query to complete
  802. m_queryCompletionEvent.acquire();
  803. // Compare the results
  804. CompareSurfacePointData(baselineResultPoints, baselineExistsFlags, comparisonResultPoints, comparisonExistsFlags);
  805. }
  806. DestroyTestTerrainSystem();
  807. }
  808. TEST_F(TerrainBulkQueryTest, ProcessSurfacePointsFromRegionAndProcessSurfacePointsFromListAsyncProduceSameResults)
  809. {
  810. CreateTestTerrainSystem(TerrainWorldBounds, TerrainQueryResolution, TerrainNumSurfaces);
  811. for (auto sampler :
  812. { AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP,
  813. AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT })
  814. {
  815. // Gather all our initial results from calling Process*FromRegion
  816. AZStd::vector<AZ::Vector3> queryPositions;
  817. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> baselineResultPoints;
  818. AZStd::vector<bool> baselineExistsFlags;
  819. GenerateBaselineSurfacePointData(
  820. QueryBounds, QueryStepSize, sampler, queryPositions, baselineResultPoints, baselineExistsFlags);
  821. ASSERT_EQ(queryPositions.size(), ExpectedResultCount);
  822. // Gather results from Process*FromListAsync
  823. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> comparisonResultPoints;
  824. AZStd::vector<bool> comparisonExistsFlags;
  825. AZStd::mutex outputMutex;
  826. auto listPositionCallback = [&comparisonResultPoints, &comparisonExistsFlags, &outputMutex](
  827. const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  828. {
  829. // Make sure only one thread can add its result at a time.
  830. AZStd::scoped_lock lock(outputMutex);
  831. comparisonResultPoints.emplace_back(surfacePoint);
  832. comparisonExistsFlags.emplace_back(terrainExists);
  833. };
  834. auto params = CreateTestAsyncParams();
  835. AZStd::shared_ptr<AzFramework::Terrain::TerrainJobContext> jobContext;
  836. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  837. jobContext, &AzFramework::Terrain::TerrainDataRequests::QueryListAsync, queryPositions,
  838. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All, listPositionCallback, sampler, params);
  839. // Wait for the async query to complete
  840. m_queryCompletionEvent.acquire();
  841. // Compare the results
  842. CompareSurfacePointData(baselineResultPoints, baselineExistsFlags, comparisonResultPoints, comparisonExistsFlags);
  843. }
  844. DestroyTestTerrainSystem();
  845. }
  846. } // namespace UnitTest