将 QMatrix4x4 与 OpenGL 函数一起使用

Posted

技术标签:

【中文标题】将 QMatrix4x4 与 OpenGL 函数一起使用【英文标题】:Use QMatrix4x4 with OpenGL functions 【发布时间】:2013-01-13 11:48:52 【问题描述】:

有没有一种简单的方法可以将QMatrix4x4 与OpenGL 函数一起使用,特别是glMultMatrixf

如果我理解正确,我必须转置矩阵,并确保将qreal(可以是floatdouble,具体取决于底层系统)转换为GLfloat。 难道没有一个函数可以为我做这件事吗?

QVector3D 也有同样的问题,我需要在函数 glVertex3fv 中作为 GLfloat 数组。

【问题讨论】:

【参考方案1】:

首先我想提一下QMatrix4x4 具有用于矩阵乘法的内置运算符(带有第二个矩阵、向量或标量)。但是,您的问题仍然需要答案,因为您迟早要将矩阵传递给 OpenGL。

QMatrix4x4 使用 qreals 进行内部表示。虽然该类旨在直接与 OpenGL 一起使用(使用 Bart 在他的回答中建议的 constData()),但如果您想保持平台兼容性,您可以确保根据类型将其传递给相应的 OpenGL 函数(在嵌入式设备上,qrealfloat!):

// these are defined in the OpenGL headers:
void glMultMatrixf(const GLfloat *m);
void glMultMatrixd(const GLdouble *m);

// add overloaded functions which call the underlying OpenGL function
inline void glMultMatrix(const GLfloat  *m)  glMultMatrixf(m); 
inline void glMultMatrix(const GLdouble *m)  glMultMatrixd(m); 

// add an overload for QMatrix4x4 for convenience
inline void glMultMatrix(const QMatrix4x4 &m)  glMultMatrix(m.constData()); 

您也可以将这种机制用于向量,这里是 glVertex* 系列,由于“原始指针”重载需要考虑的组件数量,它更有意义,但面向对象的重载可以自动执行你:

inline void glVertex2v(const GLfloat  *v)  glVertex2fv(v); 
inline void glVertex2v(const GLdouble *v)  glVertex2dv(v); 
inline void glVertex3v(const GLfloat  *v)  glVertex3fv(v); 
inline void glVertex3v(const GLdouble *v)  glVertex3dv(v); 
inline void glVertex4v(const GLfloat  *v)  glVertex4fv(v); 
inline void glVertex4v(const GLdouble *v)  glVertex4dv(v); 

// Note that QVectorND use floats, but we check this during compile time...
Q_STATIC_ASSERT(sizeof(QVector2D) == 2*sizeof(float));
Q_STATIC_ASSERT(sizeof(QVector3D) == 3*sizeof(float));
Q_STATIC_ASSERT(sizeof(QVector4D) == 4*sizeof(float));
inline void glVertex(const QVector2D &v)  glVertex2v(reinterpret_cast<const float*>(&v)); 
inline void glVertex(const QVector3D &v)  glVertex3v(reinterpret_cast<const float*>(&v)); 
inline void glVertex(const QVector4D &v)  glVertex4v(reinterpret_cast<const float*>(&v)); 

// Even for QPointF we can do it!
Q_STATIC_ASSERT(sizeof(QPointF) == 2*sizeof(qreal));
inline void glVertex(const QPointF &v)  glVertex4v(reinterpret_cast<const qreal*>(&v)); 

因此,如果进行以下更改,您的代码将保持有效:

Qt 将QVector* / QMatrix 的表示更改为分别使用浮点数/双精度数, 您的代码更改了向量的分量数

...当使用像glVertex3f这样的原始OpenGL命令时,尤其是第二个不是这种情况。

上面代码中的Q_STATIC_ASSERTions 仅在 Qt 5.0 之后定义。如果您使用的是 Qt4(或与 Qt4 兼容的代码),请将其添加到一些全局头文件 / 在您的定义之前:http://ideone.com/VDPUSg [来源:Qt5 / qglobal.h]

【讨论】:

谢谢你,正是我所需要的(虽然我更喜欢 Qt 提供的答案) @Misch 好吧,有这个QGLFunctions mixin,所以如果你从这个 mixin 继承,你可以默默地使用 Qt 的 OpenGL 函数包装器。然而,他们并没有那么聪明地引入重载。也许有一个很好的理由——但我看不到。【参考方案2】:

qreal 在所有平台上都定义为双精度,ARM 架构除外。所以对你来说他们很可能是双打。

也就是说,是的,您可以使用 constData() 方法在 OpenGL 中完美使用 QMatrix4x4。当然,对于双精度类型,您要么必须使用glMultMatrixd,要么从中创建一个浮点矩阵。这可能不是您想要做的。 Qt 有各种示例在他们的 OpenGL 演示中使用矩阵类型。

我个人从不在我的 OpenGL 代码中使用 Qt 的矩阵和向量类型(尽管我广泛使用 Qt),而是选择像 Eigen、GLM 或其他合适的库。

【讨论】:

你确定constData() 给了我我想要的吗?我不需要转置矩阵才能在 OpenGL 中使用它吗? @Misch 根据代码文档,数据经过专门布局,以便最适合传递给 OpenGL 函数。所以不,你不必担心。 我在 Qt 文档中无法确定这一点,但我认为 constData 以行主要方式返回其数据。 (我发现的唯一一件事是:“数组值的内容假定为行优先顺序。”在QGenericMatrix 的构造函数中)。然而 OpenGL 使用列主矩阵 @Misch Nah,其实不然。 OpenGL 想要一个连续的数据数组,其中平移值作为第 13 到第 15 个值。这正是 constData 会给你的。 Row-major vs colum-major 是这种 OpenGL 的大混淆,它并不是真正需要的。请参阅有关此问题的 OpenGL 常见问题解答:opengl.org/archives/resources/faq/technical/transformations.htm您是否遇到任何特殊问题? @Misch Qt 文档在这方面确实令人困惑。但在内部,数据具有符合 OpenGL 的布局。有专门关于文档的错误报告,所以只能希望在某个时候得到澄清。

以上是关于将 QMatrix4x4 与 OpenGL 函数一起使用的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL-载入纹理

OpenGL的视图变换与OSG漫游器

第一个OpenGL程序

OpenGL ES之实例化渲染(Instancing)

OpenGL基础篇——使用面向对象方法封装OpenGL函数

OpenGL及GLUT---------------函数整理