第二章
就像第一章所说,我们这次尝试使用原生的API来加载、编译和链接着色器代码。
首先还是看OpenGLWidget类定义:
class OpenGLWidget : public QOpenGLWidget,protected QOpenGLFunctions
{
const char* vShader ={
"#version 330 core\n"
"uniform Uniforms {"
" vec3 translation;"
" float scale;"
" vec4 rotation;"
" bool enabled;"
"};"
"in vec2 vPos;"
"in vec3 vColor;"
"out vec4 fColor;"
"void main()"
"{"
" vec3 pos = vec3(vPos, 0.0);"
" float angle = radians(rotation[0]);"
" vec3 axis = normalize(rotation.yzw);"
" mat3 I = mat3(1.0);"
" mat3 S = mat3( 0,-axis.z, axis.y,"
" axis.z,0,-axis.x,"
" -axis.y,axis.x,0);"
" mat3 uuT= outerProduct(axis,axis);"
" mat3 rot = uuT+cos(angle)*(I-uuT)+sin(angle)*S;"
" pos *= scale;"
" pos *= rot;"
" pos +=translation;"
" fColor = vec4(scale, scale, scale,1);"
" gl_Position = vec4(pos,1);"
"}"
};
const char* fShader ={
"#version 330 core\n"
"uniform Uniforms {"
" vec3 translation;"
" float scale;"
" vec4 rotation;"
" bool enabled;"
"};"
"in vec4 fColor;"
"out vec4 color;"
"void main()"
"{"
" color = fColor;"
"}"
};
GLuint programId;
GLuint vShaderId;
GLuint fShaderId;
QOpenGLShaderProgram *program;
public:
explicit OpenGLWidget(QWidget *parent = 0);
protected:
void initializeGL();
void paintGL();
void resizeGL(int w, int h);
void initVbo();
size_t TypeSize(GLenum type);
};
这次我们将顶点着色器和片元着色器的代码用vShader和fShader直接放入类。
主要变动的是:
void OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
QOpenGLFunctions_4_5_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
if (!f){
qWarning()<<"Could not obtain required OpenGL context version";
exit(1);
}
GLint r;
vSharderId = f->glCreateShader(GL_VERTEX_SHADER);
f->glShaderSource(vSharderId,1,&vShader,0);
f->glCompileShader(vSharderId);
f->glGetShaderiv(vSharderId,GL_COMPILE_STATUS,&r);
if (r!=GL_TRUE){
char rst[512];
f->glGetShaderInfoLog(vSharderId,512,NULL,rst);
qDebug()<<"vShader create error!::"<<rst;
return;
}
fSharderId = glCreateShader(GL_FRAGMENT_SHADER);
f->glShaderSource(fSharderId,1,&fSharder,0);
f->glCompileShader(fSharderId);
f->glGetShaderiv(fSharderId,GL_COMPILE_STATUS,&r);
if (r!=GL_TRUE){
char rst[512];
f->glGetShaderInfoLog(fSharderId,512,NULL,rst);
qDebug()<<"fShader create error!::"<<rst;
return;
}
programId =glCreateProgram();
f->glAttachShader(programId,vSharderId);
f->glAttachShader(programId,fSharderId);
f->glLinkProgram(programId);
f->glGetShaderiv(programId,GL_LINK_STATUS,&r);
if (r!=GL_TRUE){
char rst[512];
f->glGetShaderInfoLog(programId,512,NULL,rst);
qDebug()<<"fShader create error!::"<<rst;
return;
}
f->glClearColor(1,0,0,1);
f->glUseProgram(programId);
/*init uniform*/
GLuint uboIndex;
GLint uboSize;
GLuint ubo;
GLvoid *buffer;
uboIndex = f->glGetUniformBlockIndex(programId, "Uniforms");
f->glGetActiveUniformBlockiv(programId, uboIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &uboSize);
qDebug()<<"Uniform size:"<<uboSize;
buffer = malloc(uboSize);
if (buffer == NULL){
qDebug()<<"malloc error";
exit(EXIT_FAILURE);
}else{
enum {Translation, Scale, Rotation, Enabled, NumUniforms};
GLfloat scale = 0.5f;
GLfloat translation[] = { 0.1f, 0.1f, 0.0f};
GLfloat rotation[] = {90.0f, 0.0f, 0.0f, 1.0f};
GLboolean enabled = GL_TRUE;
const char* names[NumUniforms] = {
"translation",
"scale",
"rotation",
"enabled",
};
GLuint indices[NumUniforms];
GLint size[NumUniforms];
GLint offset[NumUniforms];
GLint type[NumUniforms];
f->glGetUniformIndices(programId, NumUniforms, names, indices);
f->glGetActiveUniformsiv(programId, NumUniforms, indices, GL_UNIFORM_OFFSET, offset);
f->glGetActiveUniformsiv(programId, NumUniforms, indices, GL_UNIFORM_SIZE, size);
f->glGetActiveUniformsiv(programId, NumUniforms, indices, GL_UNIFORM_TYPE, type);
/*copy from uniform to buffer*/
memcpy(static_cast<char*>(buffer)+offset[Scale], &scale, size[Scale]*TypeSize(type[Scale]));
memcpy(static_cast<char*>(buffer)+offset[Translation], &translation, size[Translation]*TypeSize(type[Translation]));
memcpy(static_cast<char*>(buffer)+offset[Rotation], &rotation, size[Rotation]*TypeSize(type[Rotation]));
memcpy(static_cast<char*>(buffer)+offset[Enabled], &enabled, size[Enabled]*TypeSize(type[Enabled]));
f->glGenBuffers(1, &ubo);
f->glBindBuffer(GL_UNIFORM_BUFFER, ubo);
f->glBufferData(GL_UNIFORM_BUFFER, uboSize, buffer, GL_STATIC_DRAW);
f->glBindBufferBase(GL_UNIFORM_BUFFER, uboIndex, ubo);
}
initVbo();
}
对比第一章的加载、编译和链接部分,可以看出QOpenGLShaderProgram替我们完成了多少事情。原生API调用一般是按照glCreateShader》glShaderSource》glCompileShader》glGetShaderiv》glGetShaderInfoLog(如果失败获取原因)。让我们回顾下第一章的相关部分,首先构建一个QOpenGLShaderProgram对象实例,然后进行调用addShaderFromSourceCode、link、bind就可以了。
另外需要注意的一点是,按照原文的方式,memcpy(buffer+offset[Scale], &scale, size[Scale]*TypeSize(type[Scale]))将无法通过Qt的编译,所以我将buffer做了个静态转换。