《OpenGL宝典》

您所在的位置:网站首页 贴图和纹理区别在哪 《OpenGL宝典》

《OpenGL宝典》

#《OpenGL宝典》| 来源: 网络整理| 查看: 265

文章目录 创建并初始化纹理创建纹理更新纹理数据 纹理目标和类型从着色器中读取纹理数据采样器类型使用texelFetch内置函数从着色器读取纹理使用texture()函数从着色器读取纹理获取更多信息 控制纹理数据的读取方式使用采样器对象存储采样器包装和过滤模式的参数创建一个或多个采样器设置采样器对象参数绑定采样器到纹理单元设置存储在纹理对象内的采样器对象 纹理对象参数纹理过滤过滤器 纹理环绕设置采样器纹理环绕方式 使用多个纹理将纹理绑定到特定纹理单元着色器中的采样器统一变量引用不同单元 mipmap层数设置,数据输入,限制层数使用mip贴图过滤构建mip层 数组纹理2D数组纹理与3D纹理的区别加载2D数组纹理使用数组纹理 在着色器中向纹理写入数据使用image变量表示纹理的单个图像声明图像单元读取存储数据将纹理层绑定到图像单元在着色器使用图像单元绑定的图像

创建并初始化纹理 创建纹理 GLuint texture; glCreateTextures(GL_TEXTURE_2D, 1, &texture); glTextureStorage2D( texture, //纹理对象 1, //mipmap等级 GL_RGBA32F, //纹理数据类型 256,256); //纹理大小 glBindTexture(GL_TEXTURE_2D,texture); 更新纹理数据 glTextureSubImage2D( texture, //纹理对象 0, //等级 0, 0, //偏移量 256, 256, //大小 GL_RGBA, //通道类型 GL_FLOAT, //数据类型 data); //数据指针

glTextureSubImage2D将保留原始纹理数据副本,因此可将data指向的内存释放。

如果只是想将纹理初始化为一个固定值,则可使用glClearTexSubImage()

void glClearTexSubImage( GLuint texture, //纹理对象 GLint level, //想要清除的mip贴图层 GLint xoffset, //待清除区域起始偏移量 GLint yoffset, // GLint zoffset, // GLsizei width, //区域尺寸 GLsizei height, // GLsizei depth, // GLenum format, //通道类型 GLenum type, //数据类型 const void *data);//单纹素数据 纹理目标和类型

纹理目标GL_TEXTURE_*: 1D/2D/3D RECTANGLE矩形纹理(2D纹理的子集) 1D_ARRAY/2D_ARRAY聚合到单个对象中的纹理* CUBE_MAP/CUBE_MAP_ARRAY六个正方形图像的集合/数组纹理 BUFFER特殊的纹理类型 2D_MULTISAMPLE/2D_MULTISAMPLE_ARRAY多采样抗锯齿

从着色器中读取纹理数据 采样器类型

常用的有sampler2D, sampler2Darray, samplerCube, samplerCubearray, sampler2DMS, sampler2DMSArray sampler2D表示符点数据,若要表示有符号整数数据、无符号整数数据,则使用isampler2D,usampler2D

使用texelFetch内置函数从着色器读取纹理 vec4 texelFetch(sampler1D s, int P, int lod);//P为读取位置,lod为mip层 vec4 texelFetch(sampler2D s, ivec2 P, int lod); ivec4 texelFetch(isampler2D s, ivec2 P, int lod); uvec4 texelFetch(usampler1D s, ivec3 P, int lod);

返回值都为4通道,若只返回一个通道,则G、B默认值为0,A默认值为1。

使用texture()函数从着色器读取纹理

texture()与texelFetch()的区别主要是: texture采用函数会涉及归一化、过滤以及插值等复杂操作,基本无法得到某一确切像素的值。 texelFetch 使用的是未归一化的坐标直接访问纹理中的纹素,不执行任何形式的过滤和插值操作,坐标范围为实际载入纹理图像的宽和高。

gvec4 texture( gsampler2D sampler, vec2 P, [float bias]); 获取更多信息

使用textureSize返回纹理大小

int textureSize(sampler1D sampler, int lod); ivec2 textureSize(sampler2D sampler, int lod); ivec3 textureSize(gsampler3D sampler, int lod);

使用textureSamples()了解多重采样纹理包含多少样本

int textureSamples(sampler2DMS sampler); 控制纹理数据的读取方式 使用采样器对象存储采样器包装和过滤模式的参数 创建一个或多个采样器 void glCreateSamplers(GLsizei n, GLuint *samplers); 设置采样器对象参数 void glSamplerParameter*( GLuint sampler, //采样器对象名称 GLenum pname, //指定采样器参数的符号名称 参数类型(与*有关) param); //指定pname的值

GLenum pname: GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_R, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_BORDER_COLOR, GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_LOD_BIAS , GL_TEXTURE_COMPARE_MODE, GL_TEXTURE_COMPARE_FUNC.

绑定采样器到纹理单元 void glBindSampler(GLuint uint, GLuint sampler); 设置存储在纹理对象内的采样器对象

每个纹理都有一个默认采样参数,当没有采样器对象绑定到相应纹理时,则将使用默认采样参数。可以使用如下函数设置默认采样参数

//Texture直接作用于纹理对象 void glTextureParameterf( GLuint texture, GLenum pname, GLfloat param); //Tex作用于指定绑定点的纹理对象----glBindTexture(GLenum target,GLuint texture); void glTexParameterf( GLenum target, GLenum pname, GLfloat param); 纹理对象参数 纹理过滤

从拉伸或收缩的纹理图中计算颜色片段的过程称为纹理过滤(texture filtering)。

过滤器

利用采样器参数函数,支持我们在放大和缩小的情况下分别设置构造纹素值

放大过滤器参数名称:GL_TEXTURE_MAG_FILTER 缩小过滤器参数名称:GL_TEXTURE_MIN_FILTER

最近邻过滤:GL_NEAREST 线性过滤:GL_LINEAR

设置采样器的过滤器

glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

直接设置纹理的默认过滤器

//Texture直接作用于纹理对象 void glTextureParameterf( GLuint texture, GLenum pname, GLfloat param); //Tex作用于指定绑定点的纹理对象----glBindTexture(GLenum target,GLuint texture); void glTexParameterf( GLenum target, GLenum pname, GLfloat param); 纹理环绕

正常情况,我们只会在0.0~1.0之间指定纹理坐标,如果纹理坐标在此范围外,OpenGL会根据采样器对象中指定的当前纹理环绕模式方式进行设置。

设置采样器纹理环绕方式

使用如下函数:

glSampleParameter*( GLuint sampler, GLenum pname, * param)

纹理环绕参数有:

GL_TEXTURE_WRAP_S //1D/2D/3D GL_TEXTURE_WRAP_T //2D/3D GL_TEXTURE_WRAP_R //3D

纹理环绕值有:

GL_REPEAT //重复 GL_MIRRORED_REPEAT //镜面重复 GL_CLAMP_TO_EDGE //超出部分对边缘采样 GL_CLAMP_TO_BORDER //超出部分使用边框颜色 GL_MIRROR_CLAMP_TO_EDGE // 只在(-1.0~0.0, 1.0~2.0上镜面重复,其余部分使用边缘颜色)

其中边框颜色使用如下函数设置。

glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, color); 使用多个纹理

使用函数glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &units);得到所有着色器阶段每次可访问的最大纹理单元数量 在这里插入图片描述

将纹理绑定到特定纹理单元

glBindTexture()只能将纹理绑定到glActiveTexture(GL_TEXTURE0 + i) 绑定的纹理点上。

void glBindTextureUnit( GLuint unit, //想要我们绑定的以零为基准的索引 GLuint texture);// // 方法1: glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding glBindTexture(GL_TEXTURE_2D, textures[i].id); // 方法2: glBindTextureUnit(i, textures[i].id); 着色器中的采样器统一变量引用不同单元

方法一:在程序中获取采样器地址,并为它设置引用单元数

glUniform1i(glGetUniformLocation(shader, name), unit);

方法二:在着色器代码中使用binding配置限定符设置。

layout(binding = 1) uniform sampler2D texture_diffuse1; mipmap 层数设置,数据输入,限制层数使用

mip贴图层通过如下函数输入2D纹理mipmap数据。

void glTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);

level参数指定图像数据应用于哪一层。

但在输入数据前,首先需要开辟对应层数的空间。 使用如下函数开辟纹理空间时,设置levels的值将确定该纹理有多少层。(0表示未使用mipmap)

void glTexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);

同时可以使用如下函数限制渲染过程中可使用的mip层。

glTextureParameteri(texture, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, 4); mip贴图过滤 GL_NEAREST GL_LINEAR GL_LEAREST_MIPMAP_NEAREST //选择最邻近的mip层,并执行最邻近过滤 GL_NEAREST_MIPMAP_LINEAR GL_LINEAR_MIPMAP_NEARSET GL_LINEAR_MIPMAP_LINEAR //在mip层之间使用线性插值并执行线性过滤(三线性插值) 构建mip层

使用glTexSubImage2D函数输入mipmap图其他层数不大方便,使用OpenGL构建纹理十分方便。

void glGenerateMipmap( GLenum target); void glGenerateTextureMipmap(GLuint texture); 如: glGenerateMipmap(GL_TEXTURE_2D);

但使用快速构建会一定程度影响程序运算速度,在性能关键型应用程序中需要优先考虑加载自己预先构建的mip贴图。

数组纹理

多个1D纹理可映射为1D数组纹理, 多个2D纹理、立方体纹理可映射为2D数组纹理, 不能创建3D数组纹理(OpenGL不支持)

2D数组纹理与3D纹理的区别

2D数组纹理的层之间不能进行过滤操作(线性过滤等),但2D数组纹理拥有比3D纹理更大的空间。

加载2D数组纹理 GLuint texture2Ds; glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &texture2Ds); void glTextureStorage3D( GLuint texture, //texture2Ds GLsizei levels, // GLenum internalformat, //内部格式 GLsizei width, GLsizei height, GLsizei depth); //数组元素 或 层 //输入数据 for(int i=0;i color = texture( texture2DArray, vec3( vec2(x,y), float(layer) ) ); //texture( 2D数组纹理采样器, vec3( vec2采样点, float(采样层数) ) ); }

注意:采样层数为整数,但在texture输入采样位置时,要转化为float值。

在着色器中向纹理写入数据 使用image变量表示纹理的单个图像 声明图像单元 uniform image2D my_image; 读取存储数据 //从P指定的坐标处读取image数据 vec4 imageLoad(readonly image2D image, ivec2 P); //将data的数据存入P指定的image中 void imageStore(image2D image, ivec2 P, vec4 data); 其他: 有符号整数数据(i)和无符号整数(u)数据图像的存取 ivec4 imageLoad(readonly iimage2D image, ivec2 P); void imageStore(iimage2D image, ivec2 P, ivec4 data);

注意:P为整数型,加载时不执行过滤(与textelFetch()函数一样)。

将纹理层绑定到图像单元 void glBindImageTexture( GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); 在着色器使用图像单元绑定的图像

rgba32ui为格式限定符,见书P125

layout (binding = 0 , rgba32ui) readonly uniform uimage2D image_in; layout (binding = 1) uniform writeonly uimage2D image_out; void main(){//将image_in 中的数据复制入 image_out ivec2 P = ivec2(gl_FragCoord.xy); uvec4 data = imageLoad(image_in, P); imageStore(image_out, P, ~data); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3