QOpenGL开发入门系列6:纹理贴图

系列教程索引:Qt开发入门系列教程索引

上一篇:QOpenGL开发入门系列5:立方体

之前的文章介绍了基本的显示方法,但是显示的是颜色,开发的时候一般显示的是风景之类的图片,所以本文介绍OpenGL相关的图片加载操作。

在OpenGLut系列中,图片数据加载用的是stb_image库,但是Qt中提供了自带的QImage用于操作图片。

显示图片

贴图先不急,来看一下如何显示一张图片。

渲染语言

顶点

1
2
3
4
5
6
7
8
9
#version 330 core

in vec2 position;
in vec2 texCoord;
out vec4 texc;
void main(){
gl_Position = vec4(position,0.0,1.0);
texc = vec4(texCoord,0.0,1.0);
}

1
2
3
4
5
6
7
8
#version 330 core

uniform sampler2D texture;
in vec4 texc;
out vec4 fragColor;
void main(){
gl_FragColor = texture2D(texture,texc.st);
}

图片数据加载

1
img = QImage(":/resources/bird.jpg");

初始化

获取并绑定顶点位置

1
2
3
4
5
6
7
8
9
10
program = new QOpenGLShaderProgram;
program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,":/resources/vsrc.glsl");
program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,":/resources/fsrc.glsl");
program->bindAttributeLocation("position",0);
program->bindAttributeLocation("texCoord",1);
program->link();//激活Program对象
program->bind();

vao.create();
vao.bind();

设置顶点数据,并创建纹理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
float vertex[]={
-1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, 0.0, 1.0
};

vbo.create();
vbo.bind();
vbo.allocate(vertex,sizeof(vertex)*sizeof(float));

program->enableAttributeArray(0);
program->enableAttributeArray(1);
program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 4*sizeof(GLfloat));
program->setAttributeBuffer(1, GL_FLOAT, 2*sizeof(GLfloat), 2, 4*sizeof(GLfloat));

texture = new QOpenGLTexture(img);

vao.release();
vbo.release();
program->release();

绘图部分

1
2
3
4
5
6
7
8
if(img.isNull()) return;

program->bind();
vao.bind();
if(texture->isCreated()) texture->bind();
glDrawArrays(GL_TRIANGLE_FAN,0,4);
vao.release();
program->release();

GL_TRIANGLE是一个三角形一个三角形的绘制,而GL_TRIANGLE_FAN是将两个三角形绘制为一个四边形,GL_QUADS是直接绘制一个四边形。

效果为:

image

显示图片2

图片加载,渲染语言和上面一样。

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
float vertex[]={
-1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, 0.0, 1.0
};

vbo.create();
vbo.bind();
vbo.allocate(vertex,sizeof(vertex)*sizeof(float));

GLuint ids[1];
glGenTextures(1,ids);
idRGB = ids[0];

设置顶点数组数据,并分配内存

绘图函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if(img.isNull()) return;

program->bind();
//vao.bind();
vbo.bind();

program->enableAttributeArray(0);
program->enableAttributeArray(1);
program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 4*sizeof(GLfloat));
program->setAttributeBuffer(1, GL_FLOAT, 2*sizeof(GLfloat), 2, 4*sizeof(GLfloat));

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,idRGB);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,img.width(),img.height(),0,GL_RGBA,GL_UNSIGNED_BYTE,img.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

program->setUniformValue("texture",0);
glDrawArrays(GL_TRIANGLE_FAN,0,4);
program->disableAttributeArray(0);
program->disableAttributeArray(1);
program->release();

可以看到绑定数组数据的代码移到绘图函数里面了,也就是说流程就是这样,位置在哪无所谓。

中间的就是OpenGLut系列中常用的纹理方法。

最下面的就是解除绑定。

GL_TEXTURE0是此纹理数据所在的位置,他的值为0,setUniformValue绑定的其实是"texture"和GL_TEXTURE0。将纹理位置和渲染语言变量绑定到一起。

查看效果

result

会发现图片篇青色。肯定是那里有问题。

先用代码获取一下图片格式

1
qDebug()<<img.format();

输出为:

1
QImage::Format_RGB32

那么RGB格式是没错了,但是它有32位,一个通道是8位,就是四个通道,即RGBA。

在图片加载完成后添加代码

1
2
3
img = QImage(":/resources/bird.jpg");
img.convertTo(QImage::Format_RGBA8888);
qDebug()<<img.format();

将图片转换为RGBA格式,这样显示就对了。

image

也可以将图片转换为RGB888,在绘图中将格式改为GL_RGB。

立方体贴图

图像能够正常显示之后,我们就该往立方体上面贴了。

下一篇: