OpenGL 编程指南 (5.2)
1、使用纹理
GLSL从纹理中读取数据使用内置函数texture的多种重载方法
Gvec4 texture(gsampler1D, float texCoord[,float bias])
Gvec4 texture(gsampler2D, vec2 texCoord[,float bias])//这里开头的g代表的是任意类型的占位符,[]是可选参数
2、纹理坐标
一般是逐顶点提供纹理坐标,然后根据图元间的线段在光栅化对每个片元进行插值得到片元纹理坐标。纹理坐标的范围为[0.0, 1.0],超过这个范围有数种方式决定超出范围的纹理坐标如下:
1)GL_CLAMP_TO_BORDER 范围外使用指定的颜色,需要同时设置GL_TEXTURE_BORDER_COLOR的值
2)GL_CLAMP_TO_EDGE 超出的使用边界值
3)GL_REPEAT 循环使用[0.0, 1.0]纹理坐标
4)GL_MIRROR_REPEAT 循环轴对称地使用[0.0, 1.0]纹理坐标
另外,这些设置时每个通道分开的,GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T、GL_TEXTURE_WRAP_R(str对应于常用坐标系xyz)
3、组织纹理数据
纹理数据的存储可以采用不同于RGBA的分量存储顺序,如ARGB。因此OpengGL提供了swizzle作为与之相关的纹理参数。使用方法glTexParameterri,参数可以是GL_TEXTURE_SWIZZLE_R、GL_TEXTURE_SWIZZLE_G、GL_TEXTURE_SWIZZLE_B、GL_TEXTURE_SWIZZLE_A等,分通道指定,还可以使用glTexParameteriv与GL_TEXTURE_SWIZZLE_RGBA一次性指定所有通道。
static const Glenum abgr_swizzle[] = {GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE};
glBindTexture(GL_TEXTURE_2D, abgr_texture);
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, abgr_swizzle);
4、复杂纹理类型
1)3D纹理,拥有宽度与高度的同时还有深度,2D宽度与高度的最大值通过GL_MAX_TEXTURE_SIZE查询,3D的则是GL_MAX_3D_TEXTURE_SIZE。
2)纹理数组,可以将有相同大小的1D或2D纹理几何合并成下一个维度的纹理。如果用3D纹理存储2D纹理数组,那么在访问具体的某一2D纹理上会比较麻烦,如有3张纹理的数组,访问第二张时因为索引是r通道值域被限制在了[0.0, 1.0]中,那么需要的值是0.6667,而且3D纹理在纹理片之间进行的滤波并不是希望那样的。
3)立方体贴图,用于环境映射,是6个面以一个立方体6个面的位置关系进行分布的结构。在立方体映射中采样的时候,使用的纹理坐标是3D的,并且被看作是来自原点的方向。最为经典的应用为大名鼎鼎的天空盒啦。
4)阴影采样器纹理,它有一个附加分量是用来与取得的纹素值做比较的参考值,采样返回的是一个[0.0, 1.0]内表示通过比较操作得到的分数,要使用它还需要设置GL_TEXTURE_COMPARE_MOD等状态。
float texture(gsampler1DShadow tex, vec3 p[,float bias])
float texture(gsampler2DShadow tex, vec3 p[,float bias])
float texture(gsamplerCubeShadow tex, vec3 p[,float bias])
float texture(gsampler1DArrayShadow tex, vec3 p[,float bias])
float texture(gsampler2DArrayShadow tex, vec3 p)
float texture(gsampler2DArrayShadow tex, vec4 p[,float bias])
float texture(gsamplerCubeArrayShadow tex, vecP p, float compare)
5)深度模板纹理,从字面上理解就是纹理数据存储的是深度与模板信息,需要对应纹理格式GL_DEPTH_STENCIL
6)纹理缓冲,没有内置的采样器,不支持mipmaps与纹理坐标wrapping,纹理坐标使用的是未归一化的整形坐标。
glGenBuffers(1, &texbuf);
glBindBuffer(GL_TEXTURE_BUFFER, texbuf);
glBufferData(GL_TEXTURE_BUFFER, size, data, GL_STATIC_DRAW);
glGenTexture(1, &texture);
//glActiveTexture(GL_TEXTURE0);//这一步非必须,因为第一个纹理单元是默认激活
glBindTexture(GL_TEXTURE_BUFFER, texture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, texbuf);//将纹理缓冲对象与纹理关联
也有关联部分空间的方法
glTexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size)//offst必须是对齐大小的整数倍
在shader中有纹理缓冲有自己的解析函数,与采样器使用方法相似,需要有uniform的设置有纹理坐标作为参数
vec4 texelFetch(samplerBuffer sb, int coord);
ivec4 texelFetch(isamplerBuffer sb, int coord);
uvec4 texelFetch(usamplerBuffer sb, int coord);
5、纹理视图
OpenGL可以在多个纹理之间共享一个数据存储,每个都能够拥有自己的格式与维数。首先,创建一个纹理并初始化它的存储空间,接着创建父纹理 texture view
void glTextureView(GLuint texture, GLenum target, GLuint origTexture, GLenum internalFormat, GLuint minLevel, GLuint minLayer, GLuint numLayers)//为已经创建的origTexture创建纹理视图,将纹理格式兼容的texture关联到origTexture的存储空间上,其它的参数都是对texture的设置,internalFormat需要与origTexture的存储格式兼容,minLevel与numLevels是关于minmap的参数
6、纹理压缩
压缩主要分为有损无损两大类,现有的ETC、PVPTR等压缩算法均是有损压缩。使用压缩纹理有两种方式,提供原始数据OpenGL进行压缩,因为需要实时所有会使用快速算法使得质量低下;另外一种是提供已经压缩了的纹理数据。
void glCompressedTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const void* data)
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
void glCompressedTexImage3D(.......)
7、纹理滤波
使用坐标来从离散采样信号选择临近样本,并且使用原始信号的线性近似来代替这些信号的技术。......
8、点精灵
使用fragment shader渲染的点,运行时考虑点内的片元坐标,点内的坐标是一个二维向量gl_PointCoord,gl_PointCoord是相当精确的数值。