今天尝试着使用QOpenGLWidget从零绘制一个三角形,发现始终黑屏。
经过反复摸索,最终可以了,这里是DEMO
总结需要注意的几点:
- 必须在
paintGL
回调里面draw,不然qt也就没有必要提供这个回调。 - 继承
QOpenGLExtraFunctions
/QOpenGLFunctions
,并在initializeGL
中进行OpenGL函数寻址
void QOpenGLWidget::initializeGL(){ this->initializeOpenGLFunctions(); // ... } 复制代码
class | OpenGL ES | 最直观的区别 |
QOpenGLExtraFunctions | 3.0/3.1/3.2 | 可以使用glBindVertexArray |
QOpenGLFunctions | 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 |