opengl——贴图

原文地址:https://www.haroldserrano.com/blog/a-brief-talk-about-opengl-textures

创建和初始化纹理
贴图在OpenGL中代表了图片,它包含了一些特性。比如,下面的图,一个是没有贴图的一个是有贴图的。
在这里插入图片描述

在OpenGL中,有两种存储方式:
1.缓冲
2.贴图

缓冲是未定义类型的线性结构的数据,可以被视为通常的内存分配。贴图是多维度的数据,比如图片。
在这里插入图片描述

在OpenGL中,属性数据如下:
1.顶点位置
2.法线
3.u-v坐标

这些都存储在OpenGL的缓冲中。相反的,图片数据则是存储在OpenGL的贴图对象中。

在这里插入图片描述

为了存储图片数据到纹理对象,你要按照如下的步骤:
1.创建纹理对象
2.分配纹理内存
3.绑定纹理对象

我们使用如下的函数去创建、绑定、分配内存。
清单1:

//创建纹理对象
glCreateTextures(...);

//分配内存
glTexStorage2D(...);

//绑定它到GL_Texture_2D目标
glBindTexture(...);

上面是程序片段,用来展示如何创建纹理对象、分配存储空间、绑定它到OpenGL上下文。

清单2:

扫描二维码关注公众号,回复: 3921917 查看本文章
//OpengL中使用名字的类型为GLuint
GLuint texture;

//创建2D的纹理对象
glCreateTextures(GL_TEXTURE_2D,1,&texture);

//定义贴图的使用内存大小
glTextureStorage2D(texture,    //纹理对象
                   1,          //1 mimap 等级
                   GL_RGBA32F, //32位浮点数RGBA数据
                   256,256);   //256 x 256 texels

//绑定它到OpenGL上下文,使用的是GL_TEXTURE_2D作为绑定点
glBindTexture(GL_TEXTURE_2D, texture);

在这个纹理对象绑定之后,你可以加载数据到纹理。数据加载的方式如下:

清单3:

glTexSubImage2D(...)

清单4:

//定义一些数据
float *data=new float[256*256*4];

glTexSubImage2D(texture,  //纹理对象
                0,        //level 0
                0,0,      //offset 0,0
                256,256,  //256 x 256 texels
                GL_RGBA,  //Four channel data
                GL_FLOAT, //Floating point data
                data);    //Pointer to data

纹理对象和类型

在理解OpenGL纹理的时候遇到的第一个问题是,什么是目标。事实证明,目标是非常简单和直接的。一个纹理目标决定了纹理对象的类型。

比如,纹理以2D纹理创建。因此,纹理对象绑定到2D纹理目标,GL_TEXTURE_2D。如果有一个1D的纹理,你就要把它绑定到1D纹理目标,GL_TEXTURE_1D。

由于你要使用多个图片,你会发现经常使用的是GL_TEXTURE_2D类型的。这是因为图片是用2D数据展示的。

从shaders中读取纹理

一旦纹理绑定了,且包含了数据,它就可以被shader使用。在shader中,纹理是作为全局Sampler变量的。
在这里插入图片描述

比如:
清单5:

uniform sampler2D myTexture;

采样器的维度和纹理的维度有关。我们的纹理是2D的,所以要指定为2D的采样器,那就是sampler2D。

如果你的纹理是1D的,采样器就是sampler1D的。如果纹理是3D的,那么采样器就是sampler3D。

纹理坐标

采样器代表了纹理以及采样参数。纹理坐标从0.0到1.0。这个两个坐标在应用纹理到物体所必须的。你已经知道如何在shader中代表纹理了,使用的是sampler。但是怎样在shader中得到纹理坐标呢?

属性数据是通过OpenGL的缓冲传递给GPU的。你加载属性数据。这些属性可以是顶点的位置、法线、纹理坐标。纹理坐标也称为uv坐标。

顶点着色器从顶点属性接收信息。只有顶点着色器可以接收属性数据。细分曲面、几何和片段着色器都不能接收属性数据。如果这些着色器需要数据,你必须从顶点着色器开始向他们传递。

在这里插入图片描述

因此,顶点着色器从顶点属性中接收纹理坐标。然后由顶点着色器向片段着色器传递。一旦这个坐标传递到了片段着色器,OpenGL就可以应用纹理到物体了。

清单6展示纹理坐标作为顶点的属性。在main函数中,这个坐标未经变换直接传递给片段着色器。

清单6:

#version 450 core
//uniform variables
uniform mat4 mvMatrix;
uniform mat4 projMatrix;

//Vertex Attributes for position and UV coordinates
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texCoordinates;

//output to fragment shader
out TextureCoordinates_Out{
    vec2 texCoordinates;
}textureCoordinates_out;

void main(){
//计算每个顶点的裁剪空间坐标
vec4 position_vertex=mvMatrix*position;

//未修改直接传出
textureCoordinates_out.texCoordinates=texCoordinates;

gl_Position=projMatrix*position_vertex;

}

清单7展示了如何使用texture()函数,它使用纹理坐标采样纹理,然后应用到一个像素。
清单7:

#version 450 core
//Sampler2D declaration
layout(binding = 0) uniform sampler2D textureObject;

//Input from vertex shader
in TextureCoordinates_Out{
    vec2 textureCoordinates;
}textureCoordinates_in;

//Output to framebuffer
out vec4 color;

void main(){
//使用纹理坐标和采样器,应用纹理,得到颜色
color=texture(textureObject,textureCoordinates_in.textureCoordinates;
}

控制纹理数据如何读取
采样器在纹理单元中找到纹理数据并且遍历。纹理单元包含了一个纹理对象和一个采样对象。你已经知道纹理对象是什么了,现在我们来讨论下采样对象吧。

纹理坐标在0.0和1.0之间。OpenGL让我们自己决定对于那些超出了这个范围的坐标怎么办。这叫包围模式。OpenGL同样让我们自己决定对于不是1比1的比例,怎么处理。这个叫做过滤模式。一个采样器存储了包围模式和过滤模式这些参数。

在这里插入图片描述

一个采样器需要纹理对象和采样器对象,他们都要绑定到纹理单元。当这个数据集合是完整的,采样才能能正常应用一个纹理。

在这里插入图片描述

在特殊情况下,你将会创建一个采样器对象、然后把它绑定到纹理单元。但是更多的情况下,你不需要创建一个采样器对象。这是因为纹理对象有一个默认的采样器对象,你可以使用这个默认的。默认的采样器对象有默认的包围/过滤模式参数配置。

为了访问存储在纹理对象中的默认的采样器对象,你可以调用:
清单8:

//accessing the default sampler object in a texture object and setting the sampling parameters
glTexParameter()

在绑定纹理对象到纹理单元之前,你必须激活纹理单元。这个需要调用下面的函数,来激活指定的纹理单元
清单9:

//Activate Texture Unit 0
glActiveTexture(GL_TEXTURE0);

猜你喜欢

转载自blog.csdn.net/wodownload2/article/details/83689242