Skip to content

Commit

Permalink
mesh conversions between HalfEdgeMesh and IndexedMesh (#213)
Browse files Browse the repository at this point in the history
  • Loading branch information
T-rvw authored Aug 13, 2023
1 parent 7387f6a commit 862175a
Show file tree
Hide file tree
Showing 18 changed files with 339 additions and 52 deletions.
10 changes: 9 additions & 1 deletion auto/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,12 @@ project("AssetPipelineCore")

includedirs {
path.join(RootPath, "public"),
}
}

filter { "action:vs*" }
disablewarnings {
-- MSVC : "needs to have dll-interface to be used by clients of class".
-- This warning is not accurate indeed.
"4251"
}
filter {}
4 changes: 3 additions & 1 deletion examples/FbxToHEMToFbx/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ int main(int argc, char** argv)
{
for (const auto& mesh : pSceneDatabase->GetMeshes())
{
auto halfEdgeMesh = cd::HalfEdgeMesh::FromIndexedMesh(mesh);
auto halfEdgeMesh = cd::hem::HalfEdgeMesh::FromIndexedMesh(mesh);
assert(halfEdgeMesh.Validate());
auto newMesh = cd::Mesh::FromHalfEdgeMesh(halfEdgeMesh, cd::ConvertStrategy::TopologyFirst);
assert(newMesh.GetVertexCount() > 0U);
}
}

Expand Down
2 changes: 1 addition & 1 deletion private/HalfEdgeMesh/Edge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Point Edge::Center() const

Direction Edge::Normal() const
{
return Direction::Zero();
return (m_halfEdgeRef->GetFace()->Normal() + m_halfEdgeRef->GetTwin()->GetFace()->Normal()).Normalize();
}

float Edge::Length() const
Expand Down
15 changes: 14 additions & 1 deletion private/HalfEdgeMesh/Face.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@ Point Face::Center() const

Direction Face::Normal() const
{
return Direction::Zero();
Direction normal(0.0f);

HalfEdgeCRef h = m_halfEdgeRef;
do
{
Direction v1 = h->GetVertex()->GetPosition();
Direction v2 = h->GetNext()->GetVertex()->GetPosition();
normal += v1.Cross(v2);

h = h->GetNext();
} while (h != m_halfEdgeRef);

normal.Normalize();
return normal;
}

uint32_t Face::Degree() const
Expand Down
27 changes: 26 additions & 1 deletion private/HalfEdgeMesh/HalfEdgeMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,32 @@ HalfEdgeMesh HalfEdgeMesh::FromIndexedFaces(const std::vector<cd::Point>& vertic

HalfEdgeMesh HalfEdgeMesh::FromIndexedMesh(const cd::Mesh& mesh)
{
return HalfEdgeMesh::FromIndexedFaces(mesh.GetVertexPositions(), mesh.GetPolygons());
auto halfEdgeMesh = HalfEdgeMesh::FromIndexedFaces(mesh.GetVertexPositions(), mesh.GetPolygons());

// Fill corner uv/normal data.
uint32_t vertexIndex = 0U;
for (const auto& vertex : halfEdgeMesh.GetVertices())
{
assert(vertexIndex < mesh.GetVertexCount());
HalfEdgeRef h = vertex.GetHalfEdge();

do
{
if (!h->GetFace()->IsBoundary())
{
// Only copy base uv.
h->SetCornerUV(mesh.GetVertexUV(0U, vertexIndex));
h->SetCornerNormal(mesh.GetVertexNormal(vertexIndex));
}

h = h->GetTwin()->GetNext();
} while (h != vertex.GetHalfEdge());

++vertexIndex;
}
assert(vertexIndex == mesh.GetVertexCount());

return halfEdgeMesh;
}

VertexRef HalfEdgeMesh::EmplaceVertex()
Expand Down
21 changes: 20 additions & 1 deletion private/HalfEdgeMesh/Vertex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,26 @@ Point Vertex::NeighborCenter() const

Direction Vertex::Normal() const
{
return Direction::Zero();
Direction normal(0.0f);

HalfEdgeCRef h = m_halfEdgeRef;
do
{
const Point& v1 = h->GetNext()->GetVertex()->GetPosition();

h = h->GetTwin()->GetNext();

const Point& v2 = h->GetNext()->GetVertex()->GetPosition();

if (!h->GetFace()->IsBoundary())
{
normal += (v1 - m_position).Cross(v2 - m_position);
}

} while (h != m_halfEdgeRef);

normal.Normalize();
return normal;
}

uint32_t Vertex::Degree() const
Expand Down
22 changes: 14 additions & 8 deletions private/Scene/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
namespace cd
{

Mesh Mesh::FromHalfEdgeMesh(const hem::HalfEdgeMesh& halfEdgeMesh, ConvertStrategy strategy)
{
Mesh mesh;
mesh.m_pMeshImpl = new MeshImpl();
mesh.m_pMeshImpl->FromHalfEdgeMesh(halfEdgeMesh, strategy);
return mesh;
}

Mesh::Mesh(InputArchive& inputArchive)
{
m_pMeshImpl = new MeshImpl(inputArchive);
Expand All @@ -18,12 +26,15 @@ Mesh::Mesh(InputArchiveSwapBytes& inputArchive)

Mesh::Mesh(uint32_t vertexCount, uint32_t polygonCount)
{
m_pMeshImpl = new MeshImpl(vertexCount, polygonCount);
m_pMeshImpl = new MeshImpl();
m_pMeshImpl->Init(vertexCount, polygonCount);
}

Mesh::Mesh(MeshID meshID, const char* pMeshName, uint32_t vertexCount, uint32_t polygonCount)
Mesh::Mesh(MeshID id, const char* pName, uint32_t vertexCount, uint32_t polygonCount) :
Mesh(vertexCount, polygonCount)
{
m_pMeshImpl = new MeshImpl(meshID, pMeshName, vertexCount, polygonCount);
m_pMeshImpl->SetID(id);
m_pMeshImpl->SetName(pName);
}

Mesh::Mesh(Mesh&& rhs)
Expand Down Expand Up @@ -51,11 +62,6 @@ void Mesh::Init(uint32_t vertexCount, uint32_t polygonCount)
m_pMeshImpl->Init(vertexCount, polygonCount);
}

void Mesh::Init(MeshID meshID, const char* pMeshName, uint32_t vertexCount, uint32_t polygonCount)
{
m_pMeshImpl->Init(meshID, pMeshName, vertexCount, polygonCount);
}

void Mesh::SetID(MeshID id)
{
m_pMeshImpl->SetID(id);
Expand Down
131 changes: 113 additions & 18 deletions private/Scene/MeshImpl.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,117 @@
#include "MeshImpl.h"

#include <cassert>

namespace cd
{

MeshImpl::MeshImpl(uint32_t vertexCount, uint32_t polygonCount)
void MeshImpl::FromHalfEdgeMesh(const hem::HalfEdgeMesh& halfEdgeMesh, ConvertStrategy strategy)
{
Init(vertexCount, polygonCount);
}
m_vertexUVSetCount = 1U;

MeshImpl::MeshImpl(MeshID meshID, std::string meshName, uint32_t vertexCount, uint32_t polygonCount) :
m_id(meshID),
m_name(MoveTemp(meshName))
{
Init(vertexCount, polygonCount);
if (ConvertStrategy::ShadingFirst == strategy)
{
uint32_t vertexIndex = 0U;
for (const auto& face : halfEdgeMesh.GetFaces())
{
if (face.IsBoundary())
{
continue;
}

uint32_t beginVertexIndex = vertexIndex;
hem::HalfEdgeCRef h = face.GetHalfEdge();
do
{
m_vertexPositions.emplace_back(h->GetVertex()->GetPosition());
m_vertexNormals.emplace_back(h->GetCornerNormal());
m_vertexUVSets[0].emplace_back(h->GetCornerUV());

++vertexIndex;
h = h->GetNext();
} while (h != face.GetHalfEdge());

uint32_t endVertexIndex = vertexIndex;
for (uint32_t cornerIndex = beginVertexIndex + 1; cornerIndex < endVertexIndex - 1; ++cornerIndex)
{
m_polygons.emplace_back(cd::Polygon{beginVertexIndex, cornerIndex, cornerIndex + 1 });
}
}
}
else if (ConvertStrategy::TopologyFirst == strategy)
{
std::unordered_map<hem::VertexCRef, uint32_t> vertexRefToIndex;

const auto& vertices = halfEdgeMesh.GetVertices();
for (hem::VertexCRef vertex = vertices.begin(); vertex != vertices.end(); ++vertex)
{
m_vertexPositions.emplace_back(vertex->GetPosition());

// Fill normal/uv data later by looping through half edges.
m_vertexNormals.emplace_back(0.0f);
m_vertexUVSets[0].emplace_back(0.0f);

auto result = vertexRefToIndex.emplace(vertex, static_cast<uint32_t>(m_vertexPositions.size() - 1));
assert(result.second); // Make sure it is unique.
}

std::vector<uint32_t> cornerCountInVertex;
cornerCountInVertex.resize(vertexRefToIndex.size(), 0U);

for (const auto& face : halfEdgeMesh.GetFaces())
{
if (face.IsBoundary())
{
continue;
}

std::vector<uint32_t> faceIndexes;
hem::HalfEdgeCRef h = face.GetHalfEdge();
do
{
auto itIndex = vertexRefToIndex.find(h->GetVertex());
assert(itIndex != vertexRefToIndex.end());

uint32_t vertexIndex = itIndex->second;
faceIndexes.emplace_back(vertexIndex);

// Add corners' normal/uv data to previously created vertex.
m_vertexNormals[vertexIndex] += h->GetCornerNormal();
m_vertexUVSets[0][vertexIndex] += h->GetCornerUV();
cornerCountInVertex[vertexIndex] += 1U;

h = h->GetNext();
} while (h != face.GetHalfEdge());

assert(faceIndexes.size() >= 3);
for (uint32_t cornerIndex = 1; cornerIndex < faceIndexes.size() - 1; ++cornerIndex)
{
m_polygons.emplace_back(cd::Polygon{faceIndexes[0], faceIndexes[cornerIndex], faceIndexes[cornerIndex + 1]});
}
}

// Average normal/uv data per vertex.
for (uint32_t vertexIndex = 0U; vertexIndex < cornerCountInVertex.size(); ++vertexIndex)
{
uint32_t cornerCount = cornerCountInVertex[vertexIndex];
if (cornerCount > 1U)
{
m_vertexNormals[vertexIndex].Normalize();
m_vertexUVSets[0][vertexIndex] /= static_cast<float>(cornerCount);
}
}
}
else
{
assert("Unsupported convert strategy.");
}

// Make capcity same with actual size.
m_vertexPositions.shrink_to_fit();
m_vertexNormals.shrink_to_fit();
m_vertexUVSets[0].shrink_to_fit();
m_polygons.shrink_to_fit();

m_vertexCount = static_cast<uint32_t>(m_vertexPositions.size());
m_polygonCount = static_cast<uint32_t>(m_polygons.size());
}

void MeshImpl::Init(uint32_t vertexCount, uint32_t polygonCount)
Expand All @@ -25,7 +122,12 @@ void MeshImpl::Init(uint32_t vertexCount, uint32_t polygonCount)
assert(vertexCount > 0 && "No need to create an empty mesh.");
assert(polygonCount > 0 && "Expect to generate index buffer by ourselves?");

// pre-construct for attributes which almost all model files will have.
// TODO : You may get confused why use resize, not reserve.
// The reason is that std::vector doesn't support operator[] access to read/write data if the real size not increases.
// So it will be very convenient for binary stream read/write.
// For example, you already get a byte stream and would like to use it to init Mesh's vertex buffers and index buffer.
// You can't write data directly to std::vector as its size is 0.
// The solution is to write a customized template dynamic array.
m_vertexPositions.resize(vertexCount);
m_vertexNormals.resize(vertexCount);
m_vertexTangents.resize(vertexCount);
Expand All @@ -34,13 +136,6 @@ void MeshImpl::Init(uint32_t vertexCount, uint32_t polygonCount)
m_polygons.resize(polygonCount);
}

void MeshImpl::Init(MeshID meshID, std::string meshName, uint32_t vertexCount, uint32_t polygonCount)
{
m_id = meshID;
m_name = MoveTemp(meshName);
Init(vertexCount, polygonCount);
}

////////////////////////////////////////////////////////////////////////////////////
// Vertex geometry data
////////////////////////////////////////////////////////////////////////////////////
Expand Down
16 changes: 10 additions & 6 deletions private/Scene/MeshImpl.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#pragma once

#include "Base/Template.h"
#include "HalfEdgeMesh/HalfEdgeMesh.h"
#include "IO/InputArchive.hpp"
#include "IO/OutputArchive.hpp"
#include "Math/Box.hpp"
#include "Scene/Morph.h"
#include "Scene/VertexFormat.h"

#include <array>
#include <cassert>
#include <map>
#include <string>
#include <unordered_map>
#include <vector>

namespace cd
Expand All @@ -18,25 +21,24 @@ namespace cd
class MeshImpl final
{
public:
MeshImpl() = delete;
void FromHalfEdgeMesh(const hem::HalfEdgeMesh& halfEdgeMesh, ConvertStrategy strategy);

public:
MeshImpl() = default;

template<bool SwapBytesOrder>
explicit MeshImpl(TInputArchive<SwapBytesOrder>& inputArchive)
{
*this << inputArchive;
}

explicit MeshImpl(uint32_t vertexCount, uint32_t polygonCount);
explicit MeshImpl(MeshID meshID, std::string meshName, uint32_t vertexCount, uint32_t polygonCount);

MeshImpl(const MeshImpl&) = delete;
MeshImpl& operator=(const MeshImpl&) = delete;
MeshImpl(MeshImpl&&) = default;
MeshImpl& operator=(MeshImpl&&) = default;
~MeshImpl() = default;

void Init(uint32_t vertexCount, uint32_t polygonCount);
void Init(MeshID meshID, std::string meshName, uint32_t vertexCount, uint32_t polygonCount);

void SetID(MeshID id) { m_id = id; }
MeshID GetID() const { return m_id; }
Expand Down Expand Up @@ -141,7 +143,9 @@ class MeshImpl final
>> vertexInfluenceCount
>> polygonCount;

Init(MeshID(meshID), MoveTemp(meshName), vertexCount, polygonCount);
SetID(meshID);
SetName(MoveTemp(meshName));
Init(vertexCount, polygonCount);
SetMaterialID(MaterialID(meshMaterialID));
SetVertexUVSetCount(vertexUVSetCount);
SetVertexColorSetCount(vertexColorSetCount);
Expand Down
Loading

0 comments on commit 862175a

Please sign in to comment.