git.s-ol.nu ~forks/DiligentFX / 8cecada
GLTF PBR Renderer: enabled rendering objects from resource cache assiduous 10 months ago
2 changed file(s) with 346 addition(s) and 198 deletion(s). Raw diff Collapse all Expand all
177177 float WhitePoint = 3.f;
178178 };
179179
180 /// GLTF Model shader resource binding information
180181 struct ModelResourceBindings
181182 {
182183 void Clear()
183184 {
184185 MaterialSRB.clear();
185186 }
187 /// Shader resource binding for every material
186188 std::vector<RefCntAutoPtr<IShaderResourceBinding>> MaterialSRB;
187189 };
188190
189 /// Renders the given GLTF model.
190
191 /// \param [in] pCtx - Device context to record rendering commands to.
192 /// \param [in] GLTFModel - GLTF model to render.
193 /// \param [in] RenderParams - Render parameters.
194 /// \param [in] ResourceBindings - Model shader resource bindings.
195 /// \param [in] RenderNodeCallback - Optional render call back function that should be called
196 /// for every GLTF node instead of rendering it.
197 /// \param [in] ResourceBindings - GLTF model shader resource bindings.
198 void Render(IDeviceContext* pCtx,
199 GLTF::Model& GLTFModel,
200 const RenderInfo& RenderParams,
201 const ModelResourceBindings& ResourceBindings);
191 /// GLTF resource cache shader resource binding information
192 struct ResourceCacheBindings
193 {
194 /// Resource version
195 Uint32 Version = 0;
196
197 RefCntAutoPtr<IShaderResourceBinding> pSRB;
198 };
199
200 /// Renders a GLTF model.
201
202 /// \param [in] pCtx - Device context to record rendering commands to.
203 /// \param [in] GLTFModel - GLTF model to render.
204 /// \param [in] RenderParams - Render parameters.
205 /// \param [in] pModelBindings - The model's shader resource binding information.
206 /// \param [in] pCacheBindings - Shader resource cache binding information, if the
207 /// model has been created using the cache.
208 void Render(IDeviceContext* pCtx,
209 GLTF::Model& GLTFModel,
210 const RenderInfo& RenderParams,
211 ModelResourceBindings* pModelBindings,
212 ResourceCacheBindings* pCacheBindings = nullptr);
202213
203214 /// Creates resource bindings for a given GLTF model
204215 ModelResourceBindings CreateResourceBindings(GLTF::Model& GLTFModel,
235246 IPipelineState* pPSO,
236247 IShaderResourceBinding** ppMaterialSRB);
237248
249
250 /// Creates a shader resource binding for a GTLF resource cache.
251
252 /// \param [in] pDevice - Render device that may be needed by the resource cache to create
253 /// internal objects.
254 /// \param [in] pCtx - Device context that may be needed by the resource cache to initialize
255 /// internal objects.
256 /// \param [in] CacheUseInfo - GLTF resource cache usage information.
257 /// \param [in] pCameraAttribs - Camera attributes constant buffer to set in the SRB.
258 /// \param [in] pLightAttribs - Light attributes constant buffer to set in the SRB.
259 /// \param [in] pPSO - Optional PSO object to use to create the SRB instead of the
260 /// default PSO. Can be null
261 /// \param [out] ppCacheSRB - Pointer to memory location where the pointer to the SRB object
262 /// will be written.
263 void CreateResourceCacheSRB(IRenderDevice* pDevice,
264 IDeviceContext* pCtx,
265 GLTF::ResourceCacheUseInfo& CacheUseInfo,
266 IBuffer* pCameraAttribs,
267 IBuffer* pLightAttribs,
268 IPipelineState* pPSO,
269 IShaderResourceBinding** ppCacheSRB);
270
271 /// Prepares the renderer for rendering objects.
272 /// This method must be called at least once per frame.
238273 void Begin(IDeviceContext* pCtx);
274
275
276 /// Prepares the renderer for rendering objects from the resource cache.
277 /// This method must be called at least once per frame before the first object
278 /// from the cache is rendered.
279 void Begin(IRenderDevice* pDevice,
280 IDeviceContext* pCtx,
281 GLTF::ResourceCacheUseInfo& CacheUseInfo,
282 ResourceCacheBindings& Bindings,
283 IBuffer* pCameraAttribs,
284 IBuffer* pLightAttribs,
285 IPipelineState* pPSO = nullptr);
239286
240287 private:
241288 void PrecomputeBRDF(IRenderDevice* pDevice,
243290
244291 void CreatePSO(IRenderDevice* pDevice);
245292
246 void RenderGLTFNode(IDeviceContext* pCtx,
247 const GLTF::Node* node,
248 GLTF::Material::ALPHA_MODE AlphaMode,
249 const float4x4& ModelTransform,
250 size_t SRBTypeId);
293 void InitCommonSRBVars(IShaderResourceBinding* pSRB,
294 IBuffer* pCameraAttribs,
295 IBuffer* pLightAttribs);
251296
252297 struct PSOKey
253298 {
257302 DoubleSided{_DoubleSided}
258303 {}
259304
305 bool operator==(const PSOKey& rhs) const
306 {
307 return AlphaMode == rhs.AlphaMode && DoubleSided == rhs.DoubleSided;
308 }
309 bool operator!=(const PSOKey& rhs) const
310 {
311 return AlphaMode != rhs.AlphaMode || DoubleSided != rhs.DoubleSided;
312 }
313
260314 GLTF::Material::ALPHA_MODE AlphaMode = GLTF::Material::ALPHA_MODE_OPAQUE;
261315 bool DoubleSided = false;
262316 };
263317
264318 static size_t GetPSOIdx(const PSOKey& Key)
265319 {
266 return (Key.AlphaMode == GLTF::Material::ALPHA_MODE_BLEND ? 1 : 0) + (Key.DoubleSided ? 2 : 0);
320 size_t PSOIdx;
321
322 PSOIdx = Key.AlphaMode == GLTF::Material::ALPHA_MODE_BLEND ? 1 : 0;
323 PSOIdx = PSOIdx * 2 + (Key.DoubleSided ? 1 : 0);
324 return PSOIdx;
267325 }
268326
269327 void AddPSO(const PSOKey& Key, RefCntAutoPtr<IPipelineState> pPSO)
312370 RefCntAutoPtr<IBuffer> m_GLTFAttribsCB;
313371 RefCntAutoPtr<IBuffer> m_PrecomputeEnvMapAttribsCB;
314372 RefCntAutoPtr<IBuffer> m_JointsBuffer;
315
316 struct GLTFNodeRenderer
317 {
318 GLTF_PBR_Renderer& Renderer;
319 IDeviceContext* const pCtx;
320 GLTF::Model& GLTFModel;
321 const RenderInfo& RenderParams;
322 const ModelResourceBindings& ResourceBindings;
323
324 const Uint32 FirstIndexLocation;
325 const Uint32 BaseVertex;
326
327 const GLTF::Mesh* pLastAnimatedMesh = nullptr;
328
329 void Render(const GLTF::Node& Node,
330 GLTF::Material::ALPHA_MODE AlphaMode);
331 };
332373 };
333374
334 DEFINE_FLAG_ENUM_OPERATORS(GLTF_PBR_Renderer::RenderInfo::ALPHA_MODE_FLAGS);
375 DEFINE_FLAG_ENUM_OPERATORS(GLTF_PBR_Renderer::RenderInfo::ALPHA_MODE_FLAGS)
335376
336377 } // namespace Diligent
389389 }
390390 }
391391
392 void GLTF_PBR_Renderer::InitCommonSRBVars(IShaderResourceBinding* pSRB,
393 IBuffer* pCameraAttribs,
394 IBuffer* pLightAttribs)
395 {
396 VERIFY_EXPR(pSRB != nullptr);
397
398 if (pCameraAttribs != nullptr)
399 {
400 if (auto* pCameraAttribsVSVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbCameraAttribs"))
401 pCameraAttribsVSVar->Set(pCameraAttribs);
402
403 if (auto* pCameraAttribsPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbCameraAttribs"))
404 pCameraAttribsPSVar->Set(pCameraAttribs);
405 }
406
407 if (pLightAttribs != nullptr)
408 {
409 if (auto* pLightAttribsPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbLightAttribs"))
410 pLightAttribsPSVar->Set(pLightAttribs);
411 }
412
413 if (m_Settings.UseIBL)
414 {
415 if (auto* pIrradianceMapPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_IrradianceMap"))
416 pIrradianceMapPSVar->Set(m_pIrradianceCubeSRV);
417
418 if (auto* pPrefilteredEnvMap = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_PrefilteredEnvMap"))
419 pPrefilteredEnvMap->Set(m_pPrefilteredEnvMapSRV);
420 }
421 }
422
423
392424 void GLTF_PBR_Renderer::CreateMaterialSRB(GLTF::Model& Model,
393425 GLTF::Material& Material,
394426 IBuffer* pCameraAttribs,
400432 pPSO = GetPSO(PSOKey{});
401433
402434 pPSO->CreateShaderResourceBinding(ppMaterialSRB, true);
403 auto* pSRB = *ppMaterialSRB;
435 auto* const pSRB = *ppMaterialSRB;
404436 if (pSRB == nullptr)
405437 {
406438 LOG_ERROR_MESSAGE("Failed to create material SRB");
407439 return;
408440 }
409441
410 if (auto* pCameraAttribsVSVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbCameraAttribs"))
411 pCameraAttribsVSVar->Set(pCameraAttribs);
412
413 if (pCameraAttribs != nullptr)
414 {
415 if (auto* pCameraAttribsPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbCameraAttribs"))
416 pCameraAttribsPSVar->Set(pCameraAttribs);
417 }
418
419 if (pLightAttribs != nullptr)
420 {
421 if (auto* pLightAttribsPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbLightAttribs"))
422 pLightAttribsPSVar->Set(pLightAttribs);
423 }
424
425 if (m_Settings.UseIBL)
426 {
427 if (auto* pIrradianceMapPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_IrradianceMap"))
428 pIrradianceMapPSVar->Set(m_pIrradianceCubeSRV);
429
430 if (auto* pPrefilteredEnvMap = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_PrefilteredEnvMap"))
431 pPrefilteredEnvMap->Set(m_pPrefilteredEnvMapSRV);
432 }
442 InitCommonSRBVars(pSRB, pCameraAttribs, pLightAttribs);
433443
434444 auto SetTexture = [&](GLTF::Material::TEXTURE_ID TexId, ITextureView* pDefaultTexSRV, const char* VarName) //
435445 {
438448 auto TexIdx = Material.TextureIds[TexId];
439449 if (TexIdx >= 0)
440450 {
441 if (auto* pTexture = Model.GetTexture(TexIdx, nullptr, nullptr))
451 if (auto* pTexture = Model.GetTexture(TexIdx))
442452 pTexSRV = pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
443453 }
444454
459469 if (m_Settings.UseEmissive)
460470 {
461471 SetTexture(GLTF::Material::TEXTURE_ID_EMISSIVE, m_pBlackTexSRV, "g_EmissiveMap");
472 }
473 }
474
475 void GLTF_PBR_Renderer::CreateResourceCacheSRB(IRenderDevice* pDevice,
476 IDeviceContext* pCtx,
477 GLTF::ResourceCacheUseInfo& CacheUseInfo,
478 IBuffer* pCameraAttribs,
479 IBuffer* pLightAttribs,
480 IPipelineState* pPSO,
481 IShaderResourceBinding** ppCacheSRB)
482 {
483 DEV_CHECK_ERR(CacheUseInfo.pResourceMgr != nullptr, "Resource manager must not be null");
484
485 pPSO->CreateShaderResourceBinding(ppCacheSRB, true);
486 IShaderResourceBinding* const pSRB = *ppCacheSRB;
487 if (pSRB == nullptr)
488 {
489 LOG_ERROR_MESSAGE("Failed to create an SRB");
490 return;
491 }
492
493 InitCommonSRBVars(pSRB, pCameraAttribs, pLightAttribs);
494
495 auto SetTexture = [&](TEXTURE_FORMAT Fmt, const char* VarName) //
496 {
497 if (auto* pVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, VarName))
498 {
499 if (auto* pTexture = CacheUseInfo.pResourceMgr->GetTexture(Fmt, pDevice, pCtx))
500 {
501 pVar->Set(pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE));
502 }
503 }
504 };
505
506 SetTexture(CacheUseInfo.BaseColorFormat, "g_ColorMap");
507 SetTexture(CacheUseInfo.PhysicalDescFormat, "g_PhysicalDescriptorMap");
508 SetTexture(CacheUseInfo.NormalFormat, "g_NormalMap");
509 if (m_Settings.UseAO)
510 {
511 SetTexture(CacheUseInfo.OcclusionFormat, "g_AOMap");
512 }
513 if (m_Settings.UseEmissive)
514 {
515 SetTexture(CacheUseInfo.EmissiveFormat, "g_EmissiveMap");
462516 }
463517 }
464518
725779 return ResourceBindings;
726780 }
727781
728 void GLTF_PBR_Renderer::GLTFNodeRenderer::Render(const GLTF::Node& Node,
729 GLTF::Material::ALPHA_MODE AlphaMode)
730 {
731 if (Node.Mesh)
732 {
733 // Render mesh primitives
734 for (const auto& primitive : Node.Mesh->Primitives)
735 {
736 const auto& material = GLTFModel.Materials[primitive.MaterialId];
737 if (material.AlphaMode != AlphaMode)
738 continue;
739
740 auto* pPSO = Renderer.GetPSO(PSOKey{AlphaMode, material.DoubleSided});
741 VERIFY_EXPR(pPSO != nullptr);
742 pCtx->SetPipelineState(pPSO);
743
744 VERIFY(primitive.MaterialId < ResourceBindings.MaterialSRB.size(),
745 "Material index is out of bounds. This mostl likely indicates that shader resources were initialized for a different model.");
746
747 IShaderResourceBinding* const pSRB = ResourceBindings.MaterialSRB[primitive.MaterialId].RawPtr<IShaderResourceBinding>();
748 if (pSRB == nullptr)
749 {
750 LOG_ERROR_MESSAGE("Unable to find SRB for GLTF material. Please call GLTF_PBR_Renderer::CreateResourceBindings()");
751 continue;
752 }
753 pCtx->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
754
755 size_t JointCount = Node.Mesh->Transforms.jointMatrices.size();
756 if (JointCount > Renderer.m_Settings.MaxJointCount)
757 {
758 LOG_WARNING_MESSAGE("The number of joints in the mesh (", JointCount, ") exceeds the maximum number (", Renderer.m_Settings.MaxJointCount,
759 ") reserved in the buffer. Increase MaxJointCount when initializing the renderer.");
760 JointCount = Renderer.m_Settings.MaxJointCount;
761 }
762
763 {
764 MapHelper<GLTFNodeShaderTransforms> pTransforms{pCtx, Renderer.m_TransformsCB, MAP_WRITE, MAP_FLAG_DISCARD};
765 pTransforms->NodeMatrix = Node.Mesh->Transforms.matrix * RenderParams.ModelTransform;
766 pTransforms->JointCount = static_cast<int>(JointCount);
767 }
768
769 if (JointCount != 0 && pLastAnimatedMesh != Node.Mesh.get())
770 {
771 MapHelper<float4x4> pJoints{pCtx, Renderer.m_JointsBuffer, MAP_WRITE, MAP_FLAG_DISCARD};
772 memcpy(pJoints, Node.Mesh->Transforms.jointMatrices.data(), JointCount * sizeof(float4x4));
773 pLastAnimatedMesh = Node.Mesh.get();
774 }
775
776 {
777 struct GLTFAttribs
778 {
779 GLTFRendererShaderParameters RenderParameters;
780 GLTF::Material::ShaderAttribs MaterialInfo;
781 static_assert(sizeof(GLTFMaterialShaderInfo) == sizeof(GLTF::Material::ShaderAttribs),
782 "The sizeof(GLTFMaterialShaderInfo) is incosistent with sizeof(GLTF::Material::ShaderAttribs)");
783 };
784 static_assert(sizeof(GLTFAttribs) <= 256, "Size of dynamic GLTFAttribs buffer exceeds 256 bytes. "
785 "It may be worth trying to reduce the size or just live with it.");
786
787 MapHelper<GLTFAttribs> pGLTFAttribs{pCtx, Renderer.m_GLTFAttribsCB, MAP_WRITE, MAP_FLAG_DISCARD};
788
789 pGLTFAttribs->MaterialInfo = material.Attribs;
790
791 auto& ShaderParams = pGLTFAttribs->RenderParameters;
792
793 ShaderParams.DebugViewType = static_cast<int>(Renderer.m_RenderParams.DebugView);
794 ShaderParams.OcclusionStrength = Renderer.m_RenderParams.OcclusionStrength;
795 ShaderParams.EmissionScale = Renderer.m_RenderParams.EmissionScale;
796 ShaderParams.AverageLogLum = Renderer.m_RenderParams.AverageLogLum;
797 ShaderParams.MiddleGray = Renderer.m_RenderParams.MiddleGray;
798 ShaderParams.WhitePoint = Renderer.m_RenderParams.WhitePoint;
799 ShaderParams.IBLScale = Renderer.m_RenderParams.IBLScale;
800 ShaderParams.PrefilteredCubeMipLevels = Renderer.m_Settings.UseIBL ? static_cast<float>(Renderer.m_pPrefilteredEnvMapSRV->GetTexture()->GetDesc().MipLevels) : 0.f;
801 }
802
803 if (primitive.HasIndices())
804 {
805 DrawIndexedAttribs drawAttrs{primitive.IndexCount, VT_UINT32, DRAW_FLAG_VERIFY_ALL};
806 drawAttrs.FirstIndexLocation = FirstIndexLocation + primitive.FirstIndex;
807 drawAttrs.BaseVertex = BaseVertex;
808 pCtx->DrawIndexed(drawAttrs);
809 }
810 else
811 {
812 DrawAttribs drawAttrs{primitive.VertexCount, DRAW_FLAG_VERIFY_ALL};
813 drawAttrs.StartVertexLocation = BaseVertex;
814 pCtx->Draw(drawAttrs);
815 }
816 }
817 }
818
819 for (const auto& child : Node.Children)
820 {
821 Render(*child, AlphaMode);
822 }
823 }
824
825782 void GLTF_PBR_Renderer::Begin(IDeviceContext* pCtx)
826783 {
827 // In next-gen backends, dynamic buffers must be mapped before the first use in every frame
828 MapHelper<float4x4> pJoints{pCtx, m_JointsBuffer, MAP_WRITE, MAP_FLAG_DISCARD};
829 }
830
831 void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
832 GLTF::Model& GLTFModel,
833 const RenderInfo& RenderParams,
834 const ModelResourceBindings& ResourceBindings)
835 {
836 DEV_CHECK_ERR(ResourceBindings.MaterialSRB.size() == GLTFModel.Materials.size(),
837 "The number of material shader resource bindings is not consistent with the number of materials");
838
839 m_RenderParams = RenderParams;
784 if (m_JointsBuffer)
785 {
786 // In next-gen backends, dynamic buffers must be mapped before the first use in every frame
787 MapHelper<float4x4> pJoints{pCtx, m_JointsBuffer, MAP_WRITE, MAP_FLAG_DISCARD};
788 }
789 }
790
791 void GLTF_PBR_Renderer::Begin(IRenderDevice* pDevice,
792 IDeviceContext* pCtx,
793 GLTF::ResourceCacheUseInfo& CacheUseInfo,
794 ResourceCacheBindings& Bindings,
795 IBuffer* pCameraAttribs,
796 IBuffer* pLightAttribs,
797 IPipelineState* pPSO)
798 {
799 VERIFY_EXPR(CacheUseInfo.pResourceMgr != nullptr);
800
801 Begin(pCtx);
802
803 if (pPSO == nullptr)
804 pPSO = GetPSO(PSOKey{});
805
806 auto TextureVersion = CacheUseInfo.pResourceMgr->GetTextureVersion();
807 if (!Bindings.pSRB || Bindings.Version != TextureVersion)
808 {
809 Bindings.pSRB.Release();
810 CreateResourceCacheSRB(pDevice, pCtx, CacheUseInfo, pCameraAttribs, pLightAttribs, pPSO, &Bindings.pSRB);
811 if (!Bindings.pSRB)
812 {
813 LOG_ERROR_MESSAGE("Failed to create an SRB for GLTF resource cache");
814 return;
815 }
816 Bindings.Version = TextureVersion;
817 }
818
819 pCtx->TransitionShaderResources(pPSO, Bindings.pSRB);
840820
841821 std::array<Uint32, 2> Offsets = {};
842822 std::array<IBuffer*, 2> pVBs =
843823 {
844 GLTFModel.GetBuffer(GLTF::Model::BUFFER_ID_VERTEX0, nullptr, nullptr),
845 GLTFModel.GetBuffer(GLTF::Model::BUFFER_ID_VERTEX1, nullptr, nullptr) //
824 CacheUseInfo.pResourceMgr->GetBuffer(CacheUseInfo.VertexBuffer0Idx, pDevice, pCtx),
825 CacheUseInfo.pResourceMgr->GetBuffer(CacheUseInfo.VertexBuffer1Idx, pDevice, pCtx) //
846826 };
847827 pCtx->SetVertexBuffers(0, static_cast<Uint32>(pVBs.size()), pVBs.data(), Offsets.data(), RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
848828
849 if (auto* pIndexBuffer = GLTFModel.GetBuffer(GLTF::Model::BUFFER_ID_INDEX, nullptr, nullptr))
850 {
851 pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
852 }
853
854 GLTFNodeRenderer NodeRenderer //
855 {
856 *this,
857 pCtx,
858 GLTFModel,
859 RenderParams,
860 ResourceBindings,
861 GLTFModel.GetFirstIndexLocation(),
862 GLTFModel.GetBaseVertex() //
829 auto* pIndexBuffer = CacheUseInfo.pResourceMgr->GetBuffer(CacheUseInfo.IndexBufferIdx, pDevice, pCtx);
830 pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
831 }
832
833 void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
834 GLTF::Model& GLTFModel,
835 const RenderInfo& RenderParams,
836 ModelResourceBindings* pModelBindings,
837 ResourceCacheBindings* pCacheBindings)
838 {
839 DEV_CHECK_ERR((pModelBindings != nullptr) ^ (pCacheBindings != nullptr), "Either model bindings or cache bindings must not be null");
840 DEV_CHECK_ERR(pModelBindings == nullptr || pModelBindings->MaterialSRB.size() == GLTFModel.Materials.size(),
841 "The number of material shader resource bindings is not consistent with the number of materials");
842
843 m_RenderParams = RenderParams;
844
845 if (pModelBindings != nullptr)
846 {
847 std::array<Uint32, 2> Offsets = {};
848 std::array<IBuffer*, 2> pVBs =
849 {
850 GLTFModel.GetBuffer(GLTF::Model::BUFFER_ID_VERTEX_BASIC_ATTRIBS),
851 GLTFModel.GetBuffer(GLTF::Model::BUFFER_ID_VERTEX_SKIN_ATTRIBS) //
852 };
853 pCtx->SetVertexBuffers(0, static_cast<Uint32>(pVBs.size()), pVBs.data(), Offsets.data(), RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
854
855 if (auto* pIndexBuffer = GLTFModel.GetBuffer(GLTF::Model::BUFFER_ID_INDEX))
856 {
857 pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
858 }
859 }
860
861 const auto FirstIndexLocation = GLTFModel.GetFirstIndexLocation();
862 const auto BaseVertex = GLTFModel.GetBaseVertex();
863
864 const std::array<GLTF::Material::ALPHA_MODE, 3> AlphaModes //
865 {
866 GLTF::Material::ALPHA_MODE_OPAQUE, // Opaque primitives - first
867 GLTF::Material::ALPHA_MODE_MASK, // Alpha-masked primitives - second
868 GLTF::Material::ALPHA_MODE_BLEND, // Transparent primitives - last (TODO: depth sorting)
863869 };
864870
865 for (auto AlphaMode : {
866 GLTF::Material::ALPHA_MODE_OPAQUE, // Opaque primitives - first
867 GLTF::Material::ALPHA_MODE_MASK, // Alpha-masked primitives - second
868 GLTF::Material::ALPHA_MODE_BLEND, // Transparent primitives - last (TODO: depth sorting)
869 })
870 {
871 if (RenderParams.AlphaModes & (1 << AlphaMode))
872 {
873 for (const auto& node : GLTFModel.Nodes)
871 const GLTF::Mesh* pLastAnimatedMesh = nullptr;
872 IPipelineState* pCurrPSO = nullptr;
873 PSOKey CurrPSOKey;
874
875 for (auto AlphaMode : AlphaModes)
876 {
877 for (const auto* pNode : GLTFModel.LinearNodes)
878 {
879 if (!pNode->pMesh)
880 continue;
881
882 const auto& Mesh = *pNode->pMesh;
883
884 // Render mesh primitives
885 for (const auto& primitive : Mesh.Primitives)
874886 {
875 NodeRenderer.Render(*node, AlphaMode);
887 const auto& material = GLTFModel.Materials[primitive.MaterialId];
888 if (material.AlphaMode != AlphaMode)
889 continue;
890
891 const PSOKey Key{AlphaMode, material.DoubleSided};
892 if (Key != CurrPSOKey)
893 {
894 CurrPSOKey = Key;
895 pCurrPSO = nullptr;
896 }
897 if (pCurrPSO == nullptr)
898 {
899 pCurrPSO = GetPSO(CurrPSOKey);
900 VERIFY_EXPR(pCurrPSO != nullptr);
901 pCtx->SetPipelineState(pCurrPSO);
902 if (pCacheBindings != nullptr)
903 {
904 pCtx->CommitShaderResources(pCacheBindings->pSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
905 }
906 }
907 else
908 {
909 VERIFY_EXPR(pCurrPSO == GetPSO(PSOKey{AlphaMode, material.DoubleSided}));
910 }
911
912 if (pModelBindings != nullptr)
913 {
914 VERIFY(primitive.MaterialId < pModelBindings->MaterialSRB.size(),
915 "Material index is out of bounds. This mostl likely indicates that shader resources were initialized for a different model.");
916
917 IShaderResourceBinding* const pSRB = pModelBindings->MaterialSRB[primitive.MaterialId].RawPtr<IShaderResourceBinding>();
918 DEV_CHECK_ERR(pSRB != nullptr, "Unable to find SRB for GLTF material.");
919 pCtx->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
920 }
921
922 size_t JointCount = Mesh.Transforms.jointMatrices.size();
923 if (JointCount > m_Settings.MaxJointCount)
924 {
925 LOG_WARNING_MESSAGE("The number of joints in the mesh (", JointCount, ") exceeds the maximum number (", m_Settings.MaxJointCount,
926 ") reserved in the buffer. Increase MaxJointCount when initializing the renderer.");
927 JointCount = m_Settings.MaxJointCount;
928 }
929
930 {
931 MapHelper<GLTFNodeShaderTransforms> pTransforms{pCtx, m_TransformsCB, MAP_WRITE, MAP_FLAG_DISCARD};
932 pTransforms->NodeMatrix = Mesh.Transforms.matrix * RenderParams.ModelTransform;
933 pTransforms->JointCount = static_cast<int>(JointCount);
934 }
935
936 if (JointCount != 0 && pLastAnimatedMesh != &Mesh)
937 {
938 MapHelper<float4x4> pJoints{pCtx, m_JointsBuffer, MAP_WRITE, MAP_FLAG_DISCARD};
939 memcpy(pJoints, Mesh.Transforms.jointMatrices.data(), JointCount * sizeof(float4x4));
940 pLastAnimatedMesh = &Mesh;
941 }
942
943 {
944 struct GLTFAttribs
945 {
946 GLTFRendererShaderParameters RenderParameters;
947 GLTF::Material::ShaderAttribs MaterialInfo;
948 static_assert(sizeof(GLTFMaterialShaderInfo) == sizeof(GLTF::Material::ShaderAttribs),
949 "The sizeof(GLTFMaterialShaderInfo) is incosistent with sizeof(GLTF::Material::ShaderAttribs)");
950 };
951 static_assert(sizeof(GLTFAttribs) <= 256, "Size of dynamic GLTFAttribs buffer exceeds 256 bytes. "
952 "It may be worth trying to reduce the size or just live with it.");
953
954 MapHelper<GLTFAttribs> pGLTFAttribs{pCtx, m_GLTFAttribsCB, MAP_WRITE, MAP_FLAG_DISCARD};
955
956 pGLTFAttribs->MaterialInfo = material.Attribs;
957
958 auto& ShaderParams = pGLTFAttribs->RenderParameters;
959
960 ShaderParams.DebugViewType = static_cast<int>(m_RenderParams.DebugView);
961 ShaderParams.OcclusionStrength = m_RenderParams.OcclusionStrength;
962 ShaderParams.EmissionScale = m_RenderParams.EmissionScale;
963 ShaderParams.AverageLogLum = m_RenderParams.AverageLogLum;
964 ShaderParams.MiddleGray = m_RenderParams.MiddleGray;
965 ShaderParams.WhitePoint = m_RenderParams.WhitePoint;
966 ShaderParams.IBLScale = m_RenderParams.IBLScale;
967 ShaderParams.PrefilteredCubeMipLevels = m_Settings.UseIBL ? static_cast<float>(m_pPrefilteredEnvMapSRV->GetTexture()->GetDesc().MipLevels) : 0.f;
968 }
969
970 if (primitive.HasIndices())
971 {
972 DrawIndexedAttribs drawAttrs{primitive.IndexCount, VT_UINT32, DRAW_FLAG_VERIFY_ALL};
973 drawAttrs.FirstIndexLocation = FirstIndexLocation + primitive.FirstIndex;
974 drawAttrs.BaseVertex = BaseVertex;
975 pCtx->DrawIndexed(drawAttrs);
976 }
977 else
978 {
979 DrawAttribs drawAttrs{primitive.VertexCount, DRAW_FLAG_VERIFY_ALL};
980 drawAttrs.StartVertexLocation = BaseVertex;
981 pCtx->Draw(drawAttrs);
982 }
876983 }
877984 }
878985 }