Skip to content

Commit

Permalink
PBR Renderer and Hydrogent: added option to pack vertex positions int…
Browse files Browse the repository at this point in the history
…o two 32-bit uints
  • Loading branch information
TheMostDiligent committed Nov 9, 2024
1 parent 0dd567b commit 5d5598c
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 67 deletions.
7 changes: 7 additions & 0 deletions Hydrogent/include/HnMeshUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ class HnMeshUtils final
/// Pack vertex normals into 32-bit unsigned integers.
pxr::VtValue PackVertexNormals(const pxr::VtValue& Normals) const;


/// Pack positions into two 32-bit unsigned integers.
/// The positions are scaled and biased to fit into the range [0, 1].
/// The original positions can be recovered using the following formula:
/// Position = (PackedPosition * Scale) + Bias
pxr::VtValue PackVertexPositions(const pxr::VtValue& Points, pxr::GfVec3f& Scale, pxr::GfVec3f& Bias) const;

private:
template <typename HandleFaceType>
void ProcessFaces(HandleFaceType&& HandleFace) const;
Expand Down
6 changes: 5 additions & 1 deletion Hydrogent/interface/HnMesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ class HnMesh final : public pxr::HdMesh
{
struct Transform
{
float4x4 Val = float4x4::Identity();
float4x4 Matrix = float4x4::Identity();
float3 PosScale = {1, 1, 1};
float3 PosBias = {0, 0, 0};
};

struct DisplayColor
Expand Down Expand Up @@ -204,6 +206,8 @@ class HnMesh final : public pxr::HdMesh
pxr::HdInterpolation Interpolation,
int ValuesPerElement = 1);

void PreprocessPrimvar(HnRenderDelegate* RenderDelegate, const pxr::TfToken& Name, pxr::VtValue& Primvar);

bool AddJointInfluencesStagingBufferSource(const pxr::VtValue& NumInfluencesPerComponentVal,
const pxr::VtValue& InfluencesVal,
StagingVertexData& StagingVerts);
Expand Down
3 changes: 3 additions & 0 deletions Hydrogent/interface/HnRenderDelegate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ class HnRenderDelegate final : public pxr::HdRenderDelegate
/// Whether to pack vertex normals into a 32-bit uint.
bool PackVertexNormals = false;

/// Whether to pack vertex positions into two 32-bit uints.
bool PackVertexPositions = false;

/// When shadows are enabled, the size of the PCF kernel.
/// Allowed values are 2, 3, 5, 7.
Uint32 PCFKernelSize = 3;
Expand Down
3 changes: 2 additions & 1 deletion Hydrogent/src/HnGeometryPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ class HnGeometryPool::VertexData final : public GeometryPoolData
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");
VERIFY((ElementType.type == pxr::HdTypeFloatVec3 || ElementType.type == pxr::HdTypeInt32Vec2) && ElementType.count == 1,
"Unexpected vertex element type");
}
else if (SourceName == pxr::HdTokens->normals)
{
Expand Down
40 changes: 30 additions & 10 deletions Hydrogent/src/HnMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ void HnMesh::UpdateRepr(pxr::HdSceneDelegate& SceneDelegate,
if (pxr::HdChangeTracker::IsTransformDirty(DirtyBits, Id))
{
entt::registry& Registry = RenderDelegate->GetEcsRegistry();
float4x4& Transform = Registry.get<Components::Transform>(m_Entity).Val;
float4x4& Transform = Registry.get<Components::Transform>(m_Entity).Matrix;

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

void HnMesh::PreprocessPrimvar(HnRenderDelegate* RenderDelegate, const pxr::TfToken& Name, pxr::VtValue& Primvar)
{
if (Name == pxr::HdTokens->points)
{
VERIFY_EXPR(RenderDelegate != nullptr);
if (RenderDelegate != nullptr && RenderDelegate->GetUSDRenderer()->GetSettings().VertexPosPackMode == PBR_Renderer::VERTEX_POS_PACK_MODE_64_BIT)
{
HnMeshUtils MeshUtils{m_Topology, GetId()};
pxr::GfVec3f UnpackScale, UnpackBias;
Primvar = MeshUtils.PackVertexPositions(Primvar, UnpackScale, UnpackBias);

entt::registry& Registry = RenderDelegate->GetEcsRegistry();
Components::Transform& Transform = Registry.get<Components::Transform>(m_Entity);
Transform.PosScale = ToFloat3(UnpackScale);
Transform.PosBias = ToFloat3(UnpackBias);
}
}
else 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);
}
}
}

bool HnMesh::AddStagingBufferSourceForPrimvar(HnRenderDelegate* RenderDelegate,
StagingVertexData& StagingVerts,
const pxr::TfToken& Name,
Expand All @@ -538,15 +566,7 @@ bool HnMesh::AddStagingBufferSourceForPrimvar(HnRenderDelegate* RenderDelegat
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);
}
}
PreprocessPrimvar(RenderDelegate, Name, Primvar);

pxr::VtValue FaceVaryingPrimvar;
pxr::VtValue* pSrcPrimvar = &Primvar;
Expand Down
66 changes: 55 additions & 11 deletions Hydrogent/src/HnMeshUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,22 +378,66 @@ pxr::VtValue HnMeshUtils::ConvertVertexPrimvarToFaceVarying(const pxr::VtValue&

pxr::VtValue HnMeshUtils::PackVertexNormals(const pxr::VtValue& Normals) const
{
if (Normals.IsHolding<pxr::VtVec3fArray>())
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);
LOG_ERROR_MESSAGE("Failed to pack vertex normals for mesh '", m_MeshId.GetString(), "': ", Normals.GetTypeName(), " is not supported");
return {};
}
else

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)
{
LOG_ERROR_MESSAGE("Failed to pack vertex normals for mesh '", m_MeshId.GetString(), "': ", Normals.GetTypeName(), " is not supported");
pPackedNormals[i] = PBR_Renderer::PackVertexNormal(ToFloat3(NormalsArray[i]));
}
return pxr::VtValue::Take(PackedNormals);
}

pxr::VtValue HnMeshUtils::PackVertexPositions(const pxr::VtValue& Points, pxr::GfVec3f& Scale, pxr::GfVec3f& Bias) const
{
if (!Points.IsHolding<pxr::VtVec3fArray>())
{
LOG_ERROR_MESSAGE("Failed to pack vertex positions for mesh '", m_MeshId.GetString(), "': ", Points.GetTypeName(), " is not supported");
return {};
}

const pxr::VtVec3fArray& PointsArray = Points.UncheckedGet<pxr::VtVec3fArray>();

pxr::GfVec3f MinPos{FLT_MAX};
pxr::GfVec3f MaxPos{-FLT_MAX};
for (const pxr::GfVec3f& Pos : PointsArray)
{
MinPos[0] = std::min(MinPos[0], Pos[0]);
MinPos[1] = std::min(MinPos[1], Pos[1]);
MinPos[2] = std::min(MinPos[2], Pos[2]);
MaxPos[0] = std::max(MaxPos[0], Pos[0]);
MaxPos[1] = std::max(MaxPos[1], Pos[1]);
MaxPos[2] = std::max(MaxPos[2], Pos[2]);
}
Bias = MinPos;
Scale = MaxPos - MinPos;

const float3 PackScale{
Scale[0] != 0.f ? 1.f / Scale[0] : 1.f,
Scale[1] != 0.f ? 1.f / Scale[1] : 1.f,
Scale[2] != 0.f ? 1.f / Scale[2] : 1.f,
};
const float3 PackBias{
-MinPos[0],
-MinPos[1],
-MinPos[2],
};

pxr::VtVec2iArray PackedPositions(PointsArray.size());
uint2* pPackedPositions = reinterpret_cast<uint2*>(PackedPositions.data());
const float3* pPoints = reinterpret_cast<const float3*>(PointsArray.data());
for (size_t i = 0; i < PointsArray.size(); ++i)
{
PBR_Renderer::PackVertexPos64(pPoints[i], PackBias, PackScale, pPackedPositions[i].x, pPackedPositions[i].y);
}

return pxr::VtValue::Take(PackedPositions);
}

} // namespace USD
Expand Down
24 changes: 12 additions & 12 deletions Hydrogent/src/HnRenderDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ static std::shared_ptr<USD_Renderer> CreateUSDRenderer(const HnRenderDelegate::C

USDRendererCI.AllowHotShaderReload = RenderDelegateCI.AllowHotShaderReload;
USDRendererCI.PackVertexNormals = RenderDelegateCI.PackVertexNormals;
USDRendererCI.VertexPosPackMode = RenderDelegateCI.PackVertexPositions ?
USD_Renderer::VERTEX_POS_PACK_MODE_64_BIT :
USD_Renderer::VERTEX_POS_PACK_MODE_NONE;

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

// 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
};
// clang-format off
constexpr LayoutElement NormalInput {USD_Renderer::VERTEX_ATTRIB_ID_NORMAL, HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS, 3, VT_FLOAT32}; // float3 Normal : ATTRIB1;
constexpr LayoutElement NormalInputPacked{USD_Renderer::VERTEX_ATTRIB_ID_NORMAL, HnRenderPass::VERTEX_BUFFER_SLOT_NORMALS, 1, VT_UINT32, false}; // uint Normal : ATTRIB1;
constexpr LayoutElement PosInput {USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 3, VT_FLOAT32}; // float3 Pos : ATTRIB0;
constexpr LayoutElement PosInputPacked64 {USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 2, VT_UINT32, false}; // uint2 Pos : ATTRIB0;
// clang-format om

const LayoutElement Inputs[] =
{
// clang-format off
{USD_Renderer::VERTEX_ATTRIB_ID_POSITION, HnRenderPass::VERTEX_BUFFER_SLOT_POSITIONS, 3, VT_FLOAT32}, // float3 Pos : ATTRIB0;
NormalInput,
USDRendererCI.VertexPosPackMode == USD_Renderer::VERTEX_POS_PACK_MODE_64_BIT ? PosInputPacked64 : PosInput,
USDRendererCI.PackVertexNormals ? NormalInputPacked : 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
14 changes: 8 additions & 6 deletions Hydrogent/src/HnRenderPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ HnRenderPass::DrawListItem::DrawListItem(HnRenderDelegate& RenderDelegate,
NumVertexBuffers{0}
{
entt::registry& Registry = RenderDelegate.GetEcsRegistry();
PrevTransform = Registry.get<HnMesh::Components::Transform>(MeshEntity).Val;
PrevTransform = Registry.get<HnMesh::Components::Transform>(MeshEntity).Matrix;
}

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

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

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

GLTF_PBR_Renderer::PBRPrimitiveShaderAttribsData AttribsData{
ListItem.PSOFlags,
&Transform,
&Transform.Matrix,
&ListItem.PrevTransform,
JointCount,
FirstJoint,
&Transform.PosScale,
&Transform.PosBias,
nullptr, // CustomData
0, // CustomDataSize
&pDstMaterialBasicAttribs,
Expand All @@ -676,7 +678,7 @@ HnRenderPass::EXECUTE_RESULT HnRenderPass::Execute(HnRenderPassState& RPState, c
// Using PBRPrimitiveShaderAttribs's CustomData will not work as fallback PSO uses different flags.
pDstMaterialBasicAttribs->CustomData.x = ListItem.MeshUID;

ListItem.PrevTransform = Transform;
ListItem.PrevTransform = Transform.Matrix;

m_PendingDrawItems.push_back(PendingDrawItem{
ListItem,
Expand Down
2 changes: 2 additions & 0 deletions PBR/interface/GLTF_PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ class GLTF_PBR_Renderer : public PBR_Renderer
const float4x4* PrevNodeMatrix = nullptr;
const Uint32 JointCount = 0;
const Uint32 FirstJoint = 0;
const float3* PosScale = nullptr;
const float3* PosBias = nullptr;
const void* CustomData = nullptr;
size_t CustomDataSize = 0;

Expand Down
45 changes: 44 additions & 1 deletion PBR/interface/PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ class PBR_Renderer
JOINTS_BUFFER_MODE_STRUCTURED,
};

/// Vertex position packing mode.
enum VERTEX_POS_PACK_MODE : Uint8
{
/// Vertex positions are not packed and are stored as float3.
VERTEX_POS_PACK_MODE_NONE = 0,

/// Vertex positoins are packed into two 32-bit uints using

Check failure on line 137 in PBR/interface/PBR_Renderer.hpp

View workflow job for this annotation

GitHub Actions / Linux -> Pre-checks

positoins ==> positions
/// 21 bits for normalized x, y, z coordinates, see PackVertxPos64().
VERTEX_POS_PACK_MODE_64_BIT,
};

/// Renderer create info
struct CreateInfo
{
Expand Down Expand Up @@ -205,6 +216,9 @@ class PBR_Renderer
/// Whether vertex normals are packed into a single 32-bit uint, see PackVertexNormal().
bool PackVertexNormals = false;

/// Vertex position packing mode, see VERTEX_POS_PACK_MODE.
VERTEX_POS_PACK_MODE VertexPosPackMode = VERTEX_POS_PACK_MODE_NONE;

/// PCF shadow kernel size.
/// Allowed values are 2, 3, 5, 7.
Uint32 PCFKernelSize = 3;
Expand Down Expand Up @@ -727,7 +741,15 @@ class PBR_Renderer
/// Packs normal into a single 32-bit uint.
///
/// \remarks The function assumes that the input vector is normalized.
static Uint32 PackVertexNormal(const float3& Normal);
static inline Uint32 PackVertexNormal(const float3& Normal);

/// Packs vertex position into two 32-bit uints.
///
/// \remarks Bias and Scale are used to map the vertex position to the [0, 1] range as follows:
/// NormPos = (Pos + Bias) * Scale
/// Typically, Bias is set to the negated minimum vertex position and Scale is set to
/// one over the maximum vertex position minus the minimum vertex position.
static inline void PackVertexPos64(const float3& Pos, const float3& Bias, const float3& Scale, Uint32& U0, Uint32& U1);

protected:
ShaderMacroHelper DefineMacros(const PSOKey& Key) const;
Expand Down Expand Up @@ -906,4 +928,25 @@ inline void PBR_Renderer::ProcessTexturAttribs(PBR_Renderer::PSO_FLAGS PSOFlags,
}
}

inline 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);
}

inline void PBR_Renderer::PackVertexPos64(const float3& Pos, const float3& Bias, const float3& Scale, Uint32& U0, Uint32& U1)
{
// X Y Y Z
// | 0 ... 20 | 21 ... 31| | 0 ... 9 | 10 ... 30 |
// 21 11 10 21
constexpr float3 U21Scale{static_cast<float>((1 << 21) - 1)};
const float3 NormPos = (Pos + Bias) * Scale;
const uint3 U21Pos = clamp(NormPos * U21Scale, float3{0}, U21Scale).Recast<uint>();

U0 = U21Pos.x | (U21Pos.y << 21u);
U1 = (U21Pos.y >> 11u) | (U21Pos.z << 10u);
}

} // namespace Diligent
10 changes: 10 additions & 0 deletions PBR/src/GLTF_PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,16 @@ void* GLTF_PBR_Renderer::WritePBRPrimitiveShaderAttribs(void*
pDstTransforms->JointCount = static_cast<int>(AttribsData.JointCount);
pDstTransforms->FirstJoint = static_cast<int>(AttribsData.FirstJoint);

const float3& PosScale = AttribsData.PosScale != nullptr ? *AttribsData.PosScale : float3{1, 1, 1};
pDstTransforms->PosScaleX = PosScale.x;
pDstTransforms->PosScaleY = PosScale.y;
pDstTransforms->PosScaleZ = PosScale.z;

const float3& PosBias = AttribsData.PosBias != nullptr ? *AttribsData.PosBias : float3{0, 0, 0};
pDstTransforms->PosBiasX = PosBias.x;
pDstTransforms->PosBiasY = PosBias.y;
pDstTransforms->PosBiasZ = PosBias.z;

static_assert(sizeof(HLSL::GLTFNodeShaderTransforms) % 16 == 0, "Size of HLSL::GLTFNodeShaderTransforms must be a multiple of 16");
pDstPtr += sizeof(HLSL::GLTFNodeShaderTransforms);
}
Expand Down
Loading

0 comments on commit 5d5598c

Please sign in to comment.