我在一个计算机图形项目中使用Eigen库,其网格会经常变化。
对所有顶点位置、法线等使用动态特征矩阵对性能有何影响?
我应该使用:
Eigen::Matrix<float, Eigen::Dynamic, 3, Eigen::RowMajor> vertices;
或者
std::vector<Eigen::Vector3f> vertices;
每次更改后,我都必须将网格数据复制到 GPU,但据我了解,我可以使用 memcpy 有效地使用两种表示形式进行此操作。
Vector 可能会消耗更多内存,因为它通常分配的空间比存储数据所需的空间多,并且Eigen::Vector3f
每次调整它的大小时,vector 都会调用默认构造函数和析构函数。AFAIK,默认Eigen::Vector3f
构造函数是空的,因此在发布构建中花费为零(但由于这个和调试迭代器,您可能会在调试构建中遇到性能问题)。另一方面,Eigen::Matrix
每次调整大小时都会重新分配内存(它也会复制内容,就像std::vector
你使用conservativeResize一样),这很慢。
但是,我还是推荐你使用vector,因为它更方便。您可以动态添加元素,无需重新分配即可调整其大小,在矢量上使用标准算法更简单。如果你想确定你的向量不会消耗比需要更多的内存,你可以使用这个技巧来调整它的大小:
std::vector<Eigen::Vector3f> vertices;
vertices.swap( std::vector<Eigen::Vector3f>(size, Eigen::Vector3f()) );
是的,您可以使用 memcpy 使用这两种表示有效地复制数据。但是 usingstd::copy
将在发布版本中以相同的性能完成相同的工作(有时它甚至被编译器替换为memcpy
)。
但是,如果您仍然对性能不满意,以下是我为自己制定的在这种情况下做出决定的提示:
std::vector
避免频繁的重新分配。Eigen::Matrix
避免过多的内存消耗。Eigen::Matrix
,stl
调试迭代器可能会破坏性能(仅适用于 MSVC)还可以考虑boost::shared_array (scoped_array),它们是专门为存储大块数据而不消耗额外内存而设计的。在您的场景中使用它们更有意义。
动态分配的矩阵数组通常存在两个问题:
您将无法使用全局memcpy
来复制整个结构:在动态分配矩阵的情况下(例如,您有 anstd::vector<float*>
而不是 an std::vector<Eigen::Vector3f>
),您的数组仅包含一系列指针,并且所有这些指针都可以指向到内存中非常不同的位置。因此,执行 amemcpy
只会复制指针,而不是数据,并且无法更改它,因为您的元素在内存中不是连续的(只有它们的指针是)。相反,您需要遍历 的每个元素,分别使用和元素std::vector
访问它。例如,在执行 your 时,您将拥有(或类似的东西:它存储一个指针和许多行和列),而operator[]
memcpy
memcpy
sizeof(Eigen::Matrix<float, Eigen::Dynamic, 3, Eigen::RowMajor>) = sizeof(void*) + 2*sizeof(int)
sizeof(Eigen::Vector3f) = 3*sizeof(float)
因为它真正存储数据而不是指针。
如果您需要频繁地创建和销毁矩阵,则使用动态分配的矩阵执行此操作会慢得多。具有固定大小的矩阵允许在堆栈上进行分配,这使其更快。
两种表示的内存布局完全相同。主要区别在于,如果您需要插入向量或类似的东西, std::vector<> 会更加灵活。另一方面 Matrix<.,3,Dynamic> 是一个 Eigen 对象,因此更容易对其执行一些操作,例如:
Matrix<.,3,Dynamic> data;
data = Affine3f(...) * data; // apply an affine transformation
data.colwise().norm(); // get the norm of each vectors
...