持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
今天尝试着使用QOpenGLWidget从零绘制一个三角形,发现始终黑屏。
经过反复摸索,最终可以了,这里是DEMO
总结需要注意的几点:
-
必须在
paintGL回调里面draw,不然qt也就没有必要提供这个回调。 -
继承
QOpenGLExtraFunctions/QOpenGLFunctions,并在initializeGL中进行OpenGL函数寻址void QOpenGLWidget::initializeGL(){ this->initializeOpenGLFunctions(); // ... }class OpenGL ES 最直观的区别 QOpenGLExtraFunctions 3.0/3.1/3.2 可以使用 glBindVertexArrayQOpenGLFunctions 2.0 无法使用 glBindVertexArray -
shader报错: version '330' is not supported
这里的报错问题其实是和OpenGL的版本有关系,每个OpenGL版本之间是存在差异的。正因为存在不同的OpenGL版本,所以shader里面才有了
#version 330 core
解决办法:
#include <qsurfaceformat.h> QSurfaceFormat fmt; fmt.setVersion(3, 3); fmt.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(fmt);当然配套的shader也得同步修改
shader编译失败导致的黑屏
首先你需要确认是debug模式,否则你看不到任何的cocos engine log,也就看不到shader编译的报错,当然也就不会怀疑是shader导致的问题。
glCompileShader如果出现问题,只有在debug模式下能看到报错,其实我感觉这种问题是无论如何都要log的,不然会增加排查难度,坑了我好几天的时间!
例如这个shader
uniform mat4 CC_PMatrix;
uniform mat4 CC_MultiViewPMatrix[4];
uniform mat4 CC_MVMatrix;
uniform mat4 CC_MVPMatrix;
uniform mat4 CC_MultiViewMVPMatrix[4];
uniform mat3 CC_NormalMatrix;
uniform vec4 CC_Time;
uniform vec4 CC_SinTime;
uniform vec4 CC_CosTime;
uniform vec4 CC_Random01;
uniform sampler2D CC_Texture0;
uniform sampler2D CC_Texture1;
uniform sampler2D CC_Texture2;
uniform sampler2D CC_Texture3;
//CC INCLUDES END
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif
void main()
{
gl_Position = CC_MVPMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
报错信息如下:
cocos2d: ERROR: 0:1: '' : #version required and missing.
ERROR: 0:18: 'attribute' : syntax error: syntax error
那很明显就是OpenGL的版本导致的问题,修改shader是不可能的,我们只能调整OpenGL版本,那么这种shader写法应该是哪个版本的呢?
查询当前使用的OpenGL相关信息:
QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
auto version = fmt.version();
qDebug() << "use surface version: " << version.first << "." << version.second; // 返回的是2.0
const GLubyte* versionString = glGetString(GL_VERSION);
qDebug() << "use opengl version: " << QString(QLatin1String((char*)versionString)); // 返回的是4.1
QSurfaceFormat::setVersion()默认值就是2.0
glGetString(GL_VERSION)可能获取的和surface不太一致,至于为啥,我就没有再深究了。
#version必须写是opengl3.3之后规定的,所以这里我直接设置QOpenGLWidget使用的版本,注意必须放在QOpenGLWidget的构造函数之前,我是放在了main入口
QSurfaceFormat fmt;
fmt.setVersion(2, 1);
fmt.setProfile(QSurfaceFormat::NoProfile);
QSurfaceFormat::setDefaultFormat(fmt);
3个模式,后续有时间再慢慢了解:
- NoProfile
- CompatibilityProfile
- CoreProfile
至此,shader就能正常通过编译了
framebuffer导致的黑屏
FrameBuffer Status Error 33305,
OpenGL error 0x0506 in cocos2d-x/cocos/renderer/CCRenderer.cpp saveRenderState 155
第二个错误是因为第一个错误导致的,这里我们需要重点关注第一个错误即可
glCheckFramebufferStatus返回值33305(0X8219)的含义是GL_FRAMEBUFFER_UNDEFINED,也就是没有framebuffer
产生原因
不同于OpenGL,Qt中的QOpenGLWidget类的对象不存在默认的Framebuffer,即当前Framebuffer的id不一定是0。
通过context()->defaultFramebufferObject()可以获取当前Framebuffer的id。
经过实验发现,在initializeGL()中的Framebuffer初始为0,而paintGL()中则默认新创建了一个Framebuffer。
因此,需要在paintGL()中通过context()->defaultFramebufferObject()获取id,之后才能进行glBindFramebuffer()等操作。
cocos2dx 使用的glfw版本为3.2,glfw会默认创建一个有效的framebuffer,所以默认的cocos xcode工程没有问题。
解决办法
在paintGL中进行初始化engine,这样frameBuffer就正常了,engine也就正常了。
其实在这个项目中就提到了这个问题,刚好曾经看过,有印象,所以我也就这么做了
OpenGL版本对应的GLSL版本
| OpenGL版本号 | GLSL版本号 | 发布时间 |
|---|---|---|
| 2.0 | 110 | 2004年9月7日 |
| 2.1 | 120 | 2006年7月2日 |
| 3.0 | 130 | 2008年8月11日 |
| 3.1 | 140 | 2009年3月24日 |
| 3.2 | 150 | 2009年8月3日 |
| 3.3 | 330 | 2010年3月11日 |
| 4.0 | 400 | 2010年3月11日 |
| 4.1 | 410 | 2010年7月26日 |
| 4.2 | 420 | 2011年8月8日 |
| 4.3 | 430 | 2012年8月6日 |
| 4.4 | 440 | 2013年7月23日 |
| 4.5 | 450 | 2014年7月 |
| 4.6 | 460 | 2017年7月 |
| OpenGL ES 版本号 | GLSL ES版本号 |
|---|---|
| 2.0 | 100 |
| 3.0 | 300 |
| 3.1 | 310 |
| 3.2 | 320 |