【问题标题】:Mesh using Eigen: MatrixX3f or std::vector<Vector3f>?使用 Eigen 的网格:MatrixX3f 还是 std::vector<Vector3f>?
【发布时间】:2012-11-23 05:02:04
【问题描述】:

我在一个计算机图形项目中使用Eigen 库,其网格会经常变化。

对所有顶点位置、法线等使用动态特征矩阵对性能有何影响?

我应该使用:

Eigen::Matrix<float, Eigen::Dynamic, 3, Eigen::RowMajor> vertices;

std::vector<Eigen::Vector3f> vertices;

每次更改后我都必须将网格数据复制到 GPU,但据我了解,我可以使用 memcpy 高效地使用两种表示形式来完成此操作。

【问题讨论】:

    标签: c++ graphics gpu eigen


    【解决方案1】:

    Vector 可能会消耗更多内存,因为它分配的空间通常比存储数据所需的空间多,并且每次调整其大小时,vector 都会为 Eigen::Vector3f 调用默认构造函数和析构函数。 AFAIK,默认 Eigen::Vector3f 构造函数为空,因此在发布构建中花费为零(但由于此和调试迭代​​器,您可能会在调试构建中遇到性能问题)。另一方面,Eigen::Matrix 每次调整大小时都会重新分配内存(如果你使用conservativeResize,它也会像std::vector 一样复制内容),这很慢。

    不过,我还是推荐你使用vector,因为它更方便。您可以动态添加元素,调整其大小而无需重新分配,在矢量上使用标准算法更简单。如果你想确定你的向量不会消耗比需要更多的内存,你可以使用这个技巧来调整它:

    std::vector<Eigen::Vector3f> vertices;
    vertices.swap( std::vector<Eigen::Vector3f>(size, Eigen::Vector3f()) );
    

    或查看shrink_to_fit

    是的,您可以使用 memcpy 来有效地复制数据,同时使用这两种表示。但是使用std::copy 将在发布版本中以相同的性能完成相同的工作(有时它甚至被编译器替换为memcpy)。

    但是,如果您仍然对性能不满意,以下是我为自己制定的在这种情况下做出决定的提示:

    • 如果您要频繁调整顶点数组的大小(添加或删除元素)-> 使用 std::vector 以避免频繁的重新分配。
    • 如果您在顶点数组中存储大量数据 -> 使用 Eigen::Matrix 以避免过多的内存消耗。
    • 如果您对调试模式下的性能不满意(如果您经常处理顶点数组中的数据,这将是幸运的)-> 使用Eigen::Matrixstl 调试迭代器可能会破坏性能(仅适用于MSVC)

    还可以考虑boost::shared_array(scoped_array),它们专门设计用于存储大块数据而不消耗额外内存。在您的场景中使用它们更有意义。

    【讨论】:

    • 这个答案包含很好的提示;不幸的是,我只能接受一个答案。
    【解决方案2】:

    两种表示的内存布局完全相同。主要区别在于,如果您需要插入向量或类似的东西, std::vector 会更加灵活。另一方面 Matrix<.> 是一个 Eigen 对象,因此对其执行一些操作更容易,例如:

    Matrix<.,3,Dynamic> data;
    data = Affine3f(...) * data; // apply an affine transformation
    data.colwise().norm(); // get the norm of each vectors
    ...
    

    【讨论】:

      【解决方案3】:

      动态分配的矩阵数组通常有两个问题:

      • 您将无法使用全局 memcpy 复制整个结构:对于动态分配的矩阵(例如,您有一个 std::vector&lt;float*&gt; 而不是 std::vector&lt;Eigen::Vector3f&gt;),您的数组仅包含一系列指针,并且所有这些指针都可以指向内存中非常不同的位置。因此,执行memcpy 只会复制指针,而不是数据,并且无法更改它,因为您的元素在内存中不是连续的(只有它们的指针是)。相反,您需要遍历std::vector 的每个元素,分别使用operator[]memcpy 元素访问它。例如,在执行memcpy 时,您将拥有sizeof(Eigen::Matrix&lt;float, Eigen::Dynamic, 3, Eigen::RowMajor&gt;) = sizeof(void*) + 2*sizeof(int)(或类似的东西:它存储一个指针以及许多行和列),而sizeof(Eigen::Vector3f) = 3*sizeof(float) 因为它真正存储的是数据而不是指针。

      • 如果您需要频繁地创建和销毁矩阵,使用动态分配的矩阵执行此操作会慢得多。具有固定大小的矩阵允许在堆栈上进行分配,这使其更快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-06
        • 1970-01-01
        • 2022-01-22
        • 2019-07-08
        • 2012-03-07
        • 1970-01-01
        • 2017-12-23
        相关资源
        最近更新 更多