From c580ef002c00edaf197850bd343204427bd4dc13 Mon Sep 17 00:00:00 2001 From: Jonathan Young Date: Sat, 25 Jul 2020 20:56:05 +1000 Subject: [PATCH] Optional per-face material. If set, only faces with the same material will be assigned to the same chart. --- extra/viewer_atlas.cpp | 11 +++++++++++ xatlas.cpp | 27 +++++++++++++++++++++------ xatlas.h | 6 +++++- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/extra/viewer_atlas.cpp b/extra/viewer_atlas.cpp index 18e3cc5..be868e7 100644 --- a/extra/viewer_atlas.cpp +++ b/extra/viewer_atlas.cpp @@ -63,6 +63,8 @@ SOFTWARE. #include "shaders/shared.h" #include "viewer.h" +#define USE_MESH_DECL_FACE_MATERIAL 0 + namespace std { typedef std::lock_guard mutex_lock; } namespace bgfx @@ -465,6 +467,15 @@ static void atlasGenerateThread() meshDecl.indexFormat = xatlas::IndexFormat::UInt32; meshDecl.indexOffset = -(int32_t)object.firstVertex; meshDecl.faceIgnoreData = (const bool *)ignoreFaces.data(); +#if USE_MESH_DECL_FACE_MATERIAL + faceMaterials.resize(object.numIndices / 3); + for (uint32_t j = 0; j < object.numMeshes; j++) { + const objzMesh &mesh = model->meshes[object.firstMesh + j]; + for (uint32_t k = 0; k < mesh.numIndices / 3; k++) + faceMaterials[(mesh.firstIndex - object.firstIndex) / 3 + k] = (uint32_t)mesh.materialIndex; + } + meshDecl.faceMaterialData = faceMaterials.data(); +#endif error = xatlas::AddMesh(s_atlas.data, meshDecl, model->numObjects); } if (error != xatlas::AddMeshError::Success) { diff --git a/xatlas.cpp b/xatlas.cpp index 6726eff..19e4ef4 100644 --- a/xatlas.cpp +++ b/xatlas.cpp @@ -2395,14 +2395,15 @@ struct MeshFlags enum { HasIgnoredFaces = 1<<0, - HasNormals = 1<<1 + HasNormals = 1<<1, + HasMaterials = 1<<2 }; }; class Mesh { public: - Mesh(float epsilon, uint32_t approxVertexCount, uint32_t approxFaceCount, uint32_t flags = 0, uint32_t id = UINT32_MAX) : m_epsilon(epsilon), m_flags(flags), m_id(id), m_faceIgnore(MemTag::Mesh), m_indices(MemTag::MeshIndices), m_positions(MemTag::MeshPositions), m_normals(MemTag::MeshNormals), m_texcoords(MemTag::MeshTexcoords), m_nextColocalVertex(MemTag::MeshColocals), m_firstColocalVertex(MemTag::MeshColocals), m_boundaryEdges(MemTag::MeshBoundaries), m_oppositeEdges(MemTag::MeshBoundaries), m_edgeMap(MemTag::MeshEdgeMap, approxFaceCount * 3) + Mesh(float epsilon, uint32_t approxVertexCount, uint32_t approxFaceCount, uint32_t flags = 0, uint32_t id = UINT32_MAX) : m_epsilon(epsilon), m_flags(flags), m_id(id), m_faceIgnore(MemTag::Mesh), m_faceMaterials(MemTag::Mesh), m_indices(MemTag::MeshIndices), m_positions(MemTag::MeshPositions), m_normals(MemTag::MeshNormals), m_texcoords(MemTag::MeshTexcoords), m_nextColocalVertex(MemTag::MeshColocals), m_firstColocalVertex(MemTag::MeshColocals), m_boundaryEdges(MemTag::MeshBoundaries), m_oppositeEdges(MemTag::MeshBoundaries), m_edgeMap(MemTag::MeshEdgeMap, approxFaceCount * 3) { m_indices.reserve(approxFaceCount * 3); m_positions.reserve(approxVertexCount); @@ -2411,6 +2412,8 @@ class Mesh m_faceIgnore.reserve(approxFaceCount); if (m_flags & MeshFlags::HasNormals) m_normals.reserve(approxVertexCount); + if (m_flags & MeshFlags::HasMaterials) + m_faceMaterials.reserve(approxFaceCount); } uint32_t flags() const { return m_flags; } @@ -2425,19 +2428,21 @@ class Mesh m_texcoords.push_back(texcoord); } - void addFace(uint32_t v0, uint32_t v1, uint32_t v2, bool ignore = false) + void addFace(uint32_t v0, uint32_t v1, uint32_t v2, bool ignore = false, uint32_t material = UINT32_MAX) { uint32_t indexArray[3]; indexArray[0] = v0; indexArray[1] = v1; indexArray[2] = v2; - return addFace(indexArray, ignore); + return addFace(indexArray, ignore, material); } - void addFace(const uint32_t *indices, bool ignore = false) + void addFace(const uint32_t *indices, bool ignore = false, uint32_t material = UINT32_MAX) { if (m_flags & MeshFlags::HasIgnoredFaces) m_faceIgnore.push_back(ignore); + if (m_flags & MeshFlags::HasMaterials) + m_faceMaterials.push_back(material); const uint32_t firstIndex = m_indices.size(); for (uint32_t i = 0; i < 3; i++) m_indices.push_back(indices[i]); @@ -2785,6 +2790,7 @@ class Mesh XA_INLINE const uint32_t *indices() const { return m_indices.data(); } XA_INLINE uint32_t indexCount() const { return m_indices.size(); } XA_INLINE bool isFaceIgnored(uint32_t face) const { return (m_flags & MeshFlags::HasIgnoredFaces) && m_faceIgnore[face]; } + XA_INLINE uint32_t faceMaterial(uint32_t face) const { return (m_flags & MeshFlags::HasMaterials) ? m_faceMaterials[face] : UINT32_MAX; } XA_INLINE const HashMap &edgeMap() const { return m_edgeMap; } private: @@ -2793,6 +2799,7 @@ class Mesh uint32_t m_flags; uint32_t m_id; Array m_faceIgnore; + Array m_faceMaterials; Array m_indices; Array m_positions; Array m_normals; @@ -2908,6 +2915,7 @@ struct MeshFaceGroups break; const uint32_t f = growFaces.back(); growFaces.pop_back(); + const uint32_t material = m_mesh->faceMaterial(f); for (Mesh::FaceEdgeIterator edgeIt(m_mesh, f); !edgeIt.isDone(); edgeIt.advance()) { const uint32_t oppositeEdge = m_mesh->findEdge(edgeIt.vertex1(), edgeIt.vertex0()); if (oppositeEdge == UINT32_MAX) @@ -2915,6 +2923,8 @@ struct MeshFaceGroups const uint32_t oppositeFace = meshEdgeFace(oppositeEdge); if (m_mesh->isFaceIgnored(oppositeFace)) continue; // Don't add ignored faces to group. + if (m_mesh->faceMaterial(oppositeFace) != material) + continue; // Different material. if (m_groups[oppositeFace] != kInvalid) continue; // Connected face is already assigned to another group. m_groups[oppositeFace] = group; @@ -8981,6 +8991,8 @@ AddMeshError::Enum AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t mesh uint32_t meshFlags = internal::MeshFlags::HasIgnoredFaces; if (meshDecl.vertexNormalData) meshFlags |= internal::MeshFlags::HasNormals; + if (meshDecl.faceMaterialData) + meshFlags |= internal::MeshFlags::HasMaterials; internal::Mesh *mesh = XA_NEW_ARGS(internal::MemTag::Mesh, internal::Mesh, meshDecl.epsilon, meshDecl.vertexCount, indexCount / 3, meshFlags, ctx->meshes.size()); for (uint32_t i = 0; i < meshDecl.vertexCount; i++) { internal::Vector3 normal(0.0f); @@ -9073,7 +9085,10 @@ AddMeshError::Enum AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t mesh } if (meshDecl.faceIgnoreData && meshDecl.faceIgnoreData[i]) ignore = true; - mesh->addFace(tri[0], tri[1], tri[2], ignore); + uint32_t material = UINT32_MAX; + if (meshDecl.faceMaterialData) + material = meshDecl.faceMaterialData[i]; + mesh->addFace(tri[0], tri[1], tri[2], ignore, material); } if (warningCount > kMaxWarnings) XA_PRINT(" %u additional warnings truncated\n", warningCount - kMaxWarnings); diff --git a/xatlas.h b/xatlas.h index 18fb1d1..9c46391 100644 --- a/xatlas.h +++ b/xatlas.h @@ -118,10 +118,14 @@ struct MeshDecl const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator. const void *indexData = nullptr; // optional - // Optional. indexCount / 3 (triangle count) in length. + // Optional. Must be indexCount / 3 in length. // Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1. const bool *faceIgnoreData = nullptr; + // Optional. Must be indexCount / 3 in length. + // Only faces with the same material will be assigned to the same chart. + const uint32_t *faceMaterialData = nullptr; + uint32_t vertexCount = 0; uint32_t vertexPositionStride = 0; uint32_t vertexNormalStride = 0; // optional