RayTracingVertexFormatExampleComponent.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  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 "RayTracingVertexFormatExampleComponent.h"
  9. #include <Atom/Bootstrap/BootstrapNotificationBus.h>
  10. #include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
  11. #include <Atom/RPI.Public/Scene.h>
  12. #include <Automation/ScriptableImGui.h>
  13. #include <AzCore/Math/PackedVector3.h>
  14. #include <AzCore/Math/PackedVector4.h>
  15. #include <AzCore/Name/NameDictionary.h>
  16. namespace AtomSampleViewer::ImGuiHelper
  17. {
  18. template<typename T, AZStd::enable_if_t<AZStd::is_enum_v<T> && sizeof(T) == sizeof(int), bool> = true>
  19. bool RadioButton(const char* label, T* value, T buttonValue)
  20. {
  21. return ScriptableImGui::RadioButton(label, reinterpret_cast<int*>(value), AZStd::to_underlying(buttonValue));
  22. }
  23. } // namespace AtomSampleViewer::ImGuiHelper
  24. namespace
  25. {
  26. enum class FloatType
  27. {
  28. Float32,
  29. Float16,
  30. Float8,
  31. Unorm8,
  32. };
  33. enum class OctahedronType
  34. {
  35. Oct32,
  36. Oct16,
  37. Oct8,
  38. };
  39. constexpr int GetFloatTypeSize(FloatType floatType)
  40. {
  41. switch (floatType)
  42. {
  43. case FloatType::Float32:
  44. return 4;
  45. case FloatType::Float16:
  46. return 2;
  47. case FloatType::Float8:
  48. case FloatType::Unorm8:
  49. return 1;
  50. default:
  51. AZ_Assert(false, "Failed to get size of FloatType %d", floatType);
  52. return 1;
  53. }
  54. }
  55. constexpr int GetOctahedronTypeSize(OctahedronType octahedronType)
  56. {
  57. switch (octahedronType)
  58. {
  59. case OctahedronType::Oct32:
  60. return 4;
  61. case OctahedronType::Oct16:
  62. return 2;
  63. case OctahedronType::Oct8:
  64. return 1;
  65. default:
  66. AZ_Assert(false, "Failed to get size of OctahedronType %d", octahedronType);
  67. return 0;
  68. }
  69. }
  70. constexpr int GetOctahedronComponentBitCount(OctahedronType octahedronType)
  71. {
  72. switch (octahedronType)
  73. {
  74. case OctahedronType::Oct32:
  75. return 15;
  76. case OctahedronType::Oct16:
  77. return 7;
  78. case OctahedronType::Oct8:
  79. return 3;
  80. default:
  81. AZ_Assert(false, "Failed to get bit count of OctahedronType %d", octahedronType);
  82. return 0;
  83. }
  84. }
  85. template<FloatType floatType>
  86. void PackFloat(float sourceValue, void* targetAddress);
  87. template<>
  88. void PackFloat<FloatType::Float32>(float sourceValue, void* targetAddress)
  89. {
  90. std::memcpy(targetAddress, &sourceValue, 4);
  91. }
  92. template<>
  93. void PackFloat<FloatType::Float16>(float sourceValue, void* targetAddress)
  94. {
  95. uint32_t sourceValueInt{ *reinterpret_cast<uint32_t*>(&sourceValue) };
  96. // https://stackoverflow.com/a/5587983
  97. uint16_t targetValue = (sourceValueInt >> 31) << 5;
  98. uint16_t tmp = (sourceValueInt >> 23) & 0xff;
  99. tmp = (tmp - 0x70) & ((unsigned int)((int)(0x70 - tmp) >> 4) >> 27);
  100. targetValue = (targetValue | tmp) << 10;
  101. targetValue |= (sourceValueInt >> 13) & 0x3ff;
  102. std::memcpy(targetAddress, &targetValue, 2);
  103. }
  104. template<>
  105. void PackFloat<FloatType::Unorm8>(float sourceValue, void* targetAddress)
  106. {
  107. uint8_t targetValue{ aznumeric_cast<uint8_t>(AZStd::clamp(sourceValue, 0.f, 1.f) * 255.f) };
  108. std::memcpy(targetAddress, &targetValue, 1);
  109. }
  110. template<int ComponentCount, FloatType ComponentOutputFormat>
  111. void ConvertFloatBuffer(AZStd::span<const uint8_t> sourceBuffer, AZStd::span<uint8_t> targetBuffer, int sourceComponentCountOverride)
  112. {
  113. AZ_Assert(
  114. sourceComponentCountOverride == 0 || sourceComponentCountOverride < ComponentCount,
  115. "Component count override must be smaller than the format component count");
  116. size_t elementCount{ sourceBuffer.size() / (ComponentCount * sizeof(float)) };
  117. auto sourceIteratorBegin{ reinterpret_cast<const float*>(sourceBuffer.data()) };
  118. auto sourceIteratorEnd{ sourceIteratorBegin + elementCount * ComponentCount };
  119. uint8_t* targetBufferAddress{ targetBuffer.data() };
  120. int currentComponentIndex{ 0 };
  121. for (auto sourceIterator{ sourceIteratorBegin }; sourceIterator != sourceIteratorEnd; ++sourceIterator)
  122. {
  123. PackFloat<ComponentOutputFormat>(*sourceIterator, targetBufferAddress);
  124. targetBufferAddress += GetFloatTypeSize(ComponentOutputFormat);
  125. if (sourceComponentCountOverride != 0 && ++currentComponentIndex == sourceComponentCountOverride)
  126. {
  127. targetBufferAddress += GetFloatTypeSize(ComponentOutputFormat) * (ComponentCount - sourceComponentCountOverride);
  128. currentComponentIndex = 0;
  129. }
  130. }
  131. }
  132. AZ::Vector3 EncodeNormalSignedOctahedron(AZ::Vector3 normal)
  133. {
  134. // http://johnwhite3d.blogspot.com/2017/10/signed-octahedron-normal-encoding.html
  135. normal /= AZStd::abs(normal.GetX()) + AZStd::abs(normal.GetY()) + AZStd::abs(normal.GetZ());
  136. AZ::Vector3 encodedNormal;
  137. encodedNormal.SetY(normal.GetY() * 0.5f + 0.5f);
  138. encodedNormal.SetX(normal.GetX() * 0.5f + encodedNormal.GetY());
  139. encodedNormal.SetY(normal.GetX() * -0.5f + encodedNormal.GetY());
  140. encodedNormal.SetZ(AZStd::clamp(normal.GetZ() * AZStd::numeric_limits<float>::max(), 0.f, 1.f));
  141. return encodedNormal;
  142. }
  143. void EncodeTangentPackOctahedron(const AZ::PackedVector4f& sourceValue, OctahedronType octahedronType, void* targetAddress)
  144. {
  145. int xyBits{ GetOctahedronComponentBitCount(octahedronType) };
  146. AZ_Assert(xyBits * 2 + 2 <= 32, "Too many bits for octahedron encoding");
  147. AZ::Vector3 encodedNormal{ EncodeNormalSignedOctahedron(
  148. AZ::Vector3{ sourceValue.GetX(), sourceValue.GetY(), sourceValue.GetZ() }) };
  149. uint32_t mask{ (1u << xyBits) - 1 };
  150. uint32_t targetValue{ aznumeric_cast<uint32_t>(encodedNormal.GetX() * mask) |
  151. aznumeric_cast<uint32_t>(encodedNormal.GetY() * mask) << xyBits |
  152. aznumeric_cast<uint32_t>(encodedNormal.GetZ() > 0) << (xyBits * 2) |
  153. aznumeric_cast<uint32_t>(sourceValue.GetW() > 0) << (xyBits * 2 + 1) };
  154. std::memcpy(targetAddress, &targetValue, GetOctahedronTypeSize(octahedronType));
  155. }
  156. void EncodeNormalPackOctahedron(const AZ::PackedVector3f& sourceValue, OctahedronType octahedronType, void* targetAddress)
  157. {
  158. EncodeTangentPackOctahedron(
  159. AZ::PackedVector4f{ sourceValue.GetX(), sourceValue.GetY(), sourceValue.GetZ(), 0.f }, octahedronType, targetAddress);
  160. }
  161. template<OctahedronType ComponentOutputFormat>
  162. void ConvertNormalBuffer(AZStd::span<const uint8_t> sourceBuffer, AZStd::span<uint8_t> targetBuffer)
  163. {
  164. size_t elementCount{ sourceBuffer.size() / sizeof(AZ::PackedVector3f) };
  165. auto sourceIteratorBegin{ reinterpret_cast<const AZ::PackedVector3f*>(sourceBuffer.data()) };
  166. auto sourceIteratorEnd{ sourceIteratorBegin + elementCount };
  167. uint8_t* targetBufferAddress{ targetBuffer.data() };
  168. for (auto sourceIterator{ sourceIteratorBegin }; sourceIterator != sourceIteratorEnd; ++sourceIterator)
  169. {
  170. EncodeNormalPackOctahedron(*sourceIterator, ComponentOutputFormat, targetBufferAddress);
  171. targetBufferAddress += GetOctahedronTypeSize(ComponentOutputFormat);
  172. }
  173. }
  174. template<OctahedronType ComponentOutputFormat>
  175. void ConvertTangentBuffer(AZStd::span<const uint8_t> sourceBuffer, AZStd::span<uint8_t> targetBuffer)
  176. {
  177. size_t elementCount{ sourceBuffer.size() / sizeof(AZ::PackedVector4f) };
  178. auto sourceIteratorBegin{ reinterpret_cast<const AZ::PackedVector4f*>(sourceBuffer.data()) };
  179. auto sourceIteratorEnd{ sourceIteratorBegin + elementCount };
  180. uint8_t* targetBufferAddress{ targetBuffer.data() };
  181. for (auto sourceIterator{ sourceIteratorBegin }; sourceIterator != sourceIteratorEnd; ++sourceIterator)
  182. {
  183. EncodeTangentPackOctahedron(*sourceIterator, ComponentOutputFormat, targetBufferAddress);
  184. targetBufferAddress += GetOctahedronTypeSize(ComponentOutputFormat);
  185. }
  186. }
  187. void ConvertIndexBufferData(
  188. AZStd::span<const uint8_t> sourceBuffer, AZStd::span<uint8_t> targetBuffer, AZ::RHI::IndexFormat indexFormat)
  189. {
  190. size_t elementCount{ sourceBuffer.size() / sizeof(uint32_t) };
  191. auto sourceIteratorBegin{ reinterpret_cast<const uint32_t*>(sourceBuffer.data()) };
  192. auto sourceIteratorEnd{ sourceIteratorBegin + elementCount };
  193. uint8_t* targetBufferAddress{ targetBuffer.data() };
  194. for (auto sourceIterator{ sourceIteratorBegin }; sourceIterator != sourceIteratorEnd; ++sourceIterator)
  195. {
  196. uint32_t sourceValue{ *sourceIterator };
  197. std::memcpy(targetBufferAddress, &sourceValue, AZ::RHI::GetIndexFormatSize(indexFormat));
  198. targetBufferAddress += AZ::RHI::GetIndexFormatSize(indexFormat);
  199. }
  200. }
  201. } // namespace
  202. namespace AtomSampleViewer
  203. {
  204. using namespace AZ;
  205. void RayTracingVertexFormatExampleComponent::Reflect(ReflectContext* context)
  206. {
  207. if (auto* serializeContext{ azrtti_cast<SerializeContext*>(context) })
  208. {
  209. serializeContext->Class<RayTracingVertexFormatExampleComponent, Component>()->Version(0);
  210. }
  211. }
  212. void RayTracingVertexFormatExampleComponent::Activate()
  213. {
  214. m_modelBrowser.SetFilter(
  215. [](const Data::AssetInfo& assetInfo)
  216. {
  217. return assetInfo.m_assetType == azrtti_typeid<RPI::ModelAsset>();
  218. });
  219. m_modelBrowser.SetDefaultPinnedAssets(
  220. {
  221. "Objects/Shaderball_simple.fbx.azmodel",
  222. "Objects/bunny.fbx.azmodel",
  223. "Objects/suzanne.fbx.azmodel",
  224. "Objects/sponza.fbx.azmodel",
  225. },
  226. true);
  227. m_imguiSidebar.Activate();
  228. m_modelBrowser.Activate();
  229. auto& rayTracingDebugFeatureProcessor{ GetRayTracingDebugFeatureProcessor() };
  230. rayTracingDebugFeatureProcessor.OnRayTracingDebugComponentAdded();
  231. rayTracingDebugFeatureProcessor.GetSettingsInterface()->SetDebugViewMode(Render::RayTracingDebugViewMode::PrimitiveIndex);
  232. TickBus::Handler::BusConnect();
  233. EBUS_EVENT_ID(GetCameraEntityId(), Debug::CameraControllerRequestBus, Enable, azrtti_typeid<Debug::ArcBallControllerComponent>());
  234. EBUS_EVENT(Render::Bootstrap::NotificationBus, OnBootstrapSceneReady, m_scene);
  235. }
  236. void RayTracingVertexFormatExampleComponent::Deactivate()
  237. {
  238. m_modelBrowser.Deactivate();
  239. m_imguiSidebar.Deactivate();
  240. GetRayTracingDebugFeatureProcessor().OnRayTracingDebugComponentRemoved();
  241. // GetRayTracingFeatureProcessor().RemoveMesh(m_rayTracingUuid);
  242. EBUS_EVENT_ID(GetCameraEntityId(), Debug::CameraControllerRequestBus, Disable);
  243. TickBus::Handler::BusDisconnect();
  244. }
  245. void RayTracingVertexFormatExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
  246. {
  247. DrawSidebar();
  248. }
  249. void RayTracingVertexFormatExampleComponent::DrawSidebar()
  250. {
  251. if (m_imguiSidebar.Begin())
  252. {
  253. ImGuiAssetBrowser::WidgetSettings modelBrowserSettings;
  254. modelBrowserSettings.m_labels.m_root = "Models";
  255. bool modelChanged{ m_modelBrowser.Tick(modelBrowserSettings) };
  256. ImGui::Separator();
  257. ImGui::Spacing();
  258. ImGui::Text("RT Debug Type:");
  259. using DebugViewMode = Render::RayTracingDebugViewMode;
  260. bool debugViewModeUpdated{ false };
  261. debugViewModeUpdated |= ImGuiHelper::RadioButton("Instance Index", &m_debugViewMode, DebugViewMode::InstanceIndex);
  262. debugViewModeUpdated |= ImGuiHelper::RadioButton("Instance ID", &m_debugViewMode, DebugViewMode::InstanceID);
  263. debugViewModeUpdated |= ImGuiHelper::RadioButton("Primitive Index", &m_debugViewMode, DebugViewMode::PrimitiveIndex);
  264. debugViewModeUpdated |= ImGuiHelper::RadioButton("Barycentric Coordinates", &m_debugViewMode, DebugViewMode::Barycentrics);
  265. debugViewModeUpdated |= ImGuiHelper::RadioButton("Normals", &m_debugViewMode, DebugViewMode::Normals);
  266. debugViewModeUpdated |= ImGuiHelper::RadioButton("UV Coordinates", &m_debugViewMode, DebugViewMode::UVs);
  267. if (debugViewModeUpdated)
  268. {
  269. GetRayTracingDebugFeatureProcessor().GetSettingsInterface()->SetDebugViewMode(m_debugViewMode);
  270. }
  271. ImGui::Separator();
  272. ImGui::Spacing();
  273. ImGui::Text("Index Format:");
  274. bool indexFormatUpdated{ false };
  275. indexFormatUpdated |= ImGuiHelper::RadioButton("Uint32", &m_indexFormat, RHI::IndexFormat::Uint32);
  276. indexFormatUpdated |= ImGuiHelper::RadioButton("Uint16", &m_indexFormat, RHI::IndexFormat::Uint16);
  277. ImGui::Spacing();
  278. ImGui::PushID("Position");
  279. ImGui::Text("Position Format:");
  280. bool positionFormatUpdated{ false };
  281. positionFormatUpdated |= ImGuiHelper::RadioButton("R32G32B32_FLOAT", &m_positionFormat, RHI::VertexFormat::R32G32B32_FLOAT);
  282. positionFormatUpdated |=
  283. ImGuiHelper::RadioButton("R16G16B16A16_FLOAT", &m_positionFormat, RHI::VertexFormat::R16G16B16A16_FLOAT);
  284. ImGui::PopID();
  285. ImGui::Spacing();
  286. ImGui::PushID("Normal");
  287. ImGui::Text("Normal Format:");
  288. bool normalFormatUpdated{ false };
  289. normalFormatUpdated |= ImGuiHelper::RadioButton("R32G32B32_FLOAT", &m_normalFormat, RHI::VertexFormat::R32G32B32_FLOAT);
  290. normalFormatUpdated |= ImGuiHelper::RadioButton("R16G16B16_FLOAT", &m_normalFormat, RHI::VertexFormat::R16G16B16_FLOAT);
  291. normalFormatUpdated |= ImGuiHelper::RadioButton("N32_OCT", &m_normalFormat, RHI::VertexFormat::N32_OCT);
  292. normalFormatUpdated |= ImGuiHelper::RadioButton("N16_OCT", &m_normalFormat, RHI::VertexFormat::N16_OCT);
  293. normalFormatUpdated |= ImGuiHelper::RadioButton("N8_OCT", &m_normalFormat, RHI::VertexFormat::N8_OCT);
  294. ImGui::PopID();
  295. ImGui::Spacing();
  296. ImGui::PushID("UV");
  297. ImGui::Text("UV Format:");
  298. bool uvFormatUpdated{ false };
  299. uvFormatUpdated |= ImGuiHelper::RadioButton("R32G32_FLOAT", &m_uvFormat, RHI::VertexFormat::R32G32_FLOAT);
  300. uvFormatUpdated |= ImGuiHelper::RadioButton("R16G16_FLOAT", &m_uvFormat, RHI::VertexFormat::R16G16_FLOAT);
  301. uvFormatUpdated |= ImGuiHelper::RadioButton("R8G8_UNORM", &m_uvFormat, RHI::VertexFormat::R8G8_UNORM);
  302. ImGui::PopID();
  303. ImGui::Spacing();
  304. ImGui::PushID("Tangent");
  305. ImGui::Text("Tangent Format:");
  306. bool tangentFormatUpdated{ false };
  307. tangentFormatUpdated |= ImGuiHelper::RadioButton("R32G32B32A32_FLOAT", &m_tangentFormat, RHI::VertexFormat::R32G32B32A32_FLOAT);
  308. tangentFormatUpdated |= ImGuiHelper::RadioButton("R16G16B16A16_FLOAT", &m_tangentFormat, RHI::VertexFormat::R16G16B16A16_FLOAT);
  309. tangentFormatUpdated |= ImGuiHelper::RadioButton("T32_OCT", &m_tangentFormat, RHI::VertexFormat::T32_OCT);
  310. tangentFormatUpdated |= ImGuiHelper::RadioButton("T16_OCT", &m_tangentFormat, RHI::VertexFormat::T16_OCT);
  311. tangentFormatUpdated |= ImGuiHelper::RadioButton("T8_OCT", &m_tangentFormat, RHI::VertexFormat::T8_OCT);
  312. ImGui::PopID();
  313. ImGui::Spacing();
  314. ImGui::PushID("Bitangent");
  315. ImGui::Text("Bitangent Format:");
  316. bool bitangentFormatUpdated{ false };
  317. bitangentFormatUpdated |= ImGuiHelper::RadioButton("R32G32B32_FLOAT", &m_bitangentFormat, RHI::VertexFormat::R32G32B32_FLOAT);
  318. bitangentFormatUpdated |= ImGuiHelper::RadioButton("R16G16B16_FLOAT", &m_bitangentFormat, RHI::VertexFormat::R16G16B16_FLOAT);
  319. bitangentFormatUpdated |= ImGuiHelper::RadioButton("N32_OCT", &m_bitangentFormat, RHI::VertexFormat::N32_OCT);
  320. bitangentFormatUpdated |= ImGuiHelper::RadioButton("N16_OCT", &m_bitangentFormat, RHI::VertexFormat::N16_OCT);
  321. bitangentFormatUpdated |= ImGuiHelper::RadioButton("N8_OCT", &m_bitangentFormat, RHI::VertexFormat::N8_OCT);
  322. ImGui::PopID();
  323. if (modelChanged || indexFormatUpdated || positionFormatUpdated || uvFormatUpdated || normalFormatUpdated ||
  324. tangentFormatUpdated || bitangentFormatUpdated)
  325. {
  326. ModelChanged();
  327. }
  328. m_imguiSidebar.End();
  329. }
  330. }
  331. void RayTracingVertexFormatExampleComponent::ModelChanged()
  332. {
  333. if (!m_modelBrowser.GetSelectedAssetId().IsValid())
  334. {
  335. return;
  336. }
  337. m_currentModel.Create(m_modelBrowser.GetSelectedAssetId());
  338. m_currentModel.QueueLoad();
  339. m_currentModel.BlockUntilLoadComplete();
  340. Render::RayTracingFeatureProcessorInterface::Mesh rtMesh;
  341. rtMesh.m_assetId.m_guid = m_rayTracingUuid;
  342. rtMesh.m_instanceMask |= static_cast<uint32_t>(RHI::RayTracingAccelerationStructureInstanceInclusionMask::STATIC_MESH);
  343. AZStd::vector<Render::RayTracingFeatureProcessorInterface::SubMesh> rtSubMeshes;
  344. const auto& meshes{ m_currentModel->GetLodAssets()[0]->GetMeshes() };
  345. for (auto& mesh : meshes)
  346. {
  347. auto& rtSubMesh{ rtSubMeshes.emplace_back() };
  348. {
  349. const auto& indexView{ mesh.GetIndexBufferAssetView() };
  350. auto indexBuffer{ ConvertIndexBuffer(
  351. indexView.GetBufferAsset()->GetBuffer(), indexView.GetBufferViewDescriptor(), m_indexFormat) };
  352. uint32_t indexElementSize{ RHI::GetIndexFormatSize(m_indexFormat) };
  353. rtSubMesh.m_indexBufferView =
  354. RHI::IndexBufferView{ *indexBuffer->GetRHIBuffer(), 0, mesh.GetIndexCount() * indexElementSize, m_indexFormat };
  355. rtSubMesh.m_indexShaderBufferView = indexBuffer->GetRHIBuffer()->GetBufferView(indexBuffer->GetBufferViewDescriptor());
  356. }
  357. {
  358. const auto* positionView{ mesh.GetSemanticBufferAssetView(AZ_NAME_LITERAL("POSITION")) };
  359. uint32_t positionElementSize{ RHI::GetVertexFormatSize(m_positionFormat) };
  360. int sourceComponentOverride{ m_positionFormat == RHI::VertexFormat::R16G16B16A16_FLOAT ? 3 : 0 };
  361. auto positionBuffer{ ConvertVertexBuffer(
  362. positionView->GetBufferAsset()->GetBuffer(), positionView->GetBufferViewDescriptor(), m_positionFormat,
  363. sourceComponentOverride) };
  364. rtSubMesh.m_positionVertexBufferView =
  365. RHI::StreamBufferView{ *positionBuffer->GetRHIBuffer(), 0, mesh.GetVertexCount() * positionElementSize,
  366. positionElementSize };
  367. rtSubMesh.m_positionShaderBufferView =
  368. positionBuffer->GetRHIBuffer()->GetBufferView(positionBuffer->GetBufferViewDescriptor());
  369. rtSubMesh.m_positionFormat = m_positionFormat;
  370. }
  371. {
  372. const auto* normalView{ mesh.GetSemanticBufferAssetView(AZ_NAME_LITERAL("NORMAL")) };
  373. uint32_t normalElementSize{ RHI::GetVertexFormatSize(m_normalFormat) };
  374. auto normalBuffer{ ConvertVertexBuffer(
  375. normalView->GetBufferAsset()->GetBuffer(), normalView->GetBufferViewDescriptor(), m_normalFormat) };
  376. rtSubMesh.m_normalVertexBufferView =
  377. RHI::StreamBufferView{ *normalBuffer->GetRHIBuffer(), 0, mesh.GetVertexCount() * normalElementSize, normalElementSize };
  378. rtSubMesh.m_normalShaderBufferView = normalBuffer->GetRHIBuffer()->GetBufferView(normalBuffer->GetBufferViewDescriptor());
  379. rtSubMesh.m_normalFormat = m_normalFormat;
  380. }
  381. if (auto* uvView{ mesh.GetSemanticBufferAssetView(AZ_NAME_LITERAL("UV")) })
  382. {
  383. uint32_t uvElementSize{ RHI::GetVertexFormatSize(m_uvFormat) };
  384. auto uvBuffer{ ConvertVertexBuffer(uvView->GetBufferAsset()->GetBuffer(), uvView->GetBufferViewDescriptor(), m_uvFormat) };
  385. rtSubMesh.m_uvVertexBufferView =
  386. RHI::StreamBufferView{ *uvBuffer->GetRHIBuffer(), 0, mesh.GetVertexCount() * uvElementSize, uvElementSize };
  387. rtSubMesh.m_uvShaderBufferView = uvBuffer->GetRHIBuffer()->GetBufferView(uvBuffer->GetBufferViewDescriptor());
  388. rtSubMesh.m_uvFormat = m_uvFormat;
  389. rtSubMesh.m_bufferFlags |= Render::RayTracingSubMeshBufferFlags::UV;
  390. }
  391. if (auto* tangentView{ mesh.GetSemanticBufferAssetView(AZ_NAME_LITERAL("TANGENT")) })
  392. {
  393. uint32_t tangentElementSize{ RHI::GetVertexFormatSize(m_tangentFormat) };
  394. auto tangentBuffer{ ConvertVertexBuffer(
  395. tangentView->GetBufferAsset()->GetBuffer(), tangentView->GetBufferViewDescriptor(), m_tangentFormat) };
  396. rtSubMesh.m_tangentVertexBufferView =
  397. RHI::StreamBufferView{ *tangentBuffer->GetRHIBuffer(), 0, mesh.GetVertexCount() * tangentElementSize,
  398. tangentElementSize };
  399. rtSubMesh.m_tangentShaderBufferView =
  400. tangentBuffer->GetRHIBuffer()->GetBufferView(tangentBuffer->GetBufferViewDescriptor());
  401. rtSubMesh.m_tangentFormat = m_tangentFormat;
  402. rtSubMesh.m_bufferFlags |= Render::RayTracingSubMeshBufferFlags::Tangent;
  403. }
  404. if (auto* bitangentView{ mesh.GetSemanticBufferAssetView(AZ_NAME_LITERAL("BITANGENT")) })
  405. {
  406. uint32_t bitangentElementSize{ RHI::GetVertexFormatSize(m_bitangentFormat) };
  407. auto bitangentBuffer{ ConvertVertexBuffer(
  408. bitangentView->GetBufferAsset()->GetBuffer(), bitangentView->GetBufferViewDescriptor(), m_bitangentFormat) };
  409. rtSubMesh.m_bitangentVertexBufferView =
  410. RHI::StreamBufferView{ *bitangentBuffer->GetRHIBuffer(), 0, mesh.GetVertexCount() * bitangentElementSize,
  411. bitangentElementSize };
  412. rtSubMesh.m_bitangentShaderBufferView =
  413. bitangentBuffer->GetRHIBuffer()->GetBufferView(bitangentBuffer->GetBufferViewDescriptor());
  414. rtSubMesh.m_bitangentFormat = m_bitangentFormat;
  415. rtSubMesh.m_bufferFlags |= Render::RayTracingSubMeshBufferFlags::Bitangent;
  416. }
  417. }
  418. GetRayTracingFeatureProcessor().RemoveMesh(m_rayTracingUuid);
  419. GetRayTracingFeatureProcessor().AddMesh(m_rayTracingUuid, rtMesh, rtSubMeshes);
  420. }
  421. RPI::Ptr<RPI::Buffer> RayTracingVertexFormatExampleComponent::ConvertVertexBuffer(
  422. AZStd::span<const uint8_t> sourceBufferData,
  423. const RHI::BufferViewDescriptor& sourceBufferDescriptor,
  424. RHI::VertexFormat targetFormat,
  425. int sourceComponentCountOverride)
  426. {
  427. auto sourceBufferView{ sourceBufferData.subspan(
  428. sourceBufferDescriptor.m_elementOffset * sourceBufferDescriptor.m_elementSize,
  429. sourceBufferDescriptor.m_elementCount * sourceBufferDescriptor.m_elementSize) };
  430. uint32_t targetFormatSize{ RHI::GetVertexFormatSize(targetFormat) };
  431. // Use SizeAlignUp to ensure 4-byte-aligned reads in the shader are always valid when the buffer size is not a multiple of 4
  432. uint32_t targetBufferSize{ SizeAlignUp(sourceBufferDescriptor.m_elementCount * targetFormatSize, 4) };
  433. AZStd::vector<uint8_t> targetBufferData(targetBufferSize);
  434. switch (targetFormat)
  435. {
  436. case RHI::VertexFormat::R32G32B32A32_FLOAT:
  437. ConvertFloatBuffer<4, FloatType::Float32>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  438. break;
  439. case RHI::VertexFormat::R16G16B16A16_FLOAT:
  440. ConvertFloatBuffer<4, FloatType::Float16>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  441. break;
  442. case RHI::VertexFormat::R32G32B32_FLOAT:
  443. ConvertFloatBuffer<3, FloatType::Float32>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  444. break;
  445. case RHI::VertexFormat::R16G16B16_FLOAT:
  446. ConvertFloatBuffer<3, FloatType::Float16>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  447. break;
  448. case RHI::VertexFormat::R32G32_FLOAT:
  449. ConvertFloatBuffer<2, FloatType::Float32>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  450. break;
  451. case RHI::VertexFormat::R16G16_FLOAT:
  452. ConvertFloatBuffer<2, FloatType::Float16>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  453. break;
  454. case RHI::VertexFormat::R8G8_UNORM:
  455. ConvertFloatBuffer<2, FloatType::Unorm8>(sourceBufferView, targetBufferData, sourceComponentCountOverride);
  456. break;
  457. case RHI::VertexFormat::N32_OCT:
  458. ConvertNormalBuffer<OctahedronType::Oct32>(sourceBufferView, targetBufferData);
  459. break;
  460. case RHI::VertexFormat::N16_OCT:
  461. ConvertNormalBuffer<OctahedronType::Oct16>(sourceBufferView, targetBufferData);
  462. break;
  463. case RHI::VertexFormat::N8_OCT:
  464. ConvertNormalBuffer<OctahedronType::Oct8>(sourceBufferView, targetBufferData);
  465. break;
  466. case RHI::VertexFormat::T32_OCT:
  467. ConvertTangentBuffer<OctahedronType::Oct32>(sourceBufferView, targetBufferData);
  468. break;
  469. case RHI::VertexFormat::T16_OCT:
  470. ConvertTangentBuffer<OctahedronType::Oct16>(sourceBufferView, targetBufferData);
  471. break;
  472. case RHI::VertexFormat::T8_OCT:
  473. ConvertTangentBuffer<OctahedronType::Oct8>(sourceBufferView, targetBufferData);
  474. break;
  475. default:
  476. AZ_Assert(false, "Target format %d not supported", targetFormat);
  477. }
  478. RPI::CommonBufferDescriptor desc;
  479. desc.m_poolType = RPI::CommonBufferPoolType::StaticInputAssembly;
  480. desc.m_bufferName = "VertexBuffer";
  481. desc.m_byteCount = targetBufferSize;
  482. desc.m_elementSize = targetFormatSize;
  483. desc.m_bufferData = targetBufferData.data();
  484. return RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  485. }
  486. RPI::Ptr<RPI::Buffer> RayTracingVertexFormatExampleComponent::ConvertIndexBuffer(
  487. AZStd::span<const uint8_t> sourceBufferData, const RHI::BufferViewDescriptor& sourceBufferDescriptor, RHI::IndexFormat targetFormat)
  488. {
  489. auto sourceBufferView{ sourceBufferData.subspan(
  490. sourceBufferDescriptor.m_elementOffset * sourceBufferDescriptor.m_elementSize,
  491. sourceBufferDescriptor.m_elementCount * sourceBufferDescriptor.m_elementSize) };
  492. uint32_t targetFormatSize{ RHI::GetIndexFormatSize(targetFormat) };
  493. // Use SizeAlignUp to ensure 4-byte-aligned reads in the shader are always valid when the buffer size is not a multiple of 4
  494. uint32_t targetBufferSize{ SizeAlignUp(sourceBufferDescriptor.m_elementCount * targetFormatSize, 4) };
  495. AZStd::vector<uint8_t> targetBufferData(targetBufferSize);
  496. ConvertIndexBufferData(sourceBufferView, targetBufferData, targetFormat);
  497. RPI::CommonBufferDescriptor desc;
  498. desc.m_poolType = RPI::CommonBufferPoolType::StaticInputAssembly;
  499. desc.m_bufferName = "IndexBuffer";
  500. desc.m_byteCount = targetBufferSize;
  501. desc.m_elementSize = targetFormatSize;
  502. desc.m_bufferData = targetBufferData.data();
  503. return RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  504. }
  505. Render::RayTracingFeatureProcessorInterface& RayTracingVertexFormatExampleComponent::GetRayTracingFeatureProcessor()
  506. {
  507. if (!m_rayTracingFeatureProcessor)
  508. {
  509. auto* scene{ RPI::Scene::GetSceneForEntityContextId(GetEntityContextId()) };
  510. auto featureProcessor{ scene->GetFeatureProcessor<Render::RayTracingFeatureProcessorInterface>() };
  511. AZ_Assert(featureProcessor != nullptr, "RayTracingFeatureProcessor not found");
  512. m_rayTracingFeatureProcessor = featureProcessor;
  513. }
  514. return *m_rayTracingFeatureProcessor;
  515. }
  516. Render::RayTracingDebugFeatureProcessorInterface& RayTracingVertexFormatExampleComponent::GetRayTracingDebugFeatureProcessor()
  517. {
  518. if (!m_rayTracingDebugFeatureProcessor)
  519. {
  520. auto* scene{ RPI::Scene::GetSceneForEntityContextId(GetEntityContextId()) };
  521. auto featureProcessor{ scene->GetFeatureProcessor<Render::RayTracingDebugFeatureProcessorInterface>() };
  522. AZ_Assert(featureProcessor != nullptr, "RayTracingDebugFeatureProcessor not found");
  523. m_rayTracingDebugFeatureProcessor = featureProcessor;
  524. }
  525. return *m_rayTracingDebugFeatureProcessor;
  526. }
  527. } // namespace AtomSampleViewer