【OpenGL学习笔记八】纹理

目录

绘制纹理的步骤

1.创建纹理对象

2.绑定纹理对象

3.给纹理对象附加上纹理图像

4.在片段着色器中定义采样器并使用

5.使纹理对象和着色器建立关系

6.传递纹理对象给纹理单元,并调用glDrawElements绘图

纹理坐标

纹理单元


纹理是一个2D图片(甚至也有1D和3D的纹理),通俗的说绘制纹理就是用OpenGL绘制图片。

除了图像以外,纹理也可以被用来储存大量的数据,这些数据可以发送到着色器上。

绘制纹理的步骤

1.创建纹理对象

//生成的OpenGL对象一样,纹理也是使用ID引用的
unsigned int texture;
glGenTextures(1, &texture);
//glGenTextures函数首先需要输入生成纹理的数量,然后把它们储存在第二个参数的unsigned int数组中

2.绑定纹理对象

绑定之后任何的纹理指令都可以配置当前绑定的纹理:

glBindTexture(GL_TEXTURE_2D, texture);

3.给纹理对象附加上纹理图像

//通过glTexImage2D在当前纹理对象上生成纹理
//当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像
QImage image1 = QGLWidget::convertToGLFormat(QImage(":/image/image/container.jpg"));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image1.width(), image1.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image1.bits());
glGenerateMipmap(GL_TEXTURE_2D);

当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像。

4.在片段着色器中定义采样器并使用

GLSL有一个供纹理对象使用的内建数据类型,叫做采样器(Sampler),它以纹理类型作为后缀,比如sampler1Dsampler3D,或在我们的例子中的sampler2D。我们可以简单声明一个uniform sampler2D把一个纹理添加到片段着色器中,稍后我们会把纹理赋值给这个uniform。

#version 330
out vec4 fragColor;

in vec2 TexCord;
uniform sampler2D texture1;
void main()
{
    fragColor = texture(texture1, TexCord);
#使用GLSL内建的texture函数来采样纹理的颜色,它第一个参数是纹理采样器,
第二个参数是对应的纹理坐标。texture函数会使用之前设置的纹理参数对相应的颜色值进行采样。
这个片段着色器的输出就是纹理的(插值)纹理坐标上的(过滤后的)颜色。
}

5.使纹理对象和着色器建立关系

纹理对象的纹理数据是不能直接传递给着色器的,纹理对象可以传递给纹理单元。

采样器可以通过glUniform1i来指定该采样器对应的是哪个纹理单元。

sharedprogram.bind();
//设定采样器对应的纹理单元
sharedprogram.setUniformValue("texture1",0);//指定采样器texture1为纹理单元0
//sharedprogram.setUniformValue("texture2",1);//指定采样器texture2为纹理单元1
sharedprogram.release();

6.传递纹理对象给纹理单元,并调用glDrawElements绘图

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);//传递纹理对象到纹理单元
//glActiveTexture(GL_TEXTURE1);
//glBindTexture(GL_TEXTURE_2D, texture2);

glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

/********************************************************************/
#version 330
out vec4 fragColor;

in vec2 TexCord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
    fragColor = mix(texture(texture1, TexCord), texture(texture2, TexCord), 0.2) ;
}
/*********************************************************************/   
 //创建一个纹理对象
    glGenTextures(1, &texture_container);
    //绑定纹理对象,让之后任何的纹理指令都可以配置当前绑定的纹理
    glBindTexture(GL_TEXTURE_2D, texture_container);
    //通过glTexImage2D在当前纹理对象上生成纹理
    //当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像
    QImage image1 = QGLWidget::convertToGLFormat(QImage(":/image/image/container.jpg"));
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image1.width(), image1.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image1.bits());
    glGenerateMipmap(GL_TEXTURE_2D);

    glGenTextures(1, &texture_awesomeface);
    glBindTexture(GL_TEXTURE_2D, texture_awesomeface);

    QImage image = QGLWidget::convertToGLFormat(QImage(":/image/image/awesomeface.png"));
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
    glGenerateMipmap(GL_TEXTURE_2D);

/*********************************************************************/
    sharedprogram.bind();
    //设定采样器对应的纹理单元
    sharedprogram.setUniformValue("texture1",0);//指定采样器texture1为纹理单元0
    sharedprogram.setUniformValue("texture2",1);//指定采样器texture2为纹理单元1
    sharedprogram.release();

/*********************************************************************/   
    sharedprogram.bind();


    glActiveTexture(GL_TEXTURE0);// 在绑定纹理之前先激活纹理单元
    glBindTexture(GL_TEXTURE_2D, texture_container);//传递纹理给纹理单元

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture_awesomeface);

    glBindVertexArray(VAO);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    sharedprogram.release();

纹理坐标

纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。

上图的纹理坐标如下

float texCoords[] = {
    0.0f, 0.0f, // 左下角
    1.0f, 0.0f, // 右下角
    0.5f, 1.0f // 上中
};

纹理单元

一个纹理的位置值通常称为一个纹理单元(Texture Unit)。一个纹理的默认纹理单元是0,它是默认的激活纹理单元,所以教程前面部分我们没有分配一个位置值。

纹理单元的主要目的是让我们在着色器中可以使用多于一个的纹理。通过把纹理单元赋值给采样器,我们可以一次绑定多个纹理,只要我们首先激活对应的纹理单元。就像glBindTexture一样,我们可以使用glActiveTexture激活纹理单元,传入我们需要使用的纹理单元:

glActiveTexture(GL_TEXTURE0); // 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture);

激活纹理单元之后,接下来的glBindTexture函数调用会绑定这个纹理到当前激活的纹理单元,纹理单元GL_TEXTURE0默认总是被激活,所以我们在前面的例子里当我们使用glBindTexture的时候,无需激活任何纹理单元。

OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15。它们都是按顺序定义的,所以我们也可以通过GL_TEXTURE0 + 8的方式获得GL_TEXTURE8,这在当我们需要循环一些纹理单元的时候会很有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值