OPenGL-纹理

一常用函数

  1. 改变像素存储⽅方式
//改变像素存储⽅方式
void glPixelStorei(GLenum pname,GLint param);
//恢复像素存储⽅方式
void glPixelStoref(GLenum pname,GLfloat param);
//举例例:
//参数1:GL_UNPACK_ALIGNMENT 指定OpenGL 如何从数据缓存区中解包图像 数据
//参数2:表示参数GL_UNPACK_ALIGNMENT 设置的值
//GL_UNPACK_ALIGNMENT 指内存中每个像素⾏行行起点的排列列请求,允许设置为1 (byte排列列)、2(排列列为偶数byte的⾏行行)、4(字word排列列)、8(⾏行行从双字节 边界开始)
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  1. 从颜⾊色缓存区内容作为像素图直接读取
/参数1:x,矩形左下⻆角的窗⼝口坐标
//参数2:y,矩形左下⻆角的窗⼝口坐标
//参数3:width,矩形的宽,以像素为单位 //参数4:height,矩形的⾼高,以像素为单位
//参数5:format,OpenGL 的像素格式,参考 表6-1 //参数6:type,解释参数pixels指向的数据,告诉OpenGL 使⽤用缓存区中的什什么 数据类型来存储颜⾊色分量量,像素数据的数据类型,参考 表6-2 //参数7:pixels,指向图形数据的指针
void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei
height, GLenum format, GLenum type,const void * pixels);
glReadBuffer(mode);—> 指定读取的缓存 glWriteBuffer(mode);—> 指定写⼊入的缓存\
  1. 载⼊纹理
void glTexImage1D(GLenum target,GLint level,GLint
     internalformat,GLsizei width,GLint border,GLenum
     format,GLenum type,void *data);
void glTexImage2D(GLenum target,GLint level,GLint
     internalformat,GLsizei width,GLsizei height,GLint
     border,GLenum format,GLenum type,void * data);
void glTexImage3D(GLenum target,GLint level,GLint internalformat,GLSizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,void *data);
// target:`GL_TEXTURE_1D`、`GL_TEXTURE_2D`、`GL_TEXTURE_3D`。
// Level:指定所加载的mip贴图层次。⼀一般我们都把这个参数设置为0。
// internalformat:每个纹理理单元中存储多少颜⾊色成分。
// width、height、depth参数:指加载纹理理的宽度、⾼高度、深度。==注意!==这些值必须是 2的整数次⽅方。(这是因为OpenGL 旧版本上的遗留留下的⼀一个要求。当然现在已经可以⽀支持不不是 2的整数次⽅方。但是开发者们还是习惯使⽤用以2的整数次⽅方去设置这些参数。)
// border参数:允许为纹理理贴图指定⼀一个边界宽度。
// format、type、data参数:与我们在讲glDrawPixels 函数对于的参数相同

常用: glTexImage2D

  1. 更新纹理
void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum
    format,GLenum type,const GLvoid *data);
void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei
    width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);
void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint
    zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);

5.插入替换纹理

void glCopyTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsize
width);
void glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint x,
     y,GLsizei width,GLsizei height);
void glCopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint
     zOffset,GLint x,GLint y,GLsizei width,GLsizei height);
  1. 使⽤用颜⾊色缓存区加载数据,形成新的纹理理使⽤用
void glCopyTexImage1D(GLenum target,GLint level,GLenum
  internalformt,GLint x,GLint y,GLsizei width,GLint border);
void glCopyTexImage2D(GLenum target,GLint level,GLenum
  internalformt,GLint x,GLint y,GLsizei width,GLsizei
  height,GLint border);
  • x,y 在颜⾊色缓存区中指定了了开始读取纹理理数据的位置; 缓存区⾥里里的数据,是源缓存区通过glReadBuffer设置的。
  • 注意:不不存在glCopyTextImage3D ,因为我们⽆无法从2D 颜⾊色缓存区中获取体积 数据。

二 纹理对象

2.1 生成纹理对象
//1. 分配纹理对象
//指定纹理理对象的数量量 和 指针(指针指向⼀一个⽆无符号整形数组,由纹理理对象标识符填充)。 void glGenTextures(GLsizei n,GLuint * textTures);
//2. 绑定纹理理状态
//参数target:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//参数texture:需要绑定的纹理理对象
void glBindTexture(GLenum target,GLunit texture);

//3. 删除绑定纹理理对象
//纹理理对象 以及 纹理理对象指针(指针指向⼀一个⽆无符号整形数组,由纹理理对象标识符填充)。
void glDeleteTextures(GLsizei n,GLuint *textures);
//4. 测试纹理理对象是否有效
//如果texture是⼀一个已经分配空间的纹理理对象,那么这个函数会返回GL_TRUE,否则会返回GL_FALSE。 
GLboolean glIsTexture(GLuint texture);
2.2 设置纹理参数
glTexParameterf(GLenum target,GLenum pname,GLFloat param);
glTexParameteri(GLenum target,GLenum pname,GLint param);
glTexParameterfv(GLenum target,GLenum pname,GLFloat *param);
glTexParameteriv(GLenum target,GLenum pname,GLint *param);
参数1:target,指定这些参数将要应⽤用在那个纹理理模式上,⽐比如GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。 参数2:pname,指定需要设置那个纹理理参数
参数3:param,设定特定的纹理理参数的值
2.3 过滤方式
  1. 邻近过滤(GL_NEAREST)


    GL_NEAREST
  1. 线性过滤(GL_LINEAR)


    GL_LINEAR

二者比较


glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) //纹理理放⼤大时,使⽤用线性过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);///纹理理缩小时,使⽤用邻近过滤
2.4 设置环绕模式
环绕方式 说明
GL_REPEAT 对纹理的默认行为,重复纹理图像
GL_MIRRORED_REPEAT 和GL_REPEAT一样,但每次重复图片是镜像放置的
GL_CLAMP_TO_EDGE 纹理坐标会被约束到0和1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果
GL_CLAMP_TO_BORDER 超出的坐标为用户指定的边缘颜色
对比
/*参数1:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D 参数2:GL_TEXTURE_WRAP_S、GL_TEXTURE_T、GL_TEXTURE_R,针对s,t,r坐标 参数3:GL_REPEAT、GL_CLAMP、GL_CLAMP_TO_EDGE、GL_CLAMP_TO_BORDER
GL_REPEAT:OpenGL 在纹理理坐标超过1.0的⽅方向上对纹理理进⾏行行重复; GL_CLAMP:所需的纹理理单元取⾃自纹理理边界或TEXTURE_BORDER_COLOR. GL_CLAMP_TO_EDGE环绕模式强制对范围之外的纹理理坐标沿着合法的纹理理单元的最后⼀一⾏行行或者最后⼀一
列列来进⾏行行采样。 GL_CLAMP_TO_BORDER:在纹理理坐标在0.0到1.0范围之外的只使⽤用边界纹理理单元。边界纹理理单元是
作为围绕基本图像的额外的⾏行行和列列,并与基本纹理理图像⼀一起加载的。*/
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_S,GL_CLAMP_TO_EDGE); 
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);

常用数据格式

  1. 像素格式
常量 说明
GL_RGB 描述红、绿、蓝顺序排列的颜⾊
GL_RGBA 按照红、绿、蓝、Alpha顺序排列的颜⾊
GL_BGR 按照蓝、绿、红顺序排列颜⾊
GL_BGRA 按照蓝、绿、红、Alpha顺序排列颜⾊
GL_RED 每个像素只包含了⼀个红⾊分量
GL_GREEN 每个像素只包含了⼀个绿⾊分量
GL_BLUE 每个像素只包含了⼀个蓝⾊分量
GL_RG 每个像素依次包含了一个红色和绿色的分量
GL_RED_INTEGER 每个像素包含了一个整数形式的红⾊分量
GL_GREEN_INTEGER 每个像素包含了一个整数形式的绿色分量
GL_BLUE_INTEGER 每个像素包含了一个整数形式的蓝色分量
GL_RG_INTEGER 每个像素依次包含了一个整数形式的红⾊、绿⾊分量
GL_RGB_INTEGER 每个像素包含了一个整数形式的红⾊、蓝⾊、绿色分量
GL_RGBA_INTEGER 每个像素包含了一个整数形式的红⾊、蓝⾊、绿⾊、Alpah分量
GL_BGR_INTEGER 每个像素包含了一个整数形式的蓝⾊、绿⾊、红色分量
GL_BGRA_INTEGER 每个像素包含了一个整数形式的蓝⾊、绿⾊、红色、Alpah分量
GL_STENCIL_INDEX 每个像素只包含了一个模板值
GL_DEPTH_COMPONENT 每个像素只包含一个深度值
GL_DEPTH_STENCIL 每个像素包含一个深度值和一个模板值
  1. 像素数据的数据类型
常量 说明
GL_UNSIGNED_BYTE 每种颜色分量都是一个8位无符号整数
GL_BYTE 8位有符号整数
GL_UNSIGNED_SHORT 16位无符号整数
GL_SHORT 16位有符号整数
CL_UNSIGNED_INT 32位无符号整数
GL_INT 32位有符号整数
GL_FLOAT 单精度浮点数
GL_HALF_FLOAT 半精度浮点数
GL_UNSIGNED_BYTE_3_2_3 包装的RGB值
GL_UNSIGNED_BYTE_2_3_3_REV 包装的RGB值
GL_UNSIGNED_SHORT_5_6_5 包装的RGB值
GL_UNSIGNED_SHORT_5_6_5_REV 包装的RGB值
GL_UNSIGNED_SHORT_4_4_4_4 包装的RGB值
GL_UNSIGNED_SHORT_4_4_4_4_REV 包装的RGB值
GL_UNSIGNED_SHORT_5_5_5_1 包装的RGB值
GL_UNSIGNED_SHORT_1_5_5_5_REV 包装的RGB值
GL_UNSIGNED_INT_8_8_8_8 包装的RGB值
GL_UNSIGNED_INT_8_8_8_8_REV 包装的RGB值
GL_UNSIGNED_INT_10_10_10_2 包装的RGB值
GL_UNSIGNED_INT_2_10_10_10_REV 包装的RGB值
GL_UNSIGNED_INT_24_8 包装的RGB值
GL_UNSIGNED_INT_10F_11F_REV 包装的RGB值
GL_FLOAT_24_UNSIGNED_INT_24_8_REV 包装的RGB值

总结:

  1. 像素格式一般使用 GL_RGB | GL_RGBA
  2. 像素数据类型一般使用 GL_UNSIGNED_BYTE

Mip贴图

Mip贴图是一种功能强大纹理技巧,他可以提高渲染性能的同时可以改善场景的显示质量,
假设一下,一个包含着成千上万的大房间,每个物体都有纹理,有些物体会很远,但器纹理拥有与进出物体相同的分辨率,由于远处物体可能只产生很少的片段,OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难,因为它需要从一个跨过纹理很大部分的片段只拾取一个纹理颜色,在小物体上这会产生不真实的感觉,而且他们使用高分辨率纹理浪费内存.

OpenGL使用一种叫多级渐远纹理的概念来解决这个问题,简单来说就是一系列的纹理图像,后一个纹理图像是前一个二分之一,其实它很简单:距观察者的距离超过一定阈值,OpenGL会使用不同的多级渐远纹理,即最适合距离的那个,由于距离远,解析度不搞也不会备用户注意到,同事它性能还非常好,


多级渐远纹理

常见问题:

  1. 闪烁问题: 当屏幕上被渲染物体的表面与它所应用的纹理图像相比显得非常小,就会出现闪烁效果,类似闪光,当纹理图像采样取悦的移动幅度与它在屏幕大小相比显得不成比例时.也会发生这种现象,处于运动状态时,会比较容易出现闪烁的负面效果

  2. 性能问题,加载大的纹理内存并对他们进行过滤处理,单屏幕上世纪只是显示很少的一部分片段,纹理越大,这个问题所造成性能影响也越明显

解决这个问题就是 使用更小的纹理图像.但是这种解决方法又将产生一个新问题,就是当一个物体更靠近观察者时,它必须渲染的比原来的更大一些,这样,纹理就不得不拉伸,形成视觉效果很差的模糊或者斑驳状的纹理效果

从根本上解决这个问题就是使用Mip贴图,不是单独的把图像加载到纹理状态中,而是把一系列从最大到最小的图像加载到Mip贴图纹理状态,然后OpenGL使用一组新的过滤模式,为一个特定的几何图形选择最佳过滤效果的纹理.

Mip纹理由一系列纹理图像组成,每个图像大小在每个轴方向上都缩小一半,或者原来图像像素的四分之一,Mip贴图每个图像大小都依次见半,知道最后一个图像大小为1*1的纹理单元为止


Mip贴图
􏱀􏱁􏱕􏵢􏰕􏰖􏱀􏱁􏱕􏵢􏰕􏰖什么时候生成Mip贴图

只有minFilter 等于以下四种模式才可以生成Mip贴图

  • GL_NEAREST_MIPMAP_NEAREST 􏴹􏱦􏳝􏰵􏳞􏱊􏰜􏱇􏱡􏴏􏵣􏳰􏳱􏰰􏱟􏳝􏰵􏵤具有非常好的性能,并且闪烁现象非常弱
  • GL_LINEAR_MIPMAP_NEAREST 􏰵􏰵􏰶􏲐􏲧􏵥􏵦􏴐􏴑􏰼􏵧􏱡􏱎􏲱􏰶􏲶􏱒􏱜􏱝􏱊􏵨 􏰜􏰞􏰟􏵩 尝尝用于游戏进行加速,使用了高质量的限行过滤器
  • GL_LINEAR_MIPMAP_LINEAR 􏵗 和 GL_NEAREST_MIPMAP_LINEAR 􏰞􏰟􏵩􏲫过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹
  • GL_LINEAR_MIPMAP_LINEAR三线性Mip贴图,纹理过滤的黄金准则,具有最高的精度
if(minFilter == GL_LINEAR_MIPMAP_LINEAR || 
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
 minFilter == GL_NEAREST_MIPMAP_LINEAR || 
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//4.􏰨􏰩􏰕􏰖􏳮􏱦􏱊Mip􏵌 //􏵈􏰌􏳆GL_TEXTURE_1D􏵸GL_TEXTURE_2D􏵸GL_TEXTURE_3D 
glGenerateMipmap(GL_TEXTURE_2D);
常量量 描述
GL_NEAREST 在Mip基层上执⾏行行最邻近过滤
GL_LINEAR 在Mip基层执⾏行行线性过滤
GL_NEAREST_MIPMAP_NEAREST 在最邻近Mip层,并执⾏行行最邻近过滤
GL_NEAREST_MIPMAP_LINEAR 在Mip层之间执⾏行行线性插补,并执⾏行行最邻近过滤
GL_LINEAR_MIPMAP_NEAREST 选择最邻近Mip层,并执⾏行行线性过滤
GL_LINEAR_MIPMAP_LINEAR 在Mip层之间执⾏行行线性插补,并执⾏行行线性过滤,⼜又称三线性Mip贴图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341