Qt+OpenGL实现加载纹理

当需要给图像赋予真实颜色的时候,不太可能使用前面的方法,为每一个顶点指定第一个颜色。通常会采用纹理贴图

为了能够把纹理映射(Map)到三角形上,需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(译注:采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。

纹理坐标在x和y轴上,范围为0到1之间(注意使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。下面的图片展示了是如何把纹理坐标映射到三角形上的。

接下来的工作:告诉OpenGL如何对纹理采样

float vertices_data[24] = {
        // 所有的值是在[-1, 1]之间的
        // 位置              // 颜色          //纹理坐标
        0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,1.0f, 1.0f,   // 右下
        -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,1.0f, 0.0f,  // 左下
        0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f,0.0f, 0.0f,   // 顶部   
    };

由于添加了一个额外的顶点属性,必须告诉OpenGL新的顶点格式:

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);

注意,同样需要调整前面两个顶点属性的步长参数为8 * sizeof(float)

接着需要调整顶点着色器使其能够接受顶点坐标为一个顶点属性,并把坐标传给片段着色器

#version 330 core
    layout(location = 0) in vec3 aPos;
    layout(location = 1) in vec3 aColor;
    layout(location = 2) in vec2 aTexCord;
    out vec3 ourColor;
    out vec2 TexCord;
    void main()
    {
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);

    ourColor=aColor;
    TexCord=aTexCord;
    }

片段着色器应该接下来会把输出变量TexCord作为输入变量。

片段着色器也应该能访问纹理对象,但是怎样能把纹理对象传给片段着色器呢?GLSL有一个供纹理对象使用的内建数据类型,叫做采样器(Sampler),它以纹理类型作为后缀,比如Sampler1D、Sampler3D,或在例子中的Sampler2D。我们可以简单声明一个uniform Sampler2D把一个纹理添加到片段着色器中,稍后会把纹理赋值给这个uniform。

#version 330 core
    out vec4 FragColor;
    in vec3 ourColor;
    in vec2 TexCord;
    uniform sampler2D texture0;
    uniform sampler2D texture1;
    void main()
    {
    FragColor = texture(texture0,TexCord);
    }

使用GLSL内建的texture函数来采样纹理的颜色,它第一个参数是纹理采样器,第二个参数是对应的纹理坐标。texture函数会使用之前设置的纹理参数对相应的颜色值进行采样。这个片段着色器的输出就是纹理的(插值)纹理坐标上的(过滤后的)颜色。

现在只剩下在调用glDrawElements之前绑定纹理了,它会自动把纹理赋值给片段着色器的采样器:

 QOpenGLTexture * textureWall;
 textureWall=new QOpenGLTexture(QImage(":/img/pic.jpg").mirrored());
 glBindVertexArray(0);
 textureWall->bind(0);
 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);

运行结果如下图:

纹理坐标的范围通常是从(0, 0)到(1, 1),那如果把纹理坐标设置在范围之外会发生什么?OpenGL默认的行为是重复这个纹理图像( 基本上忽略浮点纹理坐标的整数部分),但OpenGL提供了更多的选择:

环绕方式描述
GL_REPEAT对纹理的默认行为。重复纹理图像。
GL_MIRRORED_REPEAT和GL_REPEAT一样,但每次重复图片是镜像放置的。
GL_CLAMP_TO_EDGE纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
GL_CLAMP_TO_BORDER

超出的坐标为用户指定的边缘颜色。

当纹理坐标超出默认范围时,每个选项都有不同的视觉效果输出。现在来看看这些纹理图像的例子:

前面提到的每个选项都可以使用glTexParameter*函数对单独的一个坐标轴设置(s,t(如果是使用3D纹理那么还有一个r)它们和x,y,z是等价的):

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

如果选择GL_CLAMP_TO_BORDER选项,还需要指定一个边缘的颜色。这需要使用glTexParameter函数的fv后缀形式,用GL_TEXTURE_BORDER_COLOR作为它的选项,并且传递一个float数组作为边缘的颜色值:

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值