Skip to content

Commit

Permalink
PBR Renderer and Hydrogent: added option to pack vertex normals into …
Browse files Browse the repository at this point in the history
…32-bit uint
  • Loading branch information
TheMostDiligent committed Nov 8, 2024
1 parent 40dba30 commit 0dd567b
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 24 deletions.
4 changes: 4 additions & 0 deletions Hydrogent/include/HnMeshUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ class HnMeshUtils final
///
pxr::VtValue ConvertVertexPrimvarToFaceVarying(const pxr::VtValue& VertexData, size_t ValuesPerVertex = 1) const;


/// Pack vertex normals into 32-bit unsigned integers.
pxr::VtValue PackVertexNormals(const pxr::VtValue& Normals) const;

private:
template <typename HandleFaceType>
void ProcessFaces(HandleFaceType&& HandleFace) const;
Expand Down
5 changes: 3 additions & 2 deletions Hydrogent/interface/HnMesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ class HnMesh final : public pxr::HdMesh
pxr::HdDirtyBits& DirtyBits,
const pxr::TfToken& ReprToken);

bool AddStagingBufferSourceForPrimvar(StagingVertexData& StagingVerts,
bool AddStagingBufferSourceForPrimvar(HnRenderDelegate* RenderDelegate,
StagingVertexData& StagingVerts,
const pxr::TfToken& Name,
pxr::VtValue Primvar,
pxr::HdInterpolation Interpolation,
Expand All @@ -214,7 +215,7 @@ class HnMesh final : public pxr::HdMesh
const pxr::HdExtComputationPrimvarDescriptor& SkinningCompPrimDesc,
StagingVertexData& StagingVerts);

void GenerateSmoothNormals(StagingVertexData& StagingVerts);
void GenerateSmoothNormals(HnRenderDelegate& RenderDelegate, StagingVertexData& StagingVerts);

struct GeometrySubsetRange
{
Expand Down
3 changes: 3 additions & 0 deletions Hydrogent/interface/HnRenderDelegate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ class HnRenderDelegate final : public pxr::HdRenderDelegate
/// has no effect and texture loading will be synchronous.
bool AsyncTextureLoading = false;

/// Whether to pack vertex normals into a 32-bit uint.
bool PackVertexNormals = false;

/// When shadows are enabled, the size of the PCF kernel.
/// Allowed values are 2, 3, 5, 7.
Uint32 PCFKernelSize = 3;
Expand Down
11 changes: 10 additions & 1 deletion Hydrogent/src/HnGeometryPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,22 @@ class HnGeometryPool::VertexData final : public GeometryPoolData
const pxr::HdTupleType ElementType = Source->GetTupleType();
const size_t ElementSize = HdDataSizeOfType(ElementType.type) * ElementType.count;
if (SourceName == pxr::HdTokens->points)
{
VERIFY(ElementType.type == pxr::HdTypeFloatVec3 && ElementType.count == 1, "Unexpected vertex element type");
}
else if (SourceName == pxr::HdTokens->normals)
VERIFY(ElementType.type == pxr::HdTypeFloatVec3 && ElementType.count == 1, "Unexpected normal element type");
{
VERIFY((ElementType.type == pxr::HdTypeFloatVec3 || ElementType.type == pxr::HdTypeInt32) && ElementType.count == 1,
"Unexpected normal element type");
}
else if (SourceName == pxr::HdTokens->displayColor)
{
VERIFY(ElementType.type == pxr::HdTypeFloatVec3 && ElementType.count == 1, "Unexpected vertex color element type");
}
else if (SourceName == HnTokens->joints)
{
VERIFY(ElementType.type == pxr::HdTypeFloatVec4 && ElementType.count == 2, "Unexpected joints element type");
}

AddStream(SourceName, ElementSize, Source, nullptr);
}
Expand Down
44 changes: 30 additions & 14 deletions Hydrogent/src/HnMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ void HnMesh::UpdateRepr(pxr::HdSceneDelegate& SceneDelegate,
GetVertexBuffer(pxr::HdTokens->normals) == nullptr &&
!StagingVerts.Points.IsEmpty())
{
GenerateSmoothNormals(StagingVerts);
GenerateSmoothNormals(*RenderDelegate, StagingVerts);
}

UpdateConstantPrimvars(SceneDelegate, RenderParam, DirtyBits, ReprToken);
Expand Down Expand Up @@ -528,7 +528,8 @@ void HnMesh::UpdateTopology(pxr::HdSceneDelegate& SceneDelegate,
DirtyBits &= ~pxr::HdChangeTracker::DirtyTopology;
}

bool HnMesh::AddStagingBufferSourceForPrimvar(StagingVertexData& StagingVerts,
bool HnMesh::AddStagingBufferSourceForPrimvar(HnRenderDelegate* RenderDelegate,
StagingVertexData& StagingVerts,
const pxr::TfToken& Name,
pxr::VtValue Primvar,
pxr::HdInterpolation Interpolation,
Expand All @@ -537,6 +538,16 @@ bool HnMesh::AddStagingBufferSourceForPrimvar(StagingVertexData& StagingVerts,
if (Primvar.IsEmpty())
return false;

if (Name == pxr::HdTokens->normals)
{
VERIFY_EXPR(RenderDelegate != nullptr);
if (RenderDelegate != nullptr && RenderDelegate->GetUSDRenderer()->GetSettings().PackVertexNormals)
{
HnMeshUtils MeshUtils{m_Topology, GetId()};
Primvar = MeshUtils.PackVertexNormals(Primvar);
}
}

pxr::VtValue FaceVaryingPrimvar;
pxr::VtValue* pSrcPrimvar = &Primvar;
if ((Interpolation == pxr::HdInterpolationVertex || Interpolation == pxr::HdInterpolationVarying) && m_HasFaceVaryingPrimvars)
Expand Down Expand Up @@ -677,7 +688,7 @@ bool HnMesh::AddJointInfluencesStagingBufferSource(const pxr::VtValue& NumInflue
}
}

return AddStagingBufferSourceForPrimvar(StagingVerts, HnTokens->joints, pxr::VtValue::Take(Joints), pxr::HdInterpolationVertex, 2);
return AddStagingBufferSourceForPrimvar(nullptr, StagingVerts, HnTokens->joints, pxr::VtValue::Take(Joints), pxr::HdInterpolationVertex, 2);
}

void HnMesh::PrimvarsInfo::AddDirtyPrimvar(pxr::HdDirtyBits& DirtyBits,
Expand Down Expand Up @@ -781,9 +792,10 @@ void HnMesh::UpdateSkinningPrimvars(pxr::HdSceneDelegate&
const pxr::HdExtComputationPrimvarDescriptor& SkinningCompPrimDesc,
StagingVertexData& StagingVerts)
{
const pxr::HdRenderIndex& RenderIndex = SceneDelegate.GetRenderIndex();
const pxr::SdfPath& SkinnigCompId = SkinningCompPrimDesc.sourceComputationId;
const HnExtComputation* SkinningComp = static_cast<const HnExtComputation*>(RenderIndex.GetSprim(pxr::HdPrimTypeTokens->extComputation, SkinnigCompId));
const pxr::HdRenderIndex& RenderIndex = SceneDelegate.GetRenderIndex();
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(RenderIndex.GetRenderDelegate());
const pxr::SdfPath& SkinnigCompId = SkinningCompPrimDesc.sourceComputationId;
const HnExtComputation* SkinningComp = static_cast<const HnExtComputation*>(RenderIndex.GetSprim(pxr::HdPrimTypeTokens->extComputation, SkinnigCompId));
if (SkinningComp == nullptr)
{
LOG_ERROR_MESSAGE("Unable to find skinning computation ", SkinnigCompId);
Expand All @@ -807,7 +819,7 @@ void HnMesh::UpdateSkinningPrimvars(pxr::HdSceneDelegate&
SkinningPrimvarsVersion += InputAggregatorComp->GetSceneInputsVersion();
}

entt::registry& Registry = static_cast<HnRenderDelegate*>(SceneDelegate.GetRenderIndex().GetRenderDelegate())->GetEcsRegistry();
entt::registry& Registry = RenderDelegate->GetEcsRegistry();
Components::Skinning& SkinningData = Registry.get<Components::Skinning>(m_Entity);

if (SkinningPrimvarsVersion != m_SkinningPrimvarsVersion)
Expand Down Expand Up @@ -857,7 +869,7 @@ void HnMesh::UpdateSkinningPrimvars(pxr::HdSceneDelegate&

StagingVerts.Points = RestPointsVal;

AddStagingBufferSourceForPrimvar(StagingVerts, SkinningCompPrimDesc.name, std::move(RestPointsVal), SkinningCompPrimDesc.interpolation);
AddStagingBufferSourceForPrimvar(RenderDelegate, StagingVerts, SkinningCompPrimDesc.name, std::move(RestPointsVal), SkinningCompPrimDesc.interpolation);
AddJointInfluencesStagingBufferSource(NumInfluencesPerComponentVal, InfluencesVal, StagingVerts);

// Skeleton adapter hides normals, so try to get them directly from the scene delegate
Expand All @@ -867,9 +879,9 @@ void HnMesh::UpdateSkinningPrimvars(pxr::HdSceneDelegate&
// There is no way to get the interpolation of the normals primvar from the scene delegate,
// so rely on the number of elements.
if (NormalsPrimvar.GetArraySize() == m_Topology.GetNumPoints())
AddStagingBufferSourceForPrimvar(StagingVerts, pxr::HdTokens->normals, std::move(NormalsPrimvar), pxr::HdInterpolationVertex);
AddStagingBufferSourceForPrimvar(RenderDelegate, StagingVerts, pxr::HdTokens->normals, std::move(NormalsPrimvar), pxr::HdInterpolationVertex);
else if (NormalsPrimvar.GetArraySize() == m_Topology.GetNumFaceVaryings())
AddStagingBufferSourceForPrimvar(StagingVerts, pxr::HdTokens->normals, std::move(NormalsPrimvar), pxr::HdInterpolationFaceVarying);
AddStagingBufferSourceForPrimvar(RenderDelegate, StagingVerts, pxr::HdTokens->normals, std::move(NormalsPrimvar), pxr::HdInterpolationFaceVarying);
}

m_SkinningPrimvarsVersion = SkinningPrimvarsVersion;
Expand Down Expand Up @@ -900,6 +912,8 @@ void HnMesh::UpdateVertexAndVaryingPrimvars(pxr::HdSceneDelegate& SceneDelegate,
const PrimvarsInfo& VertexPrimvarsInfo,
StagingVertexData& StagingVerts)
{
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(SceneDelegate.GetRenderIndex().GetRenderDelegate());

for (const auto& it : VertexPrimvarsInfo.Dirty)
{
const pxr::TfToken& Name = it.first;
Expand All @@ -912,7 +926,7 @@ void HnMesh::UpdateVertexAndVaryingPrimvars(pxr::HdSceneDelegate& SceneDelegate,
if (PrimDesc.name == pxr::HdTokens->points)
StagingVerts.Points = PrimValue;

AddStagingBufferSourceForPrimvar(StagingVerts, Name, std::move(PrimValue), PrimDesc.interpolation);
AddStagingBufferSourceForPrimvar(RenderDelegate, StagingVerts, Name, std::move(PrimValue), PrimDesc.interpolation);
}

for (const pxr::HdExtComputationPrimvarDescriptor& ExtCompPrimDesc : VertexPrimvarsInfo.ExtComp)
Expand All @@ -932,13 +946,15 @@ void HnMesh::UpdateFaceVaryingPrimvars(pxr::HdSceneDelegate& SceneDelegate,
const PrimvarsInfo& FacePrimvarsInfo,
StagingVertexData& StagingVerts)
{
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(SceneDelegate.GetRenderIndex().GetRenderDelegate());

for (const auto& it : FacePrimvarsInfo.Dirty)
{
const pxr::TfToken& Name = it.first;
const pxr::HdPrimvarDescriptor& PrimDesc = it.second;

pxr::VtValue PrimValue = GetPrimvar(&SceneDelegate, PrimDesc.name);
AddStagingBufferSourceForPrimvar(StagingVerts, Name, std::move(PrimValue), PrimDesc.interpolation);
AddStagingBufferSourceForPrimvar(RenderDelegate, StagingVerts, Name, std::move(PrimValue), PrimDesc.interpolation);
}
}

Expand Down Expand Up @@ -1000,7 +1016,7 @@ void HnMesh::UpdateConstantPrimvars(pxr::HdSceneDelegate& SceneDelegate,
}
}

void HnMesh::GenerateSmoothNormals(StagingVertexData& StagingVerts)
void HnMesh::GenerateSmoothNormals(HnRenderDelegate& RenderDelegate, StagingVertexData& StagingVerts)
{
pxr::Hd_VertexAdjacency Adjacency;
Adjacency.BuildAdjacencyTable(&m_Topology);
Expand All @@ -1025,7 +1041,7 @@ void HnMesh::GenerateSmoothNormals(StagingVertexData& StagingVerts)
return;
}

AddStagingBufferSourceForPrimvar(StagingVerts, pxr::HdTokens->normals, pxr::VtValue::Take(Normals), pxr::HdInterpolationVertex);
AddStagingBufferSourceForPrimvar(&RenderDelegate, StagingVerts, pxr::HdTokens->normals, pxr::VtValue::Take(Normals), pxr::HdInterpolationVertex);
}

void HnMesh::UpdateIndexData(StagingIndexData& StagingInds, const pxr::VtValue& Points)
Expand Down
21 changes: 21 additions & 0 deletions Hydrogent/src/HnMeshUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "DebugUtilities.hpp"
#include "AdvancedMath.hpp"
#include "GfTypeConversions.hpp"
#include "PBR_Renderer.hpp"

#include "pxr/base/gf/vec2i.h"
#include "pxr/base/gf/vec3i.h"
Expand Down Expand Up @@ -375,6 +376,26 @@ pxr::VtValue HnMeshUtils::ConvertVertexPrimvarToFaceVarying(const pxr::VtValue&
}
}

pxr::VtValue HnMeshUtils::PackVertexNormals(const pxr::VtValue& Normals) const
{
if (Normals.IsHolding<pxr::VtVec3fArray>())
{
const pxr::VtVec3fArray& NormalsArray = Normals.UncheckedGet<pxr::VtVec3fArray>();
pxr::VtIntArray PackedNormals(NormalsArray.size());
Uint32* pPackedNormals = reinterpret_cast<Uint32*>(PackedNormals.data());
for (size_t i = 0; i < NormalsArray.size(); ++i)
{
pPackedNormals[i] = PBR_Renderer::PackVertexNormal(ToFloat3(NormalsArray[i]));
}
return pxr::VtValue::Take(PackedNormals);
}
else
{
LOG_ERROR_MESSAGE("Failed to pack vertex normals for mesh '", m_MeshId.GetString(), "': ", Normals.GetTypeName(), " is not supported");
return {};
}
}

} // namespace USD

} // namespace Diligent
15 changes: 13 additions & 2 deletions Hydrogent/src/HnRenderDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ static std::shared_ptr<USD_Renderer> CreateUSDRenderer(const HnRenderDelegate::C
USDRendererCI.EnableClearCoat = true;

USDRendererCI.AllowHotShaderReload = RenderDelegateCI.AllowHotShaderReload;
USDRendererCI.PackVertexNormals = RenderDelegateCI.PackVertexNormals;

const RenderDeviceInfo& DeviceInfo = RenderDelegateCI.pDevice->GetDeviceInfo();
// There is a major performance degradation when using row-major matrices
Expand Down Expand Up @@ -252,11 +253,21 @@ static std::shared_ptr<USD_Renderer> CreateUSDRenderer(const HnRenderDelegate::C
USDRendererCI.ShaderTexturesArrayMode = USD_Renderer::SHADER_TEXTURE_ARRAY_MODE_NONE;
}

static constexpr LayoutElement Inputs[] =
// float3 Normal : ATTRIB1;
// or
// uint Normal : ATTRIB1;
const LayoutElement NormalInput{
USD_Renderer::VERTEX_ATTRIB_ID_NORMAL,
HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS,
USDRendererCI.PackVertexNormals ? 1u : 3u,
USDRendererCI.PackVertexNormals ? VT_UINT32 : VT_FLOAT32,
false, // IsNormalized
};
const LayoutElement Inputs[] =
{
// clang-format off
{USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 3, VT_FLOAT32}, // float3 Pos : ATTRIB0;
{USD_Renderer::VERTEX_ATTRIB_ID_NORMAL, HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS, 3, VT_FLOAT32}, // float3 Normal : ATTRIB1;
NormalInput,
{USD_Renderer::VERTEX_ATTRIB_ID_TEXCOORD0, HnRenderPass::VERTEX_BUFFER_SLOT_TEX_COORDS0, 2, VT_FLOAT32}, // float2 UV0 : ATTRIB2;
{USD_Renderer::VERTEX_ATTRIB_ID_TEXCOORD1, HnRenderPass::VERTEX_BUFFER_SLOT_TEX_COORDS1, 2, VT_FLOAT32}, // float2 UV1 : ATTRIB3;
{USD_Renderer::VERTEX_ATTRIB_ID_COLOR, HnRenderPass::VERTEX_BUFFER_SLOT_VERTEX_COLORS, 3, VT_FLOAT32}, // float3 Color : ATTRIB6;
Expand Down
8 changes: 8 additions & 0 deletions PBR/interface/PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ class PBR_Renderer
/// Whether to use skin pre-transform before applying joint transformations.
bool UseSkinPreTransform = false;

/// Whether vertex normals are packed into a single 32-bit uint, see PackVertexNormal().
bool PackVertexNormals = false;

/// PCF shadow kernel size.
/// Allowed values are 2, 3, 5, 7.
Uint32 PCFKernelSize = 3;
Expand Down Expand Up @@ -721,6 +724,11 @@ class PBR_Renderer
Uint32 GetJointsBufferSize() const;
const char* GetJointTransformsVarName() const;

/// Packs normal into a single 32-bit uint.
///
/// \remarks The function assumes that the input vector is normalized.
static Uint32 PackVertexNormal(const float3& Normal);

protected:
ShaderMacroHelper DefineMacros(const PSOKey& Key) const;

Expand Down
43 changes: 39 additions & 4 deletions PBR/src/PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,7 @@ ShaderMacroHelper PBR_Renderer::DefineMacros(const PSOKey& Key) const
Macros.Add("JOINTS_BUFFER_MODE", static_cast<int>(m_Settings.JointsBufferMode));

Macros.Add("USE_SKIN_PRE_TRANSFORM", m_Settings.UseSkinPreTransform);
Macros.Add("PACK_VERTEX_NORMALS", m_Settings.PackVertexNormals);
Macros.Add("TONE_MAPPING_MODE", "TONE_MAPPING_MODE_UNCHARTED2");

Macros.Add("PRIMITIVE_ARRAY_SIZE", static_cast<int>(m_Settings.PrimitiveArraySize));
Expand Down Expand Up @@ -1447,11 +1448,19 @@ void PBR_Renderer::GetVSInputStructAndLayout(PSO_FLAGS PSOFlags,
}
}

const VSAttribInfo VSNormalAttrib{
VERTEX_ATTRIB_ID_NORMAL,
"Normal",
m_Settings.PackVertexNormals ? VT_UINT32 : VT_FLOAT32,
m_Settings.PackVertexNormals ? 1u : 3u,
PSO_FLAG_USE_VERTEX_NORMALS,
};

const std::array<VSAttribInfo, 8> VSAttribs = //
{
// clang-format off
VSAttribInfo{VERTEX_ATTRIB_ID_POSITION, "Pos", VT_FLOAT32, 3, PSO_FLAG_NONE},
VSAttribInfo{VERTEX_ATTRIB_ID_NORMAL, "Normal", VT_FLOAT32, 3, PSO_FLAG_USE_VERTEX_NORMALS},
VSNormalAttrib,
VSAttribInfo{VERTEX_ATTRIB_ID_TEXCOORD0, "UV0", VT_FLOAT32, 2, PSO_FLAG_USE_TEXCOORD0},
VSAttribInfo{VERTEX_ATTRIB_ID_TEXCOORD1, "UV1", VT_FLOAT32, 2, PSO_FLAG_USE_TEXCOORD1},
VSAttribInfo{VERTEX_ATTRIB_ID_JOINTS, "Joint0", VT_FLOAT32, 4, PSO_FLAG_USE_JOINTS},
Expand Down Expand Up @@ -1486,8 +1495,26 @@ void PBR_Renderer::GetVSInputStructAndLayout(PSO_FLAGS PSOFlags,
DEV_CHECK_ERR(AttribFound, "Input layout does not contain attribute '", Attrib.Name, "' (index ", Attrib.Index, ")");
}
#endif
VERIFY_EXPR(Attrib.Type == VT_FLOAT32);
ss << " float" << Attrib.NumComponents << std::setw(9) << Attrib.Name << " : ATTRIB" << Attrib.Index << ";" << std::endl;
switch (Attrib.Type)
{
case VT_FLOAT32:
ss << " float";
break;
case VT_UINT32:
ss << " uint";
break;
default:
UNEXPECTED("Unexpected attribute type");
}
if (Attrib.NumComponents > 1)
{
ss << Attrib.NumComponents;
}
else
{
ss << ' ';
}
ss << std::setw(9) << Attrib.Name << " : ATTRIB" << Attrib.Index << ";" << std::endl;
}
else
{
Expand Down Expand Up @@ -1652,7 +1679,7 @@ void PBR_Renderer::CreatePSO(PsoHashMapType& PsoHashMap,
GraphicsDesc.PrimitiveTopology == PRIMITIVE_TOPOLOGY_POINT_LIST &&
m_Device.GetDeviceInfo().IsVulkanDevice() &&
m_Settings.PrimitiveArraySize == 0; // When PrimitiveArraySize > 0, we convert HLSL to GLSL
const auto VSOutputStruct = GetVSOutputStruct(PSOFlags, UseVkPointSize, m_Settings.PrimitiveArraySize > 0);
const std::string VSOutputStruct = GetVSOutputStruct(PSOFlags, UseVkPointSize, m_Settings.PrimitiveArraySize > 0);

CreateInfo::PSMainSourceInfo PSMainSource;
if (m_Settings.GetPSMainSource)
Expand Down Expand Up @@ -2089,4 +2116,12 @@ void* PBR_Renderer::WriteSkinningData(void* pDst, const WriteSkinningDataAttribs
return WriteSkinningData(pDst, Attribs, PackMatrixRowMajor, m_Settings.MaxJointCount, m_Settings.UseSkinPreTransform);
}

Uint32 PBR_Renderer::PackVertexNormal(const float3& Normal)
{
Uint32 x = static_cast<Uint32>(clamp((Normal.x + 1.f) * 32767.f, 0.f, 65535.f));
Uint32 y = static_cast<Uint32>(clamp((Normal.y + 1.f) * 16383.f, 0.f, 32767.f));
Uint32 z = Normal.z >= 0 ? 0 : 1;
return x | (y << 16) | (z << 31);
}

} // namespace Diligent
Loading

0 comments on commit 0dd567b

Please sign in to comment.