Skip to content

Commit

Permalink
Hydrogent: implemented geometry subsets
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Jul 16, 2024
1 parent 2a3d9f0 commit 23df5ee
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 92 deletions.
58 changes: 20 additions & 38 deletions Hydrogent/interface/HnMesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,43 +88,6 @@ class HnMesh final : public pxr::HdMesh
/// If the buffer doesn't exist, returns nullptr.
IBuffer* GetVertexBuffer(const pxr::TfToken& Name) const;

/// Returns the face index buffer.
///
/// \remarks The index buffer contains the triangle list.
IBuffer* GetFaceIndexBuffer() const { return m_IndexData.Faces; }

/// Returns the edges index buffer.
///
/// \remarks The index buffer contains the line list.
IBuffer* GetEdgeIndexBuffer() const { return m_IndexData.Edges; }

/// Returns the points index buffer.
///
/// \remarks The index buffer contains the point list.
IBuffer* GetPointsIndexBuffer() const { return m_IndexData.Points; }

Uint32 GetNumFaceTriangles() const { return m_IndexData.NumFaceTriangles; }
Uint32 GetNumEdges() const { return m_IndexData.NumEdges; }
Uint32 GetNumPoints() const { return m_Topology.GetNumPoints(); }

/// Returns the start index of the face data in the index buffer.
///
/// \remarks This value should be used as the start index location
/// for the face drawing commands.
Uint32 GetFaceStartIndex() const { return m_IndexData.FaceStartIndex; }

/// Returns the start index of the edges data in the index buffer.
///
/// \remarks This value should be used as the start index location
/// for the mesh edges drawing commands.
Uint32 GetEdgeStartIndex() const { return m_IndexData.EdgeStartIndex; }

/// Returns the start index of the points data in the index buffer.
///
/// \remarks This value should be used as the start index location
/// for the points drawing commands.
Uint32 GetPointsStartIndex() const { return m_IndexData.PointsStartIndex; }

struct Components
{
struct Transform
Expand Down Expand Up @@ -201,6 +164,22 @@ class HnMesh final : public pxr::HdMesh

void GenerateSmoothNormals();

struct GeometrySubsetRange
{
Uint32 StartIndex = 0;
Uint32 NumIndices = 0;
};

struct TriangleFaceIndexData
{
pxr::VtVec3iArray Indices;

std::vector<GeometrySubsetRange> Subsets;

operator bool() const { return !Indices.empty(); }
};
TriangleFaceIndexData ComputeTriangleFaceIndices();

// Converts vertex primvar sources into face-varying primvar sources.
void ConvertVertexPrimvarSources(FaceSourcesMapType&& FaceSources);

Expand Down Expand Up @@ -231,7 +210,8 @@ class HnMesh final : public pxr::HdMesh

struct StagingIndexData
{
pxr::VtVec3iArray TrianglesFaceIndices;
TriangleFaceIndexData Faces;

std::vector<pxr::GfVec2i> MeshEdgeIndices;
std::vector<Uint32> PointIndices;
};
Expand All @@ -252,6 +232,8 @@ class HnMesh final : public pxr::HdMesh
Uint32 EdgeStartIndex = 0;
Uint32 PointsStartIndex = 0;

std::vector<GeometrySubsetRange> Subsets;

RefCntAutoPtr<IBuffer> Faces;
RefCntAutoPtr<IBuffer> Edges;
RefCntAutoPtr<IBuffer> Points;
Expand Down
186 changes: 132 additions & 54 deletions Hydrogent/src/HnMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "EngineMemory.h"

#include "pxr/base/gf/vec2f.h"
#include "pxr/base/tf/smallVector.h"
#include "pxr/imaging/hd/meshUtil.h"
#include "pxr/imaging/hd/vtBufferSource.h"
#include "pxr/imaging/hd/vertexAdjacency.h"
Expand Down Expand Up @@ -411,11 +412,11 @@ void HnMesh::UpdateTopology(pxr::HdSceneDelegate& SceneDelegate,

m_StagingIndexData = std::make_unique<StagingIndexData>();

m_StagingIndexData->Faces = ComputeTriangleFaceIndices();
pxr::HdMeshUtil MeshUtil{&m_Topology, Id};
pxr::VtIntArray PrimitiveParams;
MeshUtil.ComputeTriangleIndices(&m_StagingIndexData->TrianglesFaceIndices, &PrimitiveParams, nullptr);
MeshUtil.EnumerateEdges(&m_StagingIndexData->MeshEdgeIndices);
m_IndexData.NumFaceTriangles = static_cast<Uint32>(m_StagingIndexData->TrianglesFaceIndices.size());
m_IndexData.Subsets = m_StagingIndexData->Faces.Subsets;
m_IndexData.NumFaceTriangles = static_cast<Uint32>(m_StagingIndexData->Faces.Indices.size());
m_IndexData.NumEdges = static_cast<Uint32>(m_StagingIndexData->MeshEdgeIndices.size());

DirtyBits &= ~pxr::HdChangeTracker::DirtyTopology;
Expand Down Expand Up @@ -739,19 +740,91 @@ class TriangulatedFaceBufferSource final : public pxr::HdBufferSource

} // namespace

HnMesh::TriangleFaceIndexData HnMesh::ComputeTriangleFaceIndices()
{
TriangleFaceIndexData FaceIndexData;

pxr::HdMeshUtil MeshUtil{&m_Topology, GetId()};
pxr::VtIntArray PrimitiveParams;
MeshUtil.ComputeTriangleIndices(&FaceIndexData.Indices, &PrimitiveParams, nullptr);

if (!m_Topology.GetGeomSubsets().empty())
{
const size_t FaceCount = m_Topology.GetFaceVertexCounts().size();
// PrimitiveParams is the mapping from the triangle index to the original face index.
// +--------+---------------+
// /| \ |\ | /
// / | \ B | \ C | /
// / | \ | \ | /
// / | \ | \ | C /
// / A | B \ | C \ | /
// / | \ | \ | /
// / | \| \|/
// +-------+--------+-------+
//
// 0 -> A
// 1 -> B, 2 -> B
// 3 -> C, 4 -> C, 5 -> C
//
// We need the reverse mapping:
// A -> {0}
// B -> {1, 2}
// C -> {3, 4, 5}
std::vector<pxr::TfSmallVector<int, 4>> FaceIdxToTriIdx(FaceCount);
for (int i = 0; i < PrimitiveParams.size(); ++i)
{
int FaceIndex = pxr::HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(PrimitiveParams[i]);
if (FaceIndex >= FaceCount)
{
LOG_ERROR_MESSAGE("Invalid face index ", FaceIndex, " decoded from primitive param for triangle ", i, " in ", GetId(), " mesh. Expected value in the range [0, ", FaceCount, ").");
continue;
}
FaceIdxToTriIdx[FaceIndex].push_back(i);
}

pxr::VtVec3iArray Indices;

ProcessDrawItems(
[](HnDrawItem& DrawItem) {},
[&](const pxr::HdGeomSubset& Subset, HnDrawItem& DrawItem) {
const Uint32 FirstTri = static_cast<Uint32>(Indices.size());
for (int FaceIndex : Subset.indices)
{
if (FaceIndex >= FaceCount)
{
LOG_ERROR_MESSAGE("Invalid face index ", FaceIndex, " for subset ", Subset.id, " in ", GetId(), " mesh. Expected value in the range [0, ", FaceCount, ").");
continue;
}

for (int TriIndex : FaceIdxToTriIdx[FaceIndex])
{
Indices.push_back(FaceIndexData.Indices[TriIndex]);
}
}
const Uint32 NumTris = static_cast<Uint32>(Indices.size() - FirstTri);
FaceIndexData.Subsets.emplace_back(GeometrySubsetRange{FirstTri * 3, NumTris * 3});
});
FaceIndexData.Indices = std::move(Indices);
}

return FaceIndexData;
}

void HnMesh::ConvertVertexPrimvarSources(FaceSourcesMapType&& FaceSources)
{
pxr::VtVec3iArray TrianglesFaceIndices;
if (!m_StagingIndexData || m_StagingIndexData->TrianglesFaceIndices.empty())
TriangleFaceIndexData Faces;
if (!m_StagingIndexData || !m_StagingIndexData->Faces)
{
// Need to regenerate triangle indices
pxr::HdMeshUtil MeshUtil{&m_Topology, GetId()};
pxr::VtIntArray PrimitiveParams;
MeshUtil.ComputeTriangleIndices(&TrianglesFaceIndices, &PrimitiveParams, nullptr);
if (TrianglesFaceIndices.empty())
Faces = ComputeTriangleFaceIndices();
if (!Faces)
return;

VERIFY(Faces.Subsets.size() == m_IndexData.Subsets.size(),
"The number of subsets is not consistent with the previously computed value. "
"This may indicate that the topology was not updated during the last sync.");
}
const pxr::VtVec3iArray& Indices = !TrianglesFaceIndices.empty() ? TrianglesFaceIndices : m_StagingIndexData->TrianglesFaceIndices;
const pxr::VtVec3iArray& Indices = !Faces.Indices.empty() ? Faces.Indices : m_StagingIndexData->Faces.Indices;
VERIFY(Indices.size() == m_IndexData.NumFaceTriangles,
"The number of indices is not consistent with the previously computed value. "
"This may indicate that the topology was not updated during the last sync.");
Expand Down Expand Up @@ -809,10 +882,10 @@ void HnMesh::ConvertVertexPrimvarSources(FaceSourcesMapType&& FaceSources)
}

// Replace original triangle indices with the list of unfolded face indices
m_StagingIndexData->TrianglesFaceIndices.resize(GetNumFaceTriangles());
for (Uint32 i = 0; i < m_StagingIndexData->TrianglesFaceIndices.size(); ++i)
m_StagingIndexData->Faces.Indices.resize(m_IndexData.NumFaceTriangles);
for (Uint32 i = 0; i < m_StagingIndexData->Faces.Indices.size(); ++i)
{
pxr::GfVec3i& Tri{m_StagingIndexData->TrianglesFaceIndices[i]};
pxr::GfVec3i& Tri{m_StagingIndexData->Faces.Indices[i]};
Tri[0] = i * 3 + 0;
Tri[1] = i * 3 + 1;
Tri[2] = i * 3 + 2;
Expand All @@ -836,7 +909,7 @@ void HnMesh::ConvertVertexPrimvarSources(FaceSourcesMapType&& FaceSources)
}

// Create point indices
m_StagingIndexData->PointIndices.resize(GetNumPoints());
m_StagingIndexData->PointIndices.resize(m_Topology.GetNumPoints());
for (size_t i = 0; i < m_StagingIndexData->PointIndices.size(); ++i)
{
auto v_it = ReverseVertexMapping.find(i);
Expand Down Expand Up @@ -899,9 +972,9 @@ void HnMesh::AllocatePooledResources(pxr::HdSceneDelegate& SceneDelegate,
const Uint32 StartVertex = m_VertexData.PoolAllocation->GetStartVertex();
if (m_StagingIndexData && StartVertex != 0)
{
if (!m_StagingIndexData->TrianglesFaceIndices.empty())
if (!m_StagingIndexData->Faces.Indices.empty())
{
for (pxr::GfVec3i& Tri : m_StagingIndexData->TrianglesFaceIndices)
for (pxr::GfVec3i& Tri : m_StagingIndexData->Faces.Indices)
{
Tri[0] += StartVertex;
Tri[1] += StartVertex;
Expand All @@ -928,7 +1001,7 @@ void HnMesh::AllocatePooledResources(pxr::HdSceneDelegate& SceneDelegate,
else
{
// If there are no point indices, we need to create them
m_StagingIndexData->PointIndices.resize(GetNumPoints());
m_StagingIndexData->PointIndices.resize(m_Topology.GetNumPoints());
for (Uint32 i = 0; i < m_StagingIndexData->PointIndices.size(); ++i)
{
m_StagingIndexData->PointIndices[i] = StartVertex + i;
Expand All @@ -939,21 +1012,21 @@ void HnMesh::AllocatePooledResources(pxr::HdSceneDelegate& SceneDelegate,

if (m_StagingIndexData && static_cast<const HnRenderParam*>(RenderParam)->GetUseIndexPool())
{
if (!m_StagingIndexData->TrianglesFaceIndices.empty())
if (!m_StagingIndexData->Faces.Indices.empty())
{
m_IndexData.FaceAllocation = ResMgr.AllocateIndices(sizeof(Uint32) * GetNumFaceTriangles() * 3);
m_IndexData.FaceAllocation = ResMgr.AllocateIndices(sizeof(Uint32) * m_IndexData.NumFaceTriangles * 3);
m_IndexData.FaceStartIndex = m_IndexData.FaceAllocation->GetOffset() / sizeof(Uint32);
}

if (!m_StagingIndexData->MeshEdgeIndices.empty())
{
m_IndexData.EdgeAllocation = ResMgr.AllocateIndices(sizeof(Uint32) * GetNumEdges() * 2);
m_IndexData.EdgeAllocation = ResMgr.AllocateIndices(sizeof(Uint32) * m_IndexData.NumEdges * 2);
m_IndexData.EdgeStartIndex = m_IndexData.EdgeAllocation->GetOffset() / sizeof(Uint32);
}

if (!m_StagingIndexData->PointIndices.empty())
{
m_IndexData.PointsAllocation = ResMgr.AllocateIndices(sizeof(Uint32) * GetNumPoints());
m_IndexData.PointsAllocation = ResMgr.AllocateIndices(sizeof(Uint32) * m_Topology.GetNumPoints());
m_IndexData.PointsStartIndex = m_IndexData.PointsAllocation->GetOffset() / sizeof(Uint32);
}
}
Expand Down Expand Up @@ -1064,31 +1137,31 @@ void HnMesh::UpdateIndexBuffer(HnRenderDelegate& RenderDelegate)
}
};

if (!m_StagingIndexData->TrianglesFaceIndices.empty())
if (!m_StagingIndexData->Faces.Indices.empty())
{
VERIFY_EXPR(GetNumFaceTriangles() == static_cast<size_t>(m_StagingIndexData->TrianglesFaceIndices.size()));
static_assert(sizeof(m_StagingIndexData->TrianglesFaceIndices[0]) == sizeof(Uint32) * 3, "Unexpected triangle data size");
VERIFY_EXPR(m_IndexData.NumFaceTriangles == static_cast<size_t>(m_StagingIndexData->Faces.Indices.size()));
static_assert(sizeof(m_StagingIndexData->Faces.Indices[0]) == sizeof(Uint32) * 3, "Unexpected triangle data size");
m_IndexData.Faces = PrepareIndexBuffer("Triangle Index Buffer",
m_StagingIndexData->TrianglesFaceIndices.data(),
GetNumFaceTriangles() * sizeof(Uint32) * 3,
m_StagingIndexData->Faces.Indices.data(),
m_IndexData.NumFaceTriangles * sizeof(Uint32) * 3,
m_IndexData.FaceAllocation);
}

if (!m_StagingIndexData->MeshEdgeIndices.empty())
{
VERIFY_EXPR(GetNumEdges() == static_cast<Uint32>(m_StagingIndexData->MeshEdgeIndices.size()));
VERIFY_EXPR(m_IndexData.NumEdges == static_cast<Uint32>(m_StagingIndexData->MeshEdgeIndices.size()));
m_IndexData.Edges = PrepareIndexBuffer("Edge Index Buffer",
m_StagingIndexData->MeshEdgeIndices.data(),
GetNumEdges() * sizeof(Uint32) * 2,
m_IndexData.NumEdges * sizeof(Uint32) * 2,
m_IndexData.EdgeAllocation);
}

if (!m_StagingIndexData->PointIndices.empty())
{
VERIFY_EXPR(GetNumPoints() == static_cast<Uint32>(m_StagingIndexData->PointIndices.size()));
VERIFY_EXPR(m_Topology.GetNumPoints() == static_cast<int>(m_StagingIndexData->PointIndices.size()));
m_IndexData.Points = PrepareIndexBuffer("Points Index Buffer",
m_StagingIndexData->PointIndices.data(),
GetNumPoints() * sizeof(Uint32),
m_Topology.GetNumPoints() * sizeof(Uint32),
m_IndexData.PointsAllocation);
}

Expand Down Expand Up @@ -1136,44 +1209,49 @@ void HnMesh::UpdateDrawItemGpuGeometry(HnRenderDelegate& RenderDelegate)

void HnMesh::UpdateDrawItemGpuTopology()
{
HnDrawItem::TopologyData FaceTopology{
GetFaceIndexBuffer(),
GetFaceStartIndex(),
GetNumFaceTriangles() * 3,
};
HnDrawItem::TopologyData EdgeTopology{
GetEdgeIndexBuffer(),
GetEdgeStartIndex(),
GetNumEdges() * 2,
};
HnDrawItem::TopologyData PointsTopology{
GetPointsIndexBuffer(),
GetPointsStartIndex(),
GetNumPoints(),
};

Uint32 SubsetIdx = 0;
ProcessDrawItems(
[&](HnDrawItem& DrawItem) {
if (m_Topology.GetGeomSubsets().empty())
{
DrawItem.SetFaces(FaceTopology);
DrawItem.SetEdges(EdgeTopology);
DrawItem.SetPoints(PointsTopology);
DrawItem.SetFaces({
m_IndexData.Faces,
m_IndexData.FaceStartIndex,
m_IndexData.NumFaceTriangles * 3,
});
}
else
{
// Do not set topology if there are geometry subsets, so
// that the render pass skips this draw item.
DrawItem.SetFaces({});
DrawItem.SetEdges({});
DrawItem.SetPoints({});
}

// Render edgesand points for the entire mesh at once
DrawItem.SetEdges({
m_IndexData.Edges,
m_IndexData.EdgeStartIndex,
m_IndexData.NumEdges * 2,
});

DrawItem.SetPoints({
m_IndexData.Points,
m_IndexData.PointsStartIndex,
static_cast<Uint32>(m_Topology.GetNumPoints()),
});
},
[&](const pxr::HdGeomSubset& Subset, HnDrawItem& DrawItem) {
DrawItem.SetFaces(FaceTopology);
DrawItem.SetEdges(EdgeTopology);
DrawItem.SetPoints(PointsTopology);
const GeometrySubsetRange& SubsetRange = m_IndexData.Subsets[SubsetIdx++];
DrawItem.SetFaces({
m_IndexData.Faces,
m_IndexData.FaceStartIndex + SubsetRange.StartIndex,
SubsetRange.NumIndices,
});
// Do not set edges and points for subsets
DrawItem.SetEdges({});
DrawItem.SetPoints({});
});
VERIFY_EXPR(m_IndexData.Subsets.size() == SubsetIdx);
}

void HnMesh::CommitGPUResources(HnRenderDelegate& RenderDelegate)
Expand Down

0 comments on commit 23df5ee

Please sign in to comment.