Hello GLES3 示例
通过 QOpenGLExtraFunctions 展示 OpenGL ES 3.0 功能。
概览
此示例通过在 QOpenGLExtraFunctions 中使用 OpenGL ES 3.0 功能,演示了桌面平台上的 OpenGL 3.3 和移动/嵌入式设备上的一致性使用。
此示例没有 QWidget 依赖项,它使用 QOpenGLWindow,这是 QWindow 的一个方便子类,它可以轻松实现包含 OpenGL 渲染内容的窗口。在这方面,它补充了 OpenGL 窗口示例,该示例显示了不使用方便子类实现的基于 OpenGL 的 QWindow。
Qt 标志形状实现来自 Hello GL2 示例。
关于使用 OpenGL 的其他方面,有以下区别。
- OpenGL 上下文创建必须有一个足够的版本号,以支持使用中的功能。
- 着色器版本指令不同。
在 main.cpp 中设置
我们实例化我们的 QGuiApplication,QSurfaceformat 并设置其 深度缓冲区大小
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QSurfaceFormat fmt; fmt.setDepthBufferSize(24);
我们请求一个 OpenGL 3.3 核心或 OpenGL ES 3.0 上下文,取决于 QOpenGLContext::openGLModuleType()
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { qDebug("Requesting 3.3 core context"); fmt.setVersion(3, 3); fmt.setProfile(QSurfaceFormat::CoreProfile); } else { qDebug("Requesting 3.0 context"); fmt.setVersion(3, 0); } QSurfaceFormat::setDefaultFormat(fmt);
我们设置默认表面格式并实例化我们的 GLWindow glWindow
。
实现 GLWindow
此类提供了示例应用程序的功能。
首先,通过实现一个 QOpenGLWindow 子类来声明 GLWindow
class GLWindow : public QOpenGLWindow
以下属性使用 Q_PROPERTY 声明
{ Q_OBJECT Q_PROPERTY(float z READ z WRITE setZ) Q_PROPERTY(float r READ r WRITE setR) Q_PROPERTY(float r2 READ r2 WRITE setR2)
以下公共函数声明
public: GLWindow(); ~GLWindow(); void initializeGL(); void resizeGL(int w, int h); void paintGL(); float z() const { return m_eye.z(); } void setZ(float v); float r() const { return m_r; } void setR(float v); float r2() const { return m_r2; } void setR2(float v);
以下私有对象声明
private slots: void startSecondStage(); private: QOpenGLTexture *m_texture = nullptr; QOpenGLShaderProgram *m_program = nullptr; QOpenGLBuffer *m_vbo = nullptr; QOpenGLVertexArrayObject *m_vao = nullptr; Logo m_logo; int m_projMatrixLoc = 0; int m_camMatrixLoc = 0; int m_worldMatrixLoc = 0; int m_myMatrixLoc = 0; int m_lightPosLoc = 0; QMatrix4x4 m_proj; QMatrix4x4 m_world; QVector3D m_eye;
在实现方面,那些声明为内联的函数在 glwindow.cpp
中实现(或重新实现)。以下选择将涵盖使用 OpenGL ES 3.0 的实现细节。
动画
以下代码涉及动画,此处不进行探讨
GLWindow::GLWindow() { m_world.setToIdentity(); m_world.translate(0, 0, -1); m_world.rotate(180, 1, 0, 0); QSequentialAnimationGroup *animGroup = new QSequentialAnimationGroup(this); animGroup->setLoopCount(-1); QPropertyAnimation *zAnim0 = new QPropertyAnimation(this, QByteArrayLiteral("z")); zAnim0->setStartValue(1.5f); zAnim0->setEndValue(10.0f); zAnim0->setDuration(2000); animGroup->addAnimation(zAnim0); QPropertyAnimation *zAnim1 = new QPropertyAnimation(this, QByteArrayLiteral("z")); zAnim1->setStartValue(10.0f); zAnim1->setEndValue(50.0f); zAnim1->setDuration(4000); zAnim1->setEasingCurve(QEasingCurve::OutElastic); animGroup->addAnimation(zAnim1); QPropertyAnimation *zAnim2 = new QPropertyAnimation(this, QByteArrayLiteral("z")); zAnim2->setStartValue(50.0f); zAnim2->setEndValue(1.5f); zAnim2->setDuration(2000); animGroup->addAnimation(zAnim2); animGroup->start(); QPropertyAnimation* rAnim = new QPropertyAnimation(this, QByteArrayLiteral("r")); rAnim->setStartValue(0.0f); rAnim->setEndValue(360.0f); rAnim->setDuration(2000); rAnim->setLoopCount(-1); rAnim->start(); QTimer::singleShot(4000, this, &GLWindow::startSecondStage); } GLWindow::~GLWindow() { makeCurrent(); delete m_texture; delete m_program; delete m_vbo; delete m_vao; } void GLWindow::startSecondStage() { QPropertyAnimation* r2Anim = new QPropertyAnimation(this, QByteArrayLiteral("r2")); r2Anim->setStartValue(0.0f); r2Anim->setEndValue(360.0f); r2Anim->setDuration(20000); r2Anim->setLoopCount(-1); r2Anim->start(); } void GLWindow::setZ(float v) { m_eye.setZ(v); m_uniformsDirty = true; update(); } void GLWindow::setR(float v) { m_r = v; m_uniformsDirty = true; update(); } void GLWindow::setR2(float v) { m_r2 = v; m_uniformsDirty = true; update(); }
有关更多信息,请参阅 QPropertyAnimation、QSequentialAnimationGroup 的文档。
着色器
着色器定义如下
static const char *vertexShaderSource = "layout(location = 0) in vec4 vertex;\n" "layout(location = 1) in vec3 normal;\n" "out vec3 vert;\n" "out vec3 vertNormal;\n" "out vec3 color;\n" "uniform mat4 projMatrix;\n" "uniform mat4 camMatrix;\n" "uniform mat4 worldMatrix;\n" "uniform mat4 myMatrix;\n" "uniform sampler2D sampler;\n" "void main() {\n" " ivec2 pos = ivec2(gl_InstanceID % 32, gl_InstanceID / 32);\n" " vec2 t = vec2(float(-16 + pos.x) * 0.8, float(-18 + pos.y) * 0.6);\n" " float val = 2.0 * length(texelFetch(sampler, pos, 0).rgb);\n" " mat4 wm = myMatrix * mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, val, 1) * worldMatrix;\n" " color = texelFetch(sampler, pos, 0).rgb * vec3(0.4, 1.0, 0.0);\n" " vert = vec3(wm * vertex);\n" " vertNormal = mat3(transpose(inverse(wm))) * normal;\n" " gl_Position = projMatrix * camMatrix * wm * vertex;\n" "}\n"; static const char *fragmentShaderSource = "in highp vec3 vert;\n" "in highp vec3 vertNormal;\n" "in highp vec3 color;\n" "out highp vec4 fragColor;\n" "uniform highp vec3 lightPos;\n" "void main() {\n" " highp vec3 L = normalize(lightPos - vert);\n" " highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n" " highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n" " fragColor = vec4(col, 1.0);\n" "}\n";
注意:这些与 OpenGL 版本无关。我们将其附加版本如下
QByteArray versionedShaderCode(const char *src) { QByteArray versionedSrc; if (QOpenGLContext::currentContext()->isOpenGLES()) versionedSrc.append(QByteArrayLiteral("#version 300 es\n")); else versionedSrc.append(QByteArrayLiteral("#version 330\n")); versionedSrc.append(src); return versionedSrc; }
初始化 OpenGL
初始化着色器程序由 initializeGL()
处理
void GLWindow::initializeGL() { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); QImage img(":/qtlogo.png"); Q_ASSERT(!img.isNull()); delete m_texture; m_texture = new QOpenGLTexture(img.scaled(32, 36).mirrored()); delete m_program; m_program = new QOpenGLShaderProgram;
现在OpenGL版本已添加前缀,设置了各种矩阵和光照位置
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, versionedShaderCode(vertexShaderSource)); m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, versionedShaderCode(fragmentShaderSource)); m_program->link(); m_projMatrixLoc = m_program->uniformLocation("projMatrix"); m_camMatrixLoc = m_program->uniformLocation("camMatrix"); m_worldMatrixLoc = m_program->uniformLocation("worldMatrix"); m_myMatrixLoc = m_program->uniformLocation("myMatrix"); m_lightPosLoc = m_program->uniformLocation("lightPos");
虽然对于ES 3不是严格要求的,但创建了一个顶点数组对象。
delete m_vao; m_vao = new QOpenGLVertexArrayObject; if (m_vao->create()) m_vao->bind(); m_program->bind(); delete m_vbo; m_vbo = new QOpenGLBuffer; m_vbo->create(); m_vbo->bind(); m_vbo->allocate(m_logo.constData(), m_logo.count() * sizeof(GLfloat)); f->glEnableVertexAttribArray(0); f->glEnableVertexAttribArray(1); f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), nullptr); f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat))); m_vbo->release(); f->glEnable(GL_DEPTH_TEST); f->glEnable(GL_CULL_FACE);
调整窗口大小
视角需要与新窗口大小对齐,如下所示
void GLWindow::resizeGL(int w, int h) { m_proj.setToIdentity(); m_proj.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f); m_uniformsDirty = true; }
绘制
由于我们想做的比GL(ES) 2.0提供的更多,所以我们使用QOpenGLExtraFunctions而不是QOpenGLFunctions
void GLWindow::paintGL() { // Now use QOpenGLExtraFunctions instead of QOpenGLFunctions as we want to // do more than what GL(ES) 2.0 offers. QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
我们清除屏幕和缓冲区,并绑定我们的着色器和纹理
f->glClearColor(0, 0, 0, 1); f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_program->bind(); m_texture->bind();
处理paintGL()的初始调用或resizeGL()调用之后的调用的逻辑如下实现
if (m_uniformsDirty) { m_uniformsDirty = false; QMatrix4x4 camera; camera.lookAt(m_eye, m_eye + m_target, QVector3D(0, 1, 0)); m_program->setUniformValue(m_projMatrixLoc, m_proj); m_program->setUniformValue(m_camMatrixLoc, camera); QMatrix4x4 wm = m_world; wm.rotate(m_r, 1, 1, 0); m_program->setUniformValue(m_worldMatrixLoc, wm); QMatrix4x4 mm; mm.setToIdentity(); mm.rotate(-m_r2, 1, 0, 0); m_program->setUniformValue(m_myMatrixLoc, mm); m_program->setUniformValue(m_lightPosLoc, QVector3D(0, 0, 70)); }
最后,我们展示了OpenGL 3.1或OpenGL ES 3.0中引入的函数
f->glDrawArraysInstanced(GL_TRIANGLES, 0, m_logo.vertexCount(), 32 * 36); }
这是因为我们之前请求了3.3或3.0上下文。
© 2024 Qt公司。包含在此处的文档贡献版权属于其各自的拥有者。本提供的文档是根据免费软件基金会的GNU自由文档许可协议版本1.3许可的,如发布。Qt及其相关标志是芬兰的Qt公司及其它国家和地区商标。所有其他商标属于其各自的所有者。