《OpenGL宝典》--纹理
文章目录
- 创建并初始化纹理
- 创建纹理
- 更新纹理数据
- 纹理目标和类型
- 从着色器中读取纹理数据
- 采样器类型
- 使用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, //texture2DsGLsizei levels, //GLenum internalformat, //内部格式GLsizei width,GLsizei height,GLsizei depth); //数组元素 或 层
//输入数据
for(int i=0;i<depth;++i){void glTextureSubImage3D( GLuint texture, GLint level,GLint xoffset, //0GLint yoffset, //0GLint zoffset, //层数GLsizei width, //图片宽GLsizei height, //图片高GLsizei depth, //如果输入为2D图形,depth = 1GLenum format, //输入数据的格式GLenum type, //输入数据的类型const void *pixels); //数据指针
}
使用数组纹理
layout (binding = 0) uniform sampler2DArray texture2DArray;
void main()
{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_outivec2 P = ivec2(gl_FragCoord.xy);uvec4 data = imageLoad(image_in, P);imageStore(image_out, P, ~data);
}
《OpenGL宝典》--纹理相关推荐
- 利用opencv读取图片将其作为opengl的纹理图片的实现方法
在opengl中实现三维物体的纹理贴图的第一步就是要读入图片,然后指定该图片为纹理图片.我最早接手的项目中是通过一个专门的读取bmp图片的函数来实现纹理图片的读取的.这个函数有三个缺点: 1.只能读取 ...
- OpenGL textures纹理的实例
OpenGL textures纹理 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include &l ...
- OpenGL渲染纹理和平面反射
OpenGL渲染纹理和平面反射 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL ...
- C++ Opengl 绘制纹理字符源码
C++ Opengl 绘制纹理字符源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SDK8.1, ...
- OpenGL:纹理Textures
参考资料:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/ 学习笔记,不一当作参考教程,上面的参考资料是比较 ...
- 【Modern OpenGL】纹理 Textures
说明:跟着learnopengl的内容学习,不是纯翻译,只是自己整理记录. 强烈推荐原文,无论是内容还是排版. 原文链接 本文地址: http://blog.csdn.net/aganlengzi/a ...
- android纹理存储,Android:OpenGL存储纹理多长时间?
openGL存储纹理多长时间? 离开活动时纹理内存是否会被回收? 例如,如果我有以下代码: mGL.glGenTextures(1, mTextures, 0); mGL.glBindTexture( ...
- OpenGL立方体纹理贴图
OpenGL正方体纹理贴图 0. 写在最前面 1. 正方体顶点属性构建 2. 绑定多个VAO.VBO 3. 创建多个纹理 4. 渲染循环 5. 实现代码 6. 多个立方体纹理贴图 0. 写在最前面 要 ...
- openCV读入图片,openGL实现纹理贴图
本文结合结合openCV,openGL的优点,实现混合编程. (1)OpenCV提供图形处理和计算机视觉方面的通用算法,读入二维图片很方便: (2)OpenGL是跨平台的图形程序接口,它用于二维,三维 ...
最新文章
- C++ 函数的模板的使用
- 二叉搜索树-创建最小高度树(递归)
- Visual Studio 15改进C++工程加载
- SharePoint Error - An unrecognized HTTP response was received when attempting to crawl this item
- 获取并编译linux源码,android获取源代码、编译、命令
- 解决delphi10.2.3 android tools闪退
- 什么是formal method的invarient
- 灾备理论-可靠的异地灾备
- SAP Spartacus Delivery Mode Component单元测试的Mock设计图
- 近300万记录的论坛还用这个分页存储过程
- 3d打印光固化好还是热固化好_UV专利一览(71) —天啦噜!3D打印上太空!
- Newtonsoft 六个超简单又实用的特性,值得一试 【上篇】
- [Robot Framework] Jenkins上调用Rebot命令时执行报错不往下执行其他命令
- Go-闭包和匿名函数讲解
- CentOS7 网络配置--NAT模式
- 如何刷新linux的fdisk,②linux fdisk
- ABB机器人切割铣削钻孔自动化加工应用
- 美容院店务管理系统帮助门店管理哪些方面 ?
- 苹果电脑如何改id?这篇文章帮你搞定
- (转)[原创]在ios android设备上使用 Protobuf (使用源码方式)
热门文章
- Lark XR 平行云-云渲染方案
- 66.网页设计你缺少的是像艺术家一样“偷窃”
- 用Python做一个超好玩的拼图游戏,0基础也能包你学会,附送超详细注释的源码~
- Katalon自动化测试框架
- 白领学python_python是职场白领必学的技能吗?
- CE修改Eternium永恒之金【基础篇】
- 【IC 10】差分输入;仪表放大器和运算放大器的区别 - 仪表放大器和运算放大器优缺点对比
- x86、x64、amd64和arm CPU 架构 MSVC的各种版本 Visual Studio的安装
- 复旦计算机学院2020推免,复旦大学管理学院2020年度专业硕士项目推免招生及“领创营”系列活动通知...
- 网站部署到其他服务器但无权修改,web项目部署到服务器遇到的问题