Skip to content

Commit 5d5598c

Browse files
PBR Renderer and Hydrogent: added option to pack vertex positions into two 32-bit uints
1 parent 0dd567b commit 5d5598c

File tree

14 files changed

+236
-67
lines changed

14 files changed

+236
-67
lines changed

Hydrogent/include/HnMeshUtils.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ class HnMeshUtils final
166166
/// Pack vertex normals into 32-bit unsigned integers.
167167
pxr::VtValue PackVertexNormals(const pxr::VtValue& Normals) const;
168168

169+
170+
/// Pack positions into two 32-bit unsigned integers.
171+
/// The positions are scaled and biased to fit into the range [0, 1].
172+
/// The original positions can be recovered using the following formula:
173+
/// Position = (PackedPosition * Scale) + Bias
174+
pxr::VtValue PackVertexPositions(const pxr::VtValue& Points, pxr::GfVec3f& Scale, pxr::GfVec3f& Bias) const;
175+
169176
private:
170177
template <typename HandleFaceType>
171178
void ProcessFaces(HandleFaceType&& HandleFace) const;

Hydrogent/interface/HnMesh.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ class HnMesh final : public pxr::HdMesh
9595
{
9696
struct Transform
9797
{
98-
float4x4 Val = float4x4::Identity();
98+
float4x4 Matrix = float4x4::Identity();
99+
float3 PosScale = {1, 1, 1};
100+
float3 PosBias = {0, 0, 0};
99101
};
100102

101103
struct DisplayColor
@@ -204,6 +206,8 @@ class HnMesh final : public pxr::HdMesh
204206
pxr::HdInterpolation Interpolation,
205207
int ValuesPerElement = 1);
206208

209+
void PreprocessPrimvar(HnRenderDelegate* RenderDelegate, const pxr::TfToken& Name, pxr::VtValue& Primvar);
210+
207211
bool AddJointInfluencesStagingBufferSource(const pxr::VtValue& NumInfluencesPerComponentVal,
208212
const pxr::VtValue& InfluencesVal,
209213
StagingVertexData& StagingVerts);

Hydrogent/interface/HnRenderDelegate.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ class HnRenderDelegate final : public pxr::HdRenderDelegate
184184
/// Whether to pack vertex normals into a 32-bit uint.
185185
bool PackVertexNormals = false;
186186

187+
/// Whether to pack vertex positions into two 32-bit uints.
188+
bool PackVertexPositions = false;
189+
187190
/// When shadows are enabled, the size of the PCF kernel.
188191
/// Allowed values are 2, 3, 5, 7.
189192
Uint32 PCFKernelSize = 3;

Hydrogent/src/HnGeometryPool.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ class HnGeometryPool::VertexData final : public GeometryPoolData
188188
const size_t ElementSize = HdDataSizeOfType(ElementType.type) * ElementType.count;
189189
if (SourceName == pxr::HdTokens->points)
190190
{
191-
VERIFY(ElementType.type == pxr::HdTypeFloatVec3 && ElementType.count == 1, "Unexpected vertex element type");
191+
VERIFY((ElementType.type == pxr::HdTypeFloatVec3 || ElementType.type == pxr::HdTypeInt32Vec2) && ElementType.count == 1,
192+
"Unexpected vertex element type");
192193
}
193194
else if (SourceName == pxr::HdTokens->normals)
194195
{

Hydrogent/src/HnMesh.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ void HnMesh::UpdateRepr(pxr::HdSceneDelegate& SceneDelegate,
450450
if (pxr::HdChangeTracker::IsTransformDirty(DirtyBits, Id))
451451
{
452452
entt::registry& Registry = RenderDelegate->GetEcsRegistry();
453-
float4x4& Transform = Registry.get<Components::Transform>(m_Entity).Val;
453+
float4x4& Transform = Registry.get<Components::Transform>(m_Entity).Matrix;
454454

455455
float4x4 NewTransform = m_SkelLocalToPrimLocal * ToFloat4x4(SceneDelegate.GetTransform(Id));
456456
if (Transform != NewTransform)
@@ -528,6 +528,34 @@ void HnMesh::UpdateTopology(pxr::HdSceneDelegate& SceneDelegate,
528528
DirtyBits &= ~pxr::HdChangeTracker::DirtyTopology;
529529
}
530530

531+
void HnMesh::PreprocessPrimvar(HnRenderDelegate* RenderDelegate, const pxr::TfToken& Name, pxr::VtValue& Primvar)
532+
{
533+
if (Name == pxr::HdTokens->points)
534+
{
535+
VERIFY_EXPR(RenderDelegate != nullptr);
536+
if (RenderDelegate != nullptr && RenderDelegate->GetUSDRenderer()->GetSettings().VertexPosPackMode == PBR_Renderer::VERTEX_POS_PACK_MODE_64_BIT)
537+
{
538+
HnMeshUtils MeshUtils{m_Topology, GetId()};
539+
pxr::GfVec3f UnpackScale, UnpackBias;
540+
Primvar = MeshUtils.PackVertexPositions(Primvar, UnpackScale, UnpackBias);
541+
542+
entt::registry& Registry = RenderDelegate->GetEcsRegistry();
543+
Components::Transform& Transform = Registry.get<Components::Transform>(m_Entity);
544+
Transform.PosScale = ToFloat3(UnpackScale);
545+
Transform.PosBias = ToFloat3(UnpackBias);
546+
}
547+
}
548+
else if (Name == pxr::HdTokens->normals)
549+
{
550+
VERIFY_EXPR(RenderDelegate != nullptr);
551+
if (RenderDelegate != nullptr && RenderDelegate->GetUSDRenderer()->GetSettings().PackVertexNormals)
552+
{
553+
HnMeshUtils MeshUtils{m_Topology, GetId()};
554+
Primvar = MeshUtils.PackVertexNormals(Primvar);
555+
}
556+
}
557+
}
558+
531559
bool HnMesh::AddStagingBufferSourceForPrimvar(HnRenderDelegate* RenderDelegate,
532560
StagingVertexData& StagingVerts,
533561
const pxr::TfToken& Name,
@@ -538,15 +566,7 @@ bool HnMesh::AddStagingBufferSourceForPrimvar(HnRenderDelegate* RenderDelegat
538566
if (Primvar.IsEmpty())
539567
return false;
540568

541-
if (Name == pxr::HdTokens->normals)
542-
{
543-
VERIFY_EXPR(RenderDelegate != nullptr);
544-
if (RenderDelegate != nullptr && RenderDelegate->GetUSDRenderer()->GetSettings().PackVertexNormals)
545-
{
546-
HnMeshUtils MeshUtils{m_Topology, GetId()};
547-
Primvar = MeshUtils.PackVertexNormals(Primvar);
548-
}
549-
}
569+
PreprocessPrimvar(RenderDelegate, Name, Primvar);
550570

551571
pxr::VtValue FaceVaryingPrimvar;
552572
pxr::VtValue* pSrcPrimvar = &Primvar;

Hydrogent/src/HnMeshUtils.cpp

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -378,22 +378,66 @@ pxr::VtValue HnMeshUtils::ConvertVertexPrimvarToFaceVarying(const pxr::VtValue&
378378

379379
pxr::VtValue HnMeshUtils::PackVertexNormals(const pxr::VtValue& Normals) const
380380
{
381-
if (Normals.IsHolding<pxr::VtVec3fArray>())
381+
if (!Normals.IsHolding<pxr::VtVec3fArray>())
382382
{
383-
const pxr::VtVec3fArray& NormalsArray = Normals.UncheckedGet<pxr::VtVec3fArray>();
384-
pxr::VtIntArray PackedNormals(NormalsArray.size());
385-
Uint32* pPackedNormals = reinterpret_cast<Uint32*>(PackedNormals.data());
386-
for (size_t i = 0; i < NormalsArray.size(); ++i)
387-
{
388-
pPackedNormals[i] = PBR_Renderer::PackVertexNormal(ToFloat3(NormalsArray[i]));
389-
}
390-
return pxr::VtValue::Take(PackedNormals);
383+
LOG_ERROR_MESSAGE("Failed to pack vertex normals for mesh '", m_MeshId.GetString(), "': ", Normals.GetTypeName(), " is not supported");
384+
return {};
391385
}
392-
else
386+
387+
const pxr::VtVec3fArray& NormalsArray = Normals.UncheckedGet<pxr::VtVec3fArray>();
388+
pxr::VtIntArray PackedNormals(NormalsArray.size());
389+
Uint32* pPackedNormals = reinterpret_cast<Uint32*>(PackedNormals.data());
390+
for (size_t i = 0; i < NormalsArray.size(); ++i)
393391
{
394-
LOG_ERROR_MESSAGE("Failed to pack vertex normals for mesh '", m_MeshId.GetString(), "': ", Normals.GetTypeName(), " is not supported");
392+
pPackedNormals[i] = PBR_Renderer::PackVertexNormal(ToFloat3(NormalsArray[i]));
393+
}
394+
return pxr::VtValue::Take(PackedNormals);
395+
}
396+
397+
pxr::VtValue HnMeshUtils::PackVertexPositions(const pxr::VtValue& Points, pxr::GfVec3f& Scale, pxr::GfVec3f& Bias) const
398+
{
399+
if (!Points.IsHolding<pxr::VtVec3fArray>())
400+
{
401+
LOG_ERROR_MESSAGE("Failed to pack vertex positions for mesh '", m_MeshId.GetString(), "': ", Points.GetTypeName(), " is not supported");
395402
return {};
396403
}
404+
405+
const pxr::VtVec3fArray& PointsArray = Points.UncheckedGet<pxr::VtVec3fArray>();
406+
407+
pxr::GfVec3f MinPos{FLT_MAX};
408+
pxr::GfVec3f MaxPos{-FLT_MAX};
409+
for (const pxr::GfVec3f& Pos : PointsArray)
410+
{
411+
MinPos[0] = std::min(MinPos[0], Pos[0]);
412+
MinPos[1] = std::min(MinPos[1], Pos[1]);
413+
MinPos[2] = std::min(MinPos[2], Pos[2]);
414+
MaxPos[0] = std::max(MaxPos[0], Pos[0]);
415+
MaxPos[1] = std::max(MaxPos[1], Pos[1]);
416+
MaxPos[2] = std::max(MaxPos[2], Pos[2]);
417+
}
418+
Bias = MinPos;
419+
Scale = MaxPos - MinPos;
420+
421+
const float3 PackScale{
422+
Scale[0] != 0.f ? 1.f / Scale[0] : 1.f,
423+
Scale[1] != 0.f ? 1.f / Scale[1] : 1.f,
424+
Scale[2] != 0.f ? 1.f / Scale[2] : 1.f,
425+
};
426+
const float3 PackBias{
427+
-MinPos[0],
428+
-MinPos[1],
429+
-MinPos[2],
430+
};
431+
432+
pxr::VtVec2iArray PackedPositions(PointsArray.size());
433+
uint2* pPackedPositions = reinterpret_cast<uint2*>(PackedPositions.data());
434+
const float3* pPoints = reinterpret_cast<const float3*>(PointsArray.data());
435+
for (size_t i = 0; i < PointsArray.size(); ++i)
436+
{
437+
PBR_Renderer::PackVertexPos64(pPoints[i], PackBias, PackScale, pPackedPositions[i].x, pPackedPositions[i].y);
438+
}
439+
440+
return pxr::VtValue::Take(PackedPositions);
397441
}
398442

399443
} // namespace USD

Hydrogent/src/HnRenderDelegate.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ static std::shared_ptr<USD_Renderer> CreateUSDRenderer(const HnRenderDelegate::C
175175

176176
USDRendererCI.AllowHotShaderReload = RenderDelegateCI.AllowHotShaderReload;
177177
USDRendererCI.PackVertexNormals = RenderDelegateCI.PackVertexNormals;
178+
USDRendererCI.VertexPosPackMode = RenderDelegateCI.PackVertexPositions ?
179+
USD_Renderer::VERTEX_POS_PACK_MODE_64_BIT :
180+
USD_Renderer::VERTEX_POS_PACK_MODE_NONE;
178181

179182
const RenderDeviceInfo& DeviceInfo = RenderDelegateCI.pDevice->GetDeviceInfo();
180183
// There is a major performance degradation when using row-major matrices
@@ -253,21 +256,18 @@ static std::shared_ptr<USD_Renderer> CreateUSDRenderer(const HnRenderDelegate::C
253256
USDRendererCI.ShaderTexturesArrayMode = USD_Renderer::SHADER_TEXTURE_ARRAY_MODE_NONE;
254257
}
255258

256-
// float3 Normal : ATTRIB1;
257-
// or
258-
// uint Normal : ATTRIB1;
259-
const LayoutElement NormalInput{
260-
USD_Renderer::VERTEX_ATTRIB_ID_NORMAL,
261-
HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS,
262-
USDRendererCI.PackVertexNormals ? 1u : 3u,
263-
USDRendererCI.PackVertexNormals ? VT_UINT32 : VT_FLOAT32,
264-
false, // IsNormalized
265-
};
259+
// clang-format off
260+
constexpr LayoutElement NormalInput {USD_Renderer::VERTEX_ATTRIB_ID_NORMAL, HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS, 3, VT_FLOAT32}; // float3 Normal : ATTRIB1;
261+
constexpr LayoutElement NormalInputPacked{USD_Renderer::VERTEX_ATTRIB_ID_NORMAL, HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS, 1, VT_UINT32, false}; // uint Normal : ATTRIB1;
262+
constexpr LayoutElement PosInput {USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 3, VT_FLOAT32}; // float3 Pos : ATTRIB0;
263+
constexpr LayoutElement PosInputPacked64 {USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 2, VT_UINT32, false}; // uint2 Pos : ATTRIB0;
264+
// clang-format om
265+
266266
const LayoutElement Inputs[] =
267267
{
268268
// clang-format off
269-
{USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 3, VT_FLOAT32}, // float3 Pos : ATTRIB0;
270-
NormalInput,
269+
USDRendererCI.VertexPosPackMode == USD_Renderer::VERTEX_POS_PACK_MODE_64_BIT ? PosInputPacked64 : PosInput,
270+
USDRendererCI.PackVertexNormals ? NormalInputPacked : NormalInput,
271271
{USD_Renderer::VERTEX_ATTRIB_ID_TEXCOORD0, HnRenderPass::VERTEX_BUFFER_SLOT_TEX_COORDS0, 2, VT_FLOAT32}, // float2 UV0 : ATTRIB2;
272272
{USD_Renderer::VERTEX_ATTRIB_ID_TEXCOORD1, HnRenderPass::VERTEX_BUFFER_SLOT_TEX_COORDS1, 2, VT_FLOAT32}, // float2 UV1 : ATTRIB3;
273273
{USD_Renderer::VERTEX_ATTRIB_ID_COLOR, HnRenderPass::VERTEX_BUFFER_SLOT_VERTEX_COLORS, 3, VT_FLOAT32}, // float3 Color : ATTRIB6;

Hydrogent/src/HnRenderPass.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ HnRenderPass::DrawListItem::DrawListItem(HnRenderDelegate& RenderDelegate,
9191
NumVertexBuffers{0}
9292
{
9393
entt::registry& Registry = RenderDelegate.GetEcsRegistry();
94-
PrevTransform = Registry.get<HnMesh::Components::Transform>(MeshEntity).Val;
94+
PrevTransform = Registry.get<HnMesh::Components::Transform>(MeshEntity).Matrix;
9595
}
9696

9797
HnRenderPass::HnRenderPass(pxr::HdRenderIndex* pIndex,
@@ -504,9 +504,9 @@ HnRenderPass::EXECUTE_RESULT HnRenderPass::Execute(HnRenderPassState& RPState, c
504504
const HnMesh::Components::DisplayColor,
505505
const HnMesh::Components::Visibility>(ListItem.MeshEntity);
506506

507-
const float4x4& Transform = std::get<0>(MeshAttribs).Val;
508-
const float4& DisplayColor = std::get<1>(MeshAttribs).Val;
509-
const bool MeshVisibile = std::get<2>(MeshAttribs).Val;
507+
const HnMesh::Components::Transform& Transform = std::get<0>(MeshAttribs);
508+
const float4& DisplayColor = std::get<1>(MeshAttribs).Val;
509+
const bool MeshVisibile = std::get<2>(MeshAttribs).Val;
510510

511511
const HnMesh::Components::Skinning* pSkinningData = ((ListItem.PSOFlags & PBR_Renderer::PSO_FLAG_USE_JOINTS) && pJointsCB != nullptr) ?
512512
&MeshAttribsView.get<const HnMesh::Components::Skinning>(ListItem.MeshEntity) :
@@ -656,10 +656,12 @@ HnRenderPass::EXECUTE_RESULT HnRenderPass::Execute(HnRenderPassState& RPState, c
656656

657657
GLTF_PBR_Renderer::PBRPrimitiveShaderAttribsData AttribsData{
658658
ListItem.PSOFlags,
659-
&Transform,
659+
&Transform.Matrix,
660660
&ListItem.PrevTransform,
661661
JointCount,
662662
FirstJoint,
663+
&Transform.PosScale,
664+
&Transform.PosBias,
663665
nullptr, // CustomData
664666
0, // CustomDataSize
665667
&pDstMaterialBasicAttribs,
@@ -676,7 +678,7 @@ HnRenderPass::EXECUTE_RESULT HnRenderPass::Execute(HnRenderPassState& RPState, c
676678
// Using PBRPrimitiveShaderAttribs's CustomData will not work as fallback PSO uses different flags.
677679
pDstMaterialBasicAttribs->CustomData.x = ListItem.MeshUID;
678680

679-
ListItem.PrevTransform = Transform;
681+
ListItem.PrevTransform = Transform.Matrix;
680682

681683
m_PendingDrawItems.push_back(PendingDrawItem{
682684
ListItem,

PBR/interface/GLTF_PBR_Renderer.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ class GLTF_PBR_Renderer : public PBR_Renderer
255255
const float4x4* PrevNodeMatrix = nullptr;
256256
const Uint32 JointCount = 0;
257257
const Uint32 FirstJoint = 0;
258+
const float3* PosScale = nullptr;
259+
const float3* PosBias = nullptr;
258260
const void* CustomData = nullptr;
259261
size_t CustomDataSize = 0;
260262

PBR/interface/PBR_Renderer.hpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,17 @@ class PBR_Renderer
128128
JOINTS_BUFFER_MODE_STRUCTURED,
129129
};
130130

131+
/// Vertex position packing mode.
132+
enum VERTEX_POS_PACK_MODE : Uint8
133+
{
134+
/// Vertex positions are not packed and are stored as float3.
135+
VERTEX_POS_PACK_MODE_NONE = 0,
136+
137+
/// Vertex positoins are packed into two 32-bit uints using
138+
/// 21 bits for normalized x, y, z coordinates, see PackVertxPos64().
139+
VERTEX_POS_PACK_MODE_64_BIT,
140+
};
141+
131142
/// Renderer create info
132143
struct CreateInfo
133144
{
@@ -205,6 +216,9 @@ class PBR_Renderer
205216
/// Whether vertex normals are packed into a single 32-bit uint, see PackVertexNormal().
206217
bool PackVertexNormals = false;
207218

219+
/// Vertex position packing mode, see VERTEX_POS_PACK_MODE.
220+
VERTEX_POS_PACK_MODE VertexPosPackMode = VERTEX_POS_PACK_MODE_NONE;
221+
208222
/// PCF shadow kernel size.
209223
/// Allowed values are 2, 3, 5, 7.
210224
Uint32 PCFKernelSize = 3;
@@ -727,7 +741,15 @@ class PBR_Renderer
727741
/// Packs normal into a single 32-bit uint.
728742
///
729743
/// \remarks The function assumes that the input vector is normalized.
730-
static Uint32 PackVertexNormal(const float3& Normal);
744+
static inline Uint32 PackVertexNormal(const float3& Normal);
745+
746+
/// Packs vertex position into two 32-bit uints.
747+
///
748+
/// \remarks Bias and Scale are used to map the vertex position to the [0, 1] range as follows:
749+
/// NormPos = (Pos + Bias) * Scale
750+
/// Typically, Bias is set to the negated minimum vertex position and Scale is set to
751+
/// one over the maximum vertex position minus the minimum vertex position.
752+
static inline void PackVertexPos64(const float3& Pos, const float3& Bias, const float3& Scale, Uint32& U0, Uint32& U1);
731753

732754
protected:
733755
ShaderMacroHelper DefineMacros(const PSOKey& Key) const;
@@ -906,4 +928,25 @@ inline void PBR_Renderer::ProcessTexturAttribs(PBR_Renderer::PSO_FLAGS PSOFlags,
906928
}
907929
}
908930

931+
inline Uint32 PBR_Renderer::PackVertexNormal(const float3& Normal)
932+
{
933+
Uint32 x = static_cast<Uint32>(clamp((Normal.x + 1.f) * 32767.f, 0.f, 65535.f));
934+
Uint32 y = static_cast<Uint32>(clamp((Normal.y + 1.f) * 16383.f, 0.f, 32767.f));
935+
Uint32 z = Normal.z >= 0 ? 0 : 1;
936+
return x | (y << 16) | (z << 31);
937+
}
938+
939+
inline void PBR_Renderer::PackVertexPos64(const float3& Pos, const float3& Bias, const float3& Scale, Uint32& U0, Uint32& U1)
940+
{
941+
// X Y Y Z
942+
// | 0 ... 20 | 21 ... 31| | 0 ... 9 | 10 ... 30 |
943+
// 21 11 10 21
944+
constexpr float3 U21Scale{static_cast<float>((1 << 21) - 1)};
945+
const float3 NormPos = (Pos + Bias) * Scale;
946+
const uint3 U21Pos = clamp(NormPos * U21Scale, float3{0}, U21Scale).Recast<uint>();
947+
948+
U0 = U21Pos.x | (U21Pos.y << 21u);
949+
U1 = (U21Pos.y >> 11u) | (U21Pos.z << 10u);
950+
}
951+
909952
} // namespace Diligent

0 commit comments

Comments
 (0)