OpenGL系列(五)纹理贴图

概述

OpenGL纹理是一种在三维图形中应用纹理映射的技术。纹理是一张图像,可以应用到三维模型的表面上,从而使得模型看起来更加真实和具有细节。通过纹理映射,可以将图像的像素值与三维模型的顶点进行匹配,从而为模型的表面增加细节和图案。

OpenGL提供了一套用于加载、创建和使用纹理的API,使得纹理映射变得简单和高效。在OpenGL中,纹理被存储在纹理缓冲区中,并通过纹理坐标来进行访问。纹理坐标是一个二维向量,范围在[0,1]之间,用于映射纹理的像素值。

为了应用纹理映射,需要先加载纹理图像并将其传输到OpenGL的纹理缓冲区中。然后,可以在绘制三维模型之前,将纹理坐标与模型的顶点进行匹配,并通过纹理坐标在纹理缓冲区中获取相应的像素值。最后,将像素值应用到模型的表面上,从而实现纹理映射。

OpenGL还提供了一些纹理过滤和纹理环绕的选项,用于控制纹理在放大和缩小时的插值和边界处理。这些选项可以改善纹理映射的质量和效果,使得纹理在不同大小和角度下都能正确显示。

总的来说,OpenGL纹理是一种强大的技术,可以为三维模型增加细节和图案,并提升图形渲染的质量和真实感。通过合理的纹理映射和纹理处理,可以使得模型在视觉上更加吸引人和逼真。

示例

接下来通过一个简单的示例来介绍如何使用纹理贴图将一张图片映射到一个矩形中,效果如下图所示。

在上图中,中间是一个矩形,在该矩形中显示的图片,下面分步介绍如何实现上面的效果。

1、创建纹理对象

要使用纹理,首先要创建纹理对象,代码如下。

    mTexture = 0;
    glGenTextures(1, &mTexture);
    glBindTexture(GL_TEXTURE_2D, mTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

创建纹理过程解析如下。

1)创建纹理对象:glGenTextures用于创建纹理对象,1表示创建一个纹理对象,成功后纹理对象的句柄保存到tex中。

2)绑定纹理对象:glBindTexture用于绑定纹理对象到纹理目标GL_TEXTURE_2D,绑定后对目标的操作会影响到被绑定的纹理对象。

3)设置参数:glTexParameterf用于设置纹理参数。参数GL_TEXTURE_WRAP_S设置为GL_CLAMP_TO_EDGE表示S方向超出范围[0.0,1.0]时使用边界的颜色,同样参数GL_TEXTURE_WRAP_T也设置为GL_CLAMP_TO_EDGE表示T方向超出范围[0.0,1.0]时使用边界的颜色。参数GL_TEXTURE_MIN_FILTER和GL_TEXTURE_MAG_FILTER都设置为GL_LINEAR表示纹理缩小和放大的过滤方式都是线性插值。

2、载入图片数据

创建纹理对象后,接下来向该对象载入图片数据,流程如下。

    AAsset *pathAsset = AAssetManager_open(assetManager,path.c_str(), AASSET_MODE_BUFFER);
    unsigned char *filedata = (unsigned char *) AAsset_getBuffer(pathAsset);
    off_t assetLength = AAsset_getLength(pathAsset);
    stbi_set_flip_vertically_on_load(true);
    unsigned char *data = stbi_load_from_memory(filedata, assetLength,&w,&h,&n,0);
    if(data != nullptr){
        GLint format = GL_RGB;
        if(n == 4) format = GL_RGBA;

        glTexImage2D(GL_TEXTURE_2D,0, format, w,h,0,format,GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }

载入图片数据流程解析如下

1)AAssetManager_open打开assets目录的图片文件

2)AAsset_getBuffer获取图片文件的缓冲

3)stbi_load_from_memory将图片缓冲解吗得到图片数据

4)glTexImage2D向纹理对象载入图片数据

5)glGenerateMipmap生成多级渐远纹理

3、绑定纹理单元

纹理对象要绑定到特定的纹理单元,采样器才能采样,绑定方法如下

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mTexture);

这里把纹理对象绑定到0号纹理单元。

4、编写着色器

纹理贴图的着色器如下。

    std::string strVs = R"(
#version 300 es
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 vTexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    vTexCoord = aTexCoord;
}
)";

    std::string strFs = R"(
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 vTexCoord;
uniform sampler2D sampler;
void main()
{
    FragColor = texture(sampler, vTexCoord);
}
)";

在顶点着色器中,有两个顶点属性,0号属性aPos表示顶点位置,1号属性aTexCoord表示纹理坐标。

在片元着色器中,vTexCoord是纹理坐标,sampler是纹理采样器,在main方法中调用采样函数texture对纹理进行采样,采样结果输出到FragColor。

5、开始绘制

绘制纹理的流程如下所示。

    mShader->setInt("sampler",0);

    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(0.5f,0.6f,0.7f,1.0f);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

绘制流程解析如下:

mShader->setInt("sampler",0); 知会着色器的采样器到几号纹理单元采样,0表示0号纹理单元。

glBindVertexArray(VAO);绑定VAO,有了VAO才知道如何取得顶点数据。

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 绑定索引数据

glDrawElements开始绘制,由于已经绑定了索引数据,所以最后的参数无须传索引数据的首地址。

6、工程地址

本示例已经上传到github,地址如下。

示例工程地址

相关推荐
gis分享者21 天前
学习threejs,通过设置纹理属性来修改纹理贴图的位置和大小
threejs·纹理贴图·位置和大小
Mapmost7 个月前
深入解析纹理贴图——纹理过滤及MipMap技术
图形渲染·贴图·纹理贴图
ygtu20181 年前
如何使用凹凸贴图和位移贴图制作逼真的模型
3d·贴图·3d渲染·材质贴图·材质纹理·纹理贴图·材质编辑
ygtu20181 年前
PBR纹理贴图类型详解
贴图·3d渲染·材质纹理·纹理贴图
ygtu20181 年前
位移贴图、凹凸贴图和法线贴图之间的差异
贴图·材质纹理·纹理贴图·材质编辑·模型渲染
ygtu20181 年前
写实风格3D模型材质贴图
webgl·three.js·材质·材质纹理·纹理贴图·材质编辑·模型渲染
ygtu20181 年前
GLTF 编辑器实现逼真3D动物毛发效果
webgl·three.js·材质纹理·纹理贴图·材质编辑·模型渲染·3d材质编辑
ygtu20181 年前
法线贴图可以实现什么样的3D效果
3d·贴图·材质纹理·纹理贴图·材质编辑·模型渲染
ygtu20181 年前
3D 纹理贴图基础知识
3d·贴图·3d渲染·材质贴图·材质纹理·纹理贴图·材质编辑