CURAENGINE的Mesh类

发布于:2024-05-07 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、Mesh类

类Mesh代表了一个三维网格(mesh),它是3D图形和建模中常见的数据结构。具体来说,它包含以下主要功能和数据:

class Mesh
{
    //! The vertex_hash_map stores a index reference of each vertex for the hash of that location. Allows for quick retrieval of points with the same location.
    std::unordered_map<uint32_t, std::vector<uint32_t> > vertex_hash_map;
    AABB3D aabb;
public:
    std::vector<MeshVertex> vertices;//!< list of all vertices in the mesh
    std::vector<MeshFace> faces; //!< list of all faces in the mesh
    Settings settings;
    std::string mesh_name;

    Mesh(Settings& parent);
    Mesh();

    void addFace(Point3& v0, Point3& v1, Point3& v2); //!< add a face to the mesh without settings it's connected_faces.
    void clear(); //!< clears all data
    void finish(); //!< complete the model : set the connected_face_index fields of the faces.

    Point3 min() const; //!< min (in x,y and z) vertex of the bounding box
    Point3 max() const; //!< max (in x,y and z) vertex of the bounding box
    AABB3D getAABB() const; //!< Get the axis aligned bounding box
    void expandXY(int64_t offset); //!< Register applied horizontal expansion in the AABB
    
    /*!
     * Offset the whole mesh (all vertices and the bounding box).
     * \param offset The offset byu which to offset the whole mesh.
     */
    void offset(Point3 offset)
    {
        if (offset == Point3(0,0,0)) { return; }
        for(MeshVertex& v : vertices)
            v.p += offset;
        aabb.offset(offset);
    }

private:
    mutable bool has_disconnected_faces; //!< Whether it has been logged that this mesh contains disconnected faces
    mutable bool has_overlapping_faces; //!< Whether it has been logged that this mesh contains overlapping faces
    int findIndexOfVertex(const Point3& v); //!< find index of vertex close to the given point, or create a new vertex and return its index.

    /*!
     * Get the index of the face connected to the face with index \p notFaceIdx, via vertices \p idx0 and \p idx1.
     * 
     * In case multiple faces connect with the same edge, return the next counter-clockwise face when viewing from \p idx1 to \p idx0.
     * 
     * \param idx0 the first vertex index
     * \param idx1 the second vertex index
     * \param notFaceIdx the index of a face which shouldn't be returned
     * \param notFaceVertexIdx should be the third vertex of face \p notFaceIdx.
     * \return the face index of a face sharing the edge from \p idx0 to \p idx1
    */
    int getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVertexIdx) const;
};

顶点(Vertices)和面(Faces)相关成员:

1、vertices:一个包含所有网格顶点的std::vector。每个MeshVertex可能包含位置、颜色、纹理坐标等信息。
2、faces:一个包含所有网格面的std::vector。每个MeshFace可能包含构成该面的顶点索引和可能的其他信息(如法线、纹理坐标索引等)。
3、设置(Settings):
settings:一个Settings对象,包含与网格相关的各种设置或属性。
网格名称(Mesh Name):
4、mesh_name:一个字符串,用于标识或命名这个特定的网格。

顶点(Vertices)和面(Faces)相关成员方法:

1、添加面(Add Face):
addFace方法允许你添加一个新的面到网格中,给定三个顶点的位置。
2、清除数据(Clear):
clear方法会清除所有的顶点和面数据。
3、完成模型(Finish):
finish方法用于设置面之间的连接关系或进行其他后处理步骤的。
4、边界框(Bounding Box):
aabb:一个AABB3D对象,表示网格的轴对齐边界框(Axis-Aligned Bounding Box)。它有助于快速确定哪些对象可能与给定位置相交,常用于碰撞检测或视锥体裁剪。
5、方法
min和max方法分别返回边界框的最小和最大顶点。
getAABB方法返回边界框对象本身。
expandXY方法允许你在X和Y方向上扩展边界框。
偏移(Offset):
offset方法允许你移动整个网格(包括其所有顶点和边界框)给定的偏移量。
错误状态(Error States):
has_disconnected_faceshas_overlapping_faces是两个布尔值,用于跟踪网格是否包含未连接的面或重叠的面。这可能是为了在后续处理中报告或处理这些问题。

二、Mesh::addFace函数

void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
{
    int vi0 = findIndexOfVertex(v0);
    int vi1 = findIndexOfVertex(v1);
    int vi2 = findIndexOfVertex(v2);
    if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face.

    int idx = faces.size(); // index of face to be added
    faces.emplace_back();
    MeshFace& face = faces[idx];
    face.vertex_index[0] = vi0;
    face.vertex_index[1] = vi1;
    face.vertex_index[2] = vi2;
    vertices[face.vertex_index[0]].connected_faces.push_back(idx);
    vertices[face.vertex_index[1]].connected_faces.push_back(idx);
    vertices[face.vertex_index[2]].connected_faces.push_back(idx);
}

这个函数Mesh::addFace是Mesh类中的一个方法,用于向网格中添加一个新的面。下面我将详细解释这个函数的工作原理:

参数
Point3& v0, Point3& v1, Point3& v2:这三个参数是三个Point3类型的引用,分别表示新面的三个顶点的位置。

step 1、查找顶点索引:

findIndexOfVertex(v0), findIndexOfVertex(v1), findIndexOfVertex(v2):这三个调用是假设Mesh类中存在一个未在此代码段中定义的findIndexOfVertex方法,用于查找给定顶点在vertices向量中的索引。如果顶点已经存在,则返回其索引;如果不存在,可能会添加顶点并返回新索引(但此函数的具体实现并未给出)。

step 2、检查顶点是否重复:

如果新面的三个顶点中有任何两个顶点索引相同(即它们指向相同的顶点位置),则不添加该面,并直接返回。这是为了避免在网格中创建具有重复顶点的面。
添加新面:
int idx = faces.size();:获取当前faces向量的大小,即新面将被添加的索引。
faces.emplace_back();:在faces向量的末尾使用emplace_back方法构造一个新面(假设MeshFace有一个接受默认参数的构造函数)。
MeshFace& face = faces[idx];:通过索引获取新添加的面的引用,以便后续操作。

step 3、设置面的顶点索引:

使用face.vertex_index[0], face.vertex_index[1], face.vertex_index[2]为新面的三个顶点设置索引。这些索引指向vertices向量中的顶点。
更新顶点的连接面列表:
每个顶点都有一个connected_faces列表用于存储与该顶点相连的所有面的索引。对于新添加的面的每个顶点,都将该面的索引添加到其connected_faces列表中。这样,后续可以通过遍历顶点的connected_faces列表来找到所有与该顶点相连的面。
总之,Mesh::addFace函数的主要目的是将一个新面添加到网格中,并确保顶点的连接面列表得到正确更新。

三、Mesh::findIndexOfVertex函数

int Mesh::findIndexOfVertex(const Point3& v)
{
    uint32_t hash = pointHash(v);

    for(unsigned int idx = 0; idx < vertex_hash_map[hash].size(); idx++)
    {
        if ((vertices[vertex_hash_map[hash][idx]].p - v).testLength(vertex_meld_distance))
        {
            return vertex_hash_map[hash][idx];
        }
    }
    vertex_hash_map[hash].push_back(vertices.size());
    vertices.emplace_back(v);
    
    aabb.include(v);
    
    return vertices.size() - 1;
}

这个函数 Mesh::findIndexOfVertex 用于在 Mesh 类中查找给定顶点 v 的索引,如果顶点不存在,则将其添加到 vertices 向量中并返回新索引。以下是该函数的详细解释:

参数:
const Point3& v:这是一个常量引用,指向要查找或添加的 Point3 类型的顶点。
计算顶点哈希值:
uint32_t hash = pointHash(v);:使用 pointHash 函数(该函数未在提供的代码段中定义)计算顶点 v 的哈希值。这个哈希值用于在 vertex_hash_map 中快速查找顶点。
在哈希映射中查找顶点:
遍历 vertex_hash_map[hash] 容器,这是一个包含具有相同哈希值的所有顶点索引的 std::vector<uint32_t>
对于容器中的每个索引,使用 vertices[index].p 访问相应的顶点,并检查它与给定顶点 v 是否在 vertex_meld_distance 范围内(这里 testLength 是一个方法,用于比较两点之间的距离是否小于或等于 vertex_meld_distance)。
如果找到匹配的顶点,则返回该顶点的索引。

添加新顶点:

如果在哈希映射中没有找到匹配的顶点,则将当前 vertices 向量的大小(即新顶点的索引)添加到 vertex_hash_map[hash] 中。
使用 vertices.emplace_back(v) 将新顶点 v 添加到 vertices 向量的末尾。

更新边界框:

aabb.include(v);:调用 AABB3D 对象的 include 方法(假设该方法存在)以将新顶点 v 包含到网格的轴对齐边界框(AABB)中。
返回新索引:
返回新添加的顶点在 vertices 向量中的索引,即 vertices.size() - 1。

注意:

vertex_meld_distance 是一个成员变量或常量,用于确定两个顶点是否“距离足够短”以至于可以被认为是相同的。这通常用于网格优化,例如顶点合并或焊接。
testLength 方法是 Point3 类的一个成员函数,用于比较两个点之间的距离是否小于或等于给定的阈值。
vertex_hash_map 是一个哈希映射,用于通过哈希值快速查找顶点索引,从而提高查找效率。如果两个顶点具有相同的哈希值但实际上是不同的(哈希冲突),则通过比较顶点位置来解决冲突。
AABB3D 是另一个类,用于表示和操作轴对齐边界框。include 方法用于更新边界框以包含新的顶点。

总结