热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenGL蓝宝书源码学习(十)第五章——纹理的应用、Mip贴图、各项异性过滤和纹理压缩基础

一、纹理应用1、纹理坐标我们是通过为每个顶点指定一个纹理坐标而直接在几何图形上进行纹理贴图的。纹理坐标要么是指定为着色器的一个属性,要么通过算法计算出来。纹理贴图中的纹理单元是作为一个更加抽象的纹理坐

一、纹理应用

1、纹理坐标

我们是通过为每个顶点指定一个纹理坐标而直接在几何图形上进行纹理贴图的。纹理坐标要么是指定为着色器的一个属性,要么通过算法计算出来。纹理贴图中的纹理单元是作为一个更加抽象的纹理坐标,而不是作为内存位置进行寻址的。典型情况下,纹理坐标作为0.0到1.0范围内的浮点值指定的。纹理坐标命名为s、t、r和q,支持从一维到三维的纹理坐标,并且可以选择一种对坐标进行缩放的方法。q是一个缩放因子,作用于其他纹理坐标。一个纹理坐标会在每个顶点上应用一个纹理。然后,OpenGL根据需要对纹理进行放大或缩小,将纹理贴图到几何图形上。通过下图理解:


纹理的角对应于几何图形的角。

2、纹理参数

通过glTexParameter函数和其中的参数变量来设置纹理参数,来影响渲染的规则和纹理贴图的行为。


target指定这些参数将要应用在哪个纹理模式上,它可以是GL_TEXTIRE1D、GL_TEXTIRE2D、GL_TEXTIRE3D。

pname指定需要设置哪个纹理参数。

param或params用于设置特定的纹理参数的值。

1)基本过滤

纹理图像中的纹理单元和屏幕上的像素几乎从来不会形成一对一的关系。但是,也确实可以实现这个效果,需要在对几何图形进行纹理贴图时进行精心的计划,使出现在屏幕上的纹理单元和像素能够对齐。因此,当纹理应用于与几何图形的表面时,纹理图像不是不是被拉伸就是被收缩。根据一个拉伸或收缩的纹理贴图计算颜色片段的过程称为纹理过滤。

放大过滤参数:GL_TEXTURE_MAG_FILTER

缩小过滤参数:GL_TEXTURE_MIN_FILTER

最邻近过滤器:GL_NEAREST

线性过滤器:GL_LINEAR。

确保总是为GL_TEXTURE_MIN_FILTER选择这两种过滤器中的一种,因为默认的过滤器不适用于Mip贴图

纹理坐标总是根据纹理图像的纹理单元进行求值和绘图的。不管纹理坐标位于哪个纹理单元,这个纹理单元的颜色就作为这个片段的纹理颜色。

例如,使用glTexParameter函数,为放大和缩小过滤器设置纹理过滤器


线性过滤器并不是把最邻近的纹理单元应用到纹理坐标中,而是把这个纹理坐标周围的纹理单元的加权平均值应用到这个纹理坐标上(线性插值)。为了让这个插值的片段与纹理单元的颜色准确匹配,纹理坐标需要准确地落在纹理单元的中心。


2)纹理环绕

正常情况下,在0.0到1.0的范围之内指定纹理坐标,使他与纹理贴图的纹理单元形成映射关系。如果纹理坐标落在这个范围之外,OpenGL则根据当前纹理环绕模式处理这个问题。可以调用glTexParameteri函数,并分别使用GL_TEXTURE_WARP_S、GL_TEXTURE_WARP_T或GL_TEXTURE_WARP_R作为参数,为每个坐标分别设置环绕模式。环绕模式设置如下:

GL_REPEAT:重复模式。在纹理坐标值超过1.0的方向上对纹理进行重复。在重复模式中,相当于环绕到纹理的另一边。对于沿物体环绕并与另一边吻合的纹理(例如球体),这种模式是相当完美的。

GL_CLAMP:截取模式。典型的应用就是在必须对一块大型区域进行纹理处理时。

二、Mip贴图

Mip贴图时一种功能强大的纹理技巧,他不仅可以提高渲染性能,而且可以改善场景的显示质量。它使用标准纹理贴图处理两个常见的问题,从而实现上述目标。

问题1,闪烁:当屏幕上被渲染的物体的表面与它所应用的纹理图像相比显得非常小时,就会出现这种效果。闪烁可以看成是某种类型的闪光,当纹理图像的采样区域的移动幅度与它在屏幕上的大小相比显得不成比例时,就会发生这种现象。当照相机或物体处于运动状态时,很容易看到闪烁的负面效果。

问题2,和性能有关,原因和闪烁相同。即问题的根源在于它必须加载大量的纹理内存并对他们进行过滤处理,但屏幕上实际显示的只是很少的一部分片段。

从本质上说,不是把单个图像加载到纹理状态中,而是把一系列从最大到最小的图像加载到单个“Mip贴图”纹理状态。Mip贴图纹理由一系列纹理图像组成,每个图像大小在每个轴的方向上都缩小一半,或者说是原来图像像素总数的四分之一。

Mip贴图层是通过glTexImage函数加载的。level参数可以发挥它的作用了,它指定了图像数据用与哪个Mip层。第一层是0,接着是1、2,以此类推。如果Mip贴图未被使用,那么他就只有第0层被加载。默认情况下,为了使用Mip贴图,所有的Mip层都必须被加载。但是,可以使用GL_TEXTURE_BASE_LEVEL和GL_TEXTURE_MAX_LEVEL纹理参数特别设置需要使用的基层和最大层。

例如,如果想指定只加载第0层到第4层,可以像下面一样调用glTexParameter函数两次:


但是,也可以使用GL_TEXTURE_MIN_LOD和GL_TEXTURE_MAX_LOD参数限制已加载的Mip层的使用范围。

1、Mip贴图过滤

Mip贴图在两个基本的纹理过滤模式GL_NEARSET和GLLINER上添加了一个新的变化,这是通过向Mip贴图过滤模式提供4中不同变化实现的。下面列出:


我们必须指定下面4个的其中一个Mip贴图过滤器,这样才能使用所有已加载的Mip层。上面两个只能使用纹理贴图的基层。

2、生成Mip层

对纹理的Mip层进行预先计算会得到最好的结果,同时让为我们生成纹理是非常方便的,也是比较普遍的方式。一旦通过glGenerateMipmap函数加载了第0层,就可以为纹理生成所有的Mip层了。

void glGenerateMipmap(GLenum target);

目标参数可以是GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D、GL_TEXTURE_CUBE_MAP、GL_TEXTURE_1D_ARRAY或GL_TEXTURE_2D_ARRAY。

在运行过程中生成Mip贴图通常比预加载创建的Mip贴图要慢,所以要加载自己预先生成的Mip贴图。

三、各向异性过滤


应用各向异性过滤需要3个步骤:

1、必须确认这种扩展是得到支持的。可以使用glTools函数gltExtensionSupported完成这个任务。

if(gltIsExtSupported("GL_EXT_texture_filter_anisotropic"))

2、在确认扩展得到支持只后,就可以查询得到支持的各向异性过滤的最大数量。

GLfloat fLargest;

glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&fLargest);

各向异性过滤所应用的数量越大,沿最大变化方向(沿最强的观察点)所采样的纹理单元就越多。

3、设置想要应用的各向异性过滤的数量

glTexParameter(GL_TEXTURE_2D,GLTEXTURE_MAX_ANISOTROPY_EXT,fLargest)

各向异性过滤是以每个纹理对象为基础进行应用的,就像标准过滤参数一样。在Anisotropic.cpp的源码示例中在仔细地学习一下。

四、纹理压缩

纹理贴图可以在3D渲染场景中增加令人难以置信的逼真性,但是它们需要大量的内存来存储和处理纹理。所以OpenGL添加了对纹理压缩的本地支持。可以使用GL_ARB_texture_commpression字符串来测试这个扩展是否得到支持。

1、压缩纹理

为了利用OpenGL对压缩纹理的支持,纹理数据一开始并不需要进行压缩。可以在加载一幅纹理图像时请求OpenGL对他进行压缩,这是通过在glTexImage函数中把internalFormat参数设置为下边的任意一个值:


可以使用glGetTexLevelParameteriv函数(以GL_TEXTURE_COMPRESSED为参数)来判断这个纹理是否被成功压缩。

GLint compFlag;

glGetTexLevelParameteriv(GL_TEXTURE2D,0,GL_TEXTURE_COMPRESSED,&compFlag);

它接受下表的参数:


2、加载压缩纹理

用glGetCompressedTexImage函数提取经过压缩的数据并把它保存到磁盘中。在后续的纹理加载中,可以使用原始压缩数据,从而极大地提高纹理的加载速度。

为了加载预先经压缩的纹理数据,可以使用下列函数之一。


这些函数实际上与前一章的glTexImage函数等同,仅有的区别是这些函数的internalFormat参数必须指定一种受到支持的压缩纹理图像格式。

另外还有一组对应的glCompressedTexSubImage函数,用于更新已经加载的纹理,它们与glTexSubImage的功能相当。

注意:纹理压缩方法的选择(或选择不使用纹理压缩)可能极大地依赖于底层图像的本质。

五、小结

至此,第五章大概的知识点和概念的介绍就到此为止,后面还是进行第五章源码示例的解析学习,当然在源码的学习过程中,还要反复地查看纹理的基础知识以加深对纹理在3D渲染的应用。


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
author-avatar
盼抽淡了烟的悲伤
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有