diff --git a/Hydrogent/include/HnMaterial.hpp b/Hydrogent/include/HnMaterial.hpp index 2f8b6283..297f9f6f 100644 --- a/Hydrogent/include/HnMaterial.hpp +++ b/Hydrogent/include/HnMaterial.hpp @@ -28,6 +28,7 @@ #include #include +#include #include "HnMaterialNetwork.hpp" #include "HnTextureRegistry.hpp" @@ -82,10 +83,19 @@ class HnMaterial final : public pxr::HdMaterial const HLSL::PBRMaterialShaderInfo& GetShaderAttribs() const { return m_ShaderAttribs; } + /// Texture coordinate set info + struct TextureCoordinateSetInfo + { + /// Texture coordinate set primvar name (e.g. "st") + pxr::TfToken PrimVarName; + }; + const auto& GetTextureCoordinateSets() const { return m_TexCoords; } + private: HnMaterial(pxr::SdfPath const& id); - void AllocateTextures(HnTextureRegistry& TexRegistry); + using TexNameToCoordSetMapType = std::unordered_map; + void AllocateTextures(HnTextureRegistry& TexRegistry, TexNameToCoordSetMapType& TexNameToCoordSetMap); private: HnMaterialNetwork m_Network; @@ -95,6 +105,8 @@ class HnMaterial final : public pxr::HdMaterial RefCntAutoPtr m_SRB; HLSL::PBRMaterialShaderInfo m_ShaderAttribs{}; + + std::vector m_TexCoords; }; } // namespace USD diff --git a/Hydrogent/include/HnMesh.hpp b/Hydrogent/include/HnMesh.hpp index d020b847..c457ad75 100644 --- a/Hydrogent/include/HnMesh.hpp +++ b/Hydrogent/include/HnMesh.hpp @@ -28,7 +28,6 @@ #include #include -#include // NoteL tbb.h must be included before mesh.h to avoid compilation errors in tbb headers. #include "tbb/tbb.h" @@ -74,15 +73,10 @@ class HnMesh final : public pxr::HdMesh void CommitGPUResources(IRenderDevice* pDevice); - enum VERTEX_BUFFER_ID - { - VERTEX_BUFFER_ID_POSITION = 0, - VERTEX_BUFFER_ID_NORMAL, - VERTEX_BUFFER_ID_TEXCOORD, - VERTEX_BUFFER_ID_COUNT - }; + /// Returns vertex buffer for the given primvar name (e.g. "points", "normals", etc.). + /// If the buffer doesn't exist, returns nullptr. + IBuffer* GetVertexBuffer(const pxr::TfToken& Name) const; - IBuffer* GetVertexBuffer(VERTEX_BUFFER_ID BufferId) const { return m_pVertexBuffers[BufferId]; } IBuffer* GetTriangleIndexBuffer() const { return m_pTriangleIndexBuffer; } IBuffer* GetEdgeIndexBuffer() const { return m_pEdgeIndexBuffer; } @@ -153,7 +147,7 @@ class HnMesh final : public pxr::HdMesh RefCntAutoPtr m_pTriangleIndexBuffer; RefCntAutoPtr m_pEdgeIndexBuffer; - std::array, VERTEX_BUFFER_ID_COUNT> m_pVertexBuffers; + std::unordered_map, pxr::TfToken::HashFunctor> m_VertexBuffers; }; } // namespace USD diff --git a/Hydrogent/include/HnTokens.hpp b/Hydrogent/include/HnTokens.hpp index d3e66f57..5cdaed56 100644 --- a/Hydrogent/include/HnTokens.hpp +++ b/Hydrogent/include/HnTokens.hpp @@ -68,7 +68,7 @@ namespace USD (roughness) \ (normal) \ (occlusion) \ - (st0) + (emissive) #define HN_MATERIAL_TAG_TOKENS \ (defaultTag) \ diff --git a/Hydrogent/src/HnMaterial.cpp b/Hydrogent/src/HnMaterial.cpp index 3ddcacf8..a15f71b0 100644 --- a/Hydrogent/src/HnMaterial.cpp +++ b/Hydrogent/src/HnMaterial.cpp @@ -83,7 +83,9 @@ void HnMaterial::Sync(pxr::HdSceneDelegate* SceneDelegate, } HnTextureRegistry& TexRegistry = static_cast(SceneDelegate->GetRenderIndex().GetRenderDelegate())->GetTextureRegistry(); - AllocateTextures(TexRegistry); + + TexNameToCoordSetMapType TexNameToCoordSetMap; + AllocateTextures(TexRegistry, TexNameToCoordSetMap); m_ShaderAttribs.BaseColorFactor = float4{1, 1, 1, 1}; m_ShaderAttribs.EmissiveFactor = float4{0, 0, 0, 0}; @@ -121,12 +123,14 @@ void HnMaterial::Sync(pxr::HdSceneDelegate* SceneDelegate, m_ShaderAttribs.OcclusionFactor = Val.Get(); }); - m_ShaderAttribs.Workflow = PBR_Renderer::PBR_WORKFLOW_METALL_ROUGH; - m_ShaderAttribs.UVSelector0 = 0; - m_ShaderAttribs.UVSelector1 = 0; - m_ShaderAttribs.UVSelector2 = 0; - m_ShaderAttribs.UVSelector3 = 0; - m_ShaderAttribs.UVSelector4 = 0; + m_ShaderAttribs.Workflow = PBR_Renderer::PBR_WORKFLOW_METALL_ROUGH; + m_ShaderAttribs.UVSelector0 = static_cast(TexNameToCoordSetMap[HnTokens->diffuseColor]); + m_ShaderAttribs.UVSelector1 = static_cast(TexNameToCoordSetMap[HnTokens->metallic]); + if (TexNameToCoordSetMap[HnTokens->metallic] != TexNameToCoordSetMap[HnTokens->roughness]) + LOG_ERROR_MESSAGE("Metallic and roughness textures must use the same texture coordinates"); + m_ShaderAttribs.UVSelector2 = static_cast(TexNameToCoordSetMap[HnTokens->normal]); + m_ShaderAttribs.UVSelector3 = static_cast(TexNameToCoordSetMap[HnTokens->occlusion]); + m_ShaderAttribs.UVSelector4 = static_cast(TexNameToCoordSetMap[HnTokens->emissive]); m_ShaderAttribs.TextureSlice0 = 0; m_ShaderAttribs.TextureSlice1 = 0; m_ShaderAttribs.TextureSlice2 = 0; @@ -148,13 +152,46 @@ void HnMaterial::Sync(pxr::HdSceneDelegate* SceneDelegate, *DirtyBits = HdMaterial::Clean; } -void HnMaterial::AllocateTextures(HnTextureRegistry& TexRegistry) +void HnMaterial::AllocateTextures(HnTextureRegistry& TexRegistry, TexNameToCoordSetMapType& TexNameToCoordSetMap) { + std::unordered_map TexCoordMapping; for (const HnMaterialNetwork::TextureDescriptor& TexDescriptor : m_Network.GetTextures()) { if (auto pTex = TexRegistry.Allocate(TexDescriptor.TextureId, TexDescriptor.SamplerParams)) { m_Textures[TexDescriptor.Name] = pTex; + // Find texture coordinate + size_t TexCoordIdx = ~size_t{0}; + for (const HnMaterialParameter& Param : m_Network.GetParameters()) + { + if (Param.Type == HnMaterialParameter::ParamType::Texture && Param.Name == TexDescriptor.Name) + { + if (!Param.SamplerCoords.empty()) + { + if (Param.SamplerCoords.size() > 1) + LOG_WARNING_MESSAGE("Texture '", TexDescriptor.Name, "' has ", Param.SamplerCoords.size(), " texture coordinates. Only the first set will be used"); + const pxr::TfToken& TexCoordName = Param.SamplerCoords[0]; + + auto it_inserted = TexCoordMapping.emplace(TexCoordName, TexCoordMapping.size()); + TexCoordIdx = it_inserted.first->second; + if (it_inserted.second) + { + m_TexCoords.resize(TexCoordIdx + 1); + m_TexCoords[TexCoordIdx] = {TexCoordName}; + } + } + else + { + LOG_ERROR_MESSAGE("Texture '", TexDescriptor.Name, "' has no texture coordinates"); + } + break; + } + } + + if (TexCoordIdx == ~size_t{0}) + { + LOG_ERROR_MESSAGE("Failed to find texture coordinates for texture '", TexDescriptor.Name, "'"); + } } } } diff --git a/Hydrogent/src/HnMaterialNetwork.cpp b/Hydrogent/src/HnMaterialNetwork.cpp index b06471f3..c1452d9c 100644 --- a/Hydrogent/src/HnMaterialNetwork.cpp +++ b/Hydrogent/src/HnMaterialNetwork.cpp @@ -1034,7 +1034,7 @@ void HnMaterialNetwork::AddTextureParam(const pxr::HdMaterialNetwork2& Network, } else if (SdrRole == pxr::SdrNodeRole->Math) { - UNSUPPORTED("Transform2D is not currently supported"); + LOG_ERROR_MESSAGE("Transform2D is not currently supported"); #if 0 HdSt_MaterialParamVector transform2dParams; diff --git a/Hydrogent/src/HnMesh.cpp b/Hydrogent/src/HnMesh.cpp index 2df1fd49..487c0dba 100644 --- a/Hydrogent/src/HnMesh.cpp +++ b/Hydrogent/src/HnMesh.cpp @@ -232,20 +232,6 @@ void HnMesh::UpdateVertexPrims(pxr::HdSceneDelegate& SceneDelegate, m_BufferSources.emplace(PrimDesc.name, std::move(BufferSource)); } - // Create dummy texture coordinates if they are not present - if (m_BufferSources.find(HnTokens->st0) == m_BufferSources.end()) - { - pxr::VtValue DummyUVs; - DummyUVs = pxr::VtArray{static_cast(NumPoints), pxr::GfVec2f{0}}; - auto BufferSource = std::make_shared( - HnTokens->st0, - DummyUVs, - 1, // values per element - false // whether doubles are supported or must be converted to floats - ); - m_BufferSources.emplace(HnTokens->st0, std::move(BufferSource)); - } - DirtyBits &= ~pxr::HdChangeTracker::DirtyPrimvar; } @@ -256,18 +242,7 @@ void HnMesh::UpdateVertexBuffers(const RenderDeviceX_N& Device) for (auto source_it : m_BufferSources) { const auto& PrimName = source_it.first; - - VERTEX_BUFFER_ID BufferId = VERTEX_BUFFER_ID_COUNT; - if (PrimName == pxr::HdTokens->points) - BufferId = VERTEX_BUFFER_ID_POSITION; - else if (PrimName == pxr::HdTokens->normals) - BufferId = VERTEX_BUFFER_ID_NORMAL; - else if (PrimName == HnTokens->st0) - BufferId = VERTEX_BUFFER_ID_TEXCOORD; - else - continue; - - auto pSource = source_it.second.get(); + const auto pSource = source_it.second.get(); if (pSource == nullptr) return; @@ -276,10 +251,10 @@ void HnMesh::UpdateVertexBuffers(const RenderDeviceX_N& Device) const auto ElementType = pSource->GetTupleType().type; const auto ElementSize = HdDataSizeOfType(ElementType); - VERIFY((BufferId == VERTEX_BUFFER_ID_POSITION && ElementSize == sizeof(float) * 3 || - BufferId == VERTEX_BUFFER_ID_NORMAL && ElementSize == sizeof(float) * 3 || - BufferId == VERTEX_BUFFER_ID_TEXCOORD && ElementSize == sizeof(float) * 2), - "Unexpected element size"); + if (PrimName == pxr::HdTokens->points) + VERIFY(ElementSize == sizeof(float) * 3, "Unexpected vertex size"); + else if (PrimName == pxr::HdTokens->normals) + VERIFY(ElementSize == sizeof(float) * 3, "Unexpected normal size"); const auto Name = GetId().GetString() + " - " + PrimName.GetString(); BufferDesc Desc{ @@ -290,7 +265,7 @@ void HnMesh::UpdateVertexBuffers(const RenderDeviceX_N& Device) }; BufferData InitData{pSource->GetData(), Desc.Size}; - m_pVertexBuffers[BufferId] = Device.CreateBuffer(Desc, &InitData); + m_VertexBuffers[PrimName] = Device.CreateBuffer(Desc, &InitData); } m_BufferSources.clear(); @@ -349,6 +324,12 @@ void HnMesh::CommitGPUResources(IRenderDevice* pDevice) } } +IBuffer* HnMesh::GetVertexBuffer(const pxr::TfToken& Name) const +{ + auto it = m_VertexBuffers.find(Name); + return it != m_VertexBuffers.end() ? it->second.RawPtr() : nullptr; +} + } // namespace USD } // namespace Diligent diff --git a/Hydrogent/src/HnRendererImpl.cpp b/Hydrogent/src/HnRendererImpl.cpp index 8cb9891f..6d33193a 100644 --- a/Hydrogent/src/HnRendererImpl.cpp +++ b/Hydrogent/src/HnRendererImpl.cpp @@ -187,14 +187,20 @@ class SyncTask final : public pxr::HdTask void HnRendererImpl::Update() { - m_ImagingDelegate->ApplyPendingUpdates(); - pxr::HdTaskSharedPtrVector tasks = { - std::make_shared(m_GeometryPass, m_RenderTags)}; - m_Engine.Execute(&m_ImagingDelegate->GetRenderIndex(), &tasks); + if (m_ImagingDelegate) + { + m_ImagingDelegate->ApplyPendingUpdates(); + pxr::HdTaskSharedPtrVector tasks = { + std::make_shared(m_GeometryPass, m_RenderTags)}; + m_Engine.Execute(&m_ImagingDelegate->GetRenderIndex(), &tasks); + } } void HnRendererImpl::Draw(IDeviceContext* pCtx, const HnDrawAttribs& Attribs) { + if (!m_RenderDelegate) + return; + const auto& Meshes = m_RenderDelegate->GetMeshes(); if (Meshes.empty()) return; @@ -249,10 +255,32 @@ void HnRendererImpl::Draw(IDeviceContext* pCtx, const HnDrawAttribs& Attribs) void HnRendererImpl::RenderMesh(IDeviceContext* pCtx, const HnMesh& Mesh, const HnMaterial& Material, const HnDrawAttribs& Attribs) { - auto* pSRB = Material.GetSRB(); - auto* pVB0 = Mesh.GetVertexBuffer(HnMesh::VERTEX_BUFFER_ID_POSITION); - auto* pVB1 = Mesh.GetVertexBuffer(HnMesh::VERTEX_BUFFER_ID_NORMAL); - auto* pVB2 = Mesh.GetVertexBuffer(HnMesh::VERTEX_BUFFER_ID_TEXCOORD); + auto* pSRB = Material.GetSRB(); + auto* pPosVB = Mesh.GetVertexBuffer(pxr::HdTokens->points); + auto* pNormalsVB = Mesh.GetVertexBuffer(pxr::HdTokens->normals); + + const auto& TexCoordSets = Material.GetTextureCoordinateSets(); + IBuffer* pTexCoordVBs[2] = {}; + for (size_t i = 0; i < TexCoordSets.size(); ++i) + { + const auto& TexCoordSet = TexCoordSets[i]; + if (!TexCoordSet.PrimVarName.IsEmpty()) + { + pTexCoordVBs[i] = Mesh.GetVertexBuffer(TexCoordSet.PrimVarName); + if (!pTexCoordVBs[i]) + { + LOG_ERROR_MESSAGE("Failed to find texture coordinates vertex buffer '", TexCoordSet.PrimVarName.GetText(), "' in mesh '", Mesh.GetId().GetText(), "'"); + } + } + } + + for (size_t i = 0; i < _countof(pTexCoordVBs); ++i) + { + // Temporary workaround - assign normals VB to texture coordinate VB if the latter is not available. + // Texture coordinates will not be used in the shader anyway, but we need to have valid VB bound. + if (pTexCoordVBs[i] == nullptr) + pTexCoordVBs[i] = pNormalsVB; + } const auto& ShaderAttribs = Material.GetShaderAttribs(); @@ -260,11 +288,11 @@ void HnRendererImpl::RenderMesh(IDeviceContext* pCtx, const HnMesh& Mesh, const Mesh.GetEdgeIndexBuffer() : Mesh.GetTriangleIndexBuffer(); - if (pVB0 == nullptr || pVB1 == nullptr || pVB2 == nullptr || pIB == nullptr || pSRB == nullptr) + if (pPosVB == nullptr || pNormalsVB == nullptr || pTexCoordVBs[0] == nullptr || pTexCoordVBs[1] == nullptr || pIB == nullptr || pSRB == nullptr) return; // Bind vertex and index buffers - IBuffer* pBuffs[] = {pVB0, pVB1, pVB2, pVB2}; + IBuffer* pBuffs[] = {pPosVB, pNormalsVB, pTexCoordVBs[0], pTexCoordVBs[1]}; pCtx->SetVertexBuffers(0, _countof(pBuffs), pBuffs, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); pCtx->SetIndexBuffer(pIB, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);