将 QMatrix4x4 与 OpenGL 函数一起使用
Posted
技术标签:
【中文标题】将 QMatrix4x4 与 OpenGL 函数一起使用【英文标题】:Use QMatrix4x4 with OpenGL functions 【发布时间】:2013-01-13 11:48:52 【问题描述】:有没有一种简单的方法可以将QMatrix4x4
与OpenGL 函数一起使用,特别是glMultMatrixf
?
如果我理解正确,我必须转置矩阵,并确保将qreal
(可以是float
或double
,具体取决于底层系统)转换为GLfloat
。
难道没有一个函数可以为我做这件事吗?
QVector3D
也有同样的问题,我需要在函数 glVertex3fv
中作为 GLfloat
数组。
【问题讨论】:
【参考方案1】:首先我想提一下QMatrix4x4
具有用于矩阵乘法的内置运算符(带有第二个矩阵、向量或标量)。但是,您的问题仍然需要答案,因为您迟早要将矩阵传递给 OpenGL。
QMatrix4x4
使用 qreals
进行内部表示。虽然该类旨在直接与 OpenGL 一起使用(使用 Bart 在他的回答中建议的 constData()
),但如果您想保持平台兼容性,您可以确保根据类型将其传递给相应的 OpenGL 函数(在嵌入式设备上,qreal
是 float
!):
// 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_ASSERT
ions 仅在 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 函数一起使用的主要内容,如果未能解决你的问题,请参考以下文章