法线贴图是目前游戏开发中最常见的贴图之一。我们知道,一般情况下,模型面数越高,可以表现的细节越多,效果也越好。但是,由于面数多了,顶点数多了,计算量也就上去了,效果永远是和性能成反比的。怎么样用尽可能简单模型来做出更好的效果就成了大家研究的方向之一。纹理映射是最早的一种,通过纹理直接贴在模型表面,提供了一些细节,但是普通的纹理贴图只是影响最终像素阶段输出的颜色值,不能让模型有一些凹凸之类的细节表现。而法线贴图就是为了解决上面的问题,给我们提供了通过低面数模型来模拟高面数模型的效果,增加细节层次感,效果与高模相差不多,但是大大降低了模型的面数。

凹凸贴图和纹理贴图非常相似。然而,纹理贴图是把颜色加到多边形上,而凹凸贴图是把粗糙信息加到多边形上。这在多边形的视觉上会产生很吸引人的效果。

粗糙信息的表示有很多方式,下面重点介绍几种常见的方式:

1、Bump Mapping 凹凸贴图

凹凸贴图在计算机图形领域中的研究,最早开始于70年代末,至今已经有接近50年历史了。

凹凸图里存储的是物体表面的高度值(比如木材,做石头,脱了漆的墙面,),本质上是灰度图,这种贴图都是灰白的,如果节省空间的话,甚至可以把贴图的Alpha通道征用来用作Bump。

渲染时候根据这些高度值来计算法线方向(有多种计算方法),进而再根据法线方向计算物体表面的亮度值(有多种计算方法),从而使物体表面出现亮暗分布,给人一种凹凸不平的视觉感受。这其实是一种对人眼进行欺骗的伪凹凸效果。

至于为什么会感觉出凹凸来这个就是人的眼睛自己骗自己了……其实那里本没有凹凸的,但是我们人眼睛太多管闲事了。就像Windows的按钮哪个纯平面的东西我们还以为是凸出来的呢。

下图坐标是效果图,右边是凹凸贴图。

2、Normal Mapping 法线贴图

相对于Bump Mapping,直接省去了从高度图生成法线图的过程。现在很多软件都支持从高精度模型中生成法线图。

Normal Map最大的也是最明显的缺点应该就是它的视角问题。因为Normal Map只是改变的表面上的光照结果,并没有改变表面上的形状。因此,表面上看来,似乎只要是不接近水平,NormalMap就不会有视角问题。其实不然,NormalMap因为不能实现自身内部的遮挡,因此不能表现平面上凹凸起伏比较大的场合。比如说我们一个桌面上突出一块,然后在突出的这块东西边上放一支牙签。如果用Normal Map表现,会发现。根据经验,这个凸起会很轻易的挡住我们的视线,让我们看不见那支牙签。可是Normal Map却不会这么做。因此我们一直能看见障碍物背后的东西,这一点是个问题--也就是说只有在垂直于平面的时候NormalMap才会发挥最好的作用。这样一来,Normal Map只能用在大家对遮挡关系不敏感的场合,比如场景等,不是不能用于人物,而是用Normal Map的人物不太经得起特写,放大了,角度刁钻了都容易穿帮。

法线贴图只能在明暗效果上作假(模拟凹凸),无法控制表面的凹凸程度。

上面的是一张用了法线贴图的地面,在红色圆圈的地方是有问题的。我们使用一张平面图来分析下。

这是一张凸起砖块的截面图,绿色箭头表示视线的方向,白色线条表示砖块的横截面。按照常识来看,我们能看到砖块的最远的一点是蓝色点,因为蓝色点后面(红色线条部分)的砖块由于高度较低,被前面挡住了。但是从上面那张使用了法线贴图的地面效果图上可以看到,蓝色点后的砖块并没有被挡住,甚至能够看到黄色点的位置,这种效果显然是不正确的。而这是法线贴图无法避免的问题,因为上文已经说过了,法线贴图只能模拟明暗,也就是说最多只能将红色线条部分变暗(以此来模拟背光)。

为什么Normal Map会是蓝兮兮的?首先,我们知道如果在一个物体表面,法线垂直向上,那么它的XYZ坐标是多少?是0,0,1对不对?然后我们把这个数字按照我们前面所说的压缩方法进行压缩,每个数字加1然后再除以2(从[-1,1]映射到[0,1]),那么我们得到的是0.5,0.5,1对不对?好我们把它代入到RGB中,那么我们会得到128,128,255对不对?好了,试试看在调色板里的颜色吧!

3、Parallax mapping(又称为 Offset Mapping) 视差贴图

视差贴图是一种NormalMapping算法的增强算法,其本质上和NormalMapping没有区别。优势是只需要增加3个HLSL语句和一个控制纹理通道(只需要几个GPU指令,代价小到可以忽略)就可以显著的增加物体表面的深度感。但是NormalMap中出现的问题,Parallax mapping基本上都有--特别是视角接近平行的时候,凹凸感消失的问题,并没有明显改善。

控制纹理的范围很大,除了NormalMap还有很多,比如说Nvidia的DEMO曾经用纹理存储物体表面在阳光下的色彩变化规律。

这就是视差贴图可以解决法线贴图的问题,它可以让背面被遮挡住的部分完全不显示出来,除此之外还能在一定范围内调整砖块凹凸的程度。视差贴图也只是模拟作假,并没有真的改变模型表面,下面就开始分析视差贴图吧。

如图所示,视线 e 落点是点 a,但是因为模型并不是真的有凹凸,而是一个平面,所以真实的落点是在点 b。这样就变成了如何将点 a 纠正到点 b 的问题了。让我们再在参考图上加上一些辅助参数。

需要说明的是我们在分析视差贴图的时候使用的是切线空间,这和法线贴图是一样的,切线空间中的切线和副切线是与纹理坐标 uv 对齐的,上图中只显示了 u 方向上的情况,在 v 方向上是一样的。当前实际的落点是点 b,u 坐标是 ub,而理想的落点是在点 a,u坐标是 ua。如果能有一个 delta 量,把 ub 加上 delta 等于 ua,似乎就可以了。但是还有个问题是,因为视线的方向是一直在变化的,这就导致了 delta 量不可能是一个固定的值。所以暂且没有什么好的办法求出 delta,那么就把问题想简单点。这里不要求精确的 delta,只要近似的就可以。于是有了一张称为高度图的纹理,它存储了点 b 在切线空间的真实凹凸表面的凹陷或凸起程度。黑色(0)表示不凸起,白色(1)表示完全凸起。我们可以试着使用这个值来最大可能的近似模拟出 delta 值。

效果如下图

4、Displacement mapping 位移贴图

视差贴图和法线贴图都是使用特定的手段来达到欺骗视觉的目的,让人以为物体的表面是凹凸起伏的。而位移贴图却是真的将模型的顶点进行偏移,在原本的平面上创造出凹凸的效果。既然是对顶点进行偏移,那么就需要模型有足够多的顶点数量,否则达不到比较好的效果。为了达到足以置换的顶点数量,一般会使用 Tessellation 技术来增加低模的面数。查阅了相关资料,Tessellation 是 DirectX11 才有的技术,OpenGL 要到 4.0 才能使用。

顶点偏移后需要重新计算法线。

模型顶点的法线 置换顶点后错误的法线 置换顶点后正确的法线

具体流程是这样的。首先,根据屏幕的分辨率,在模型的可见面上镶嵌和最终象素尺寸相同的微多边形。这个过程叫做镶嵌。然后读取一张Bump贴图。根据表面的灰度确定高度。然后根据镶嵌所得到的多边形,沿着原先的表面法线方向移动微多边形。接着再为新的多边形确定好新的法线方向。此时,物体的表面确实已经真的增加出了细节。

相比来说位移贴图在效果上是没有任何瑕疵的,但是也未必没有缺点。首先就是,对硬件的要求很高,必须支持ShaderMode3.0才可以,因为只有支持SM3才可以在顶点阶段进行纹理操作。同时镶嵌对于性能的消耗也不小。不过其实就对于GPU的压力而言,反而似乎要更合理一些(因为对顶点的运算要求提高,对象素级别的运算要求反而没有影响)想必在将来的DX10统一渲染构架中会更有价值。

5、Relief Mapping 浮雕纹理贴图

其实就只是Offset Mapping的精确版本,运用光线追踪计算出近似的交点而已。

OM很快,因为OM计算纹理偏移只是简单的把当前点的高度乘以观察方向就够了,但是RM不是,RM需要在一个循环内逐个高度的测试,看所测试的高度是否接近相交点的高度。OM只需要两次纹理寻址,而RM需要6次(效果一般般)以上。由此使得RM的效率实在不能恭维。

从图中可以看出:最上层的高度值为1,最下层的高度值为0,对中间值划分为四等分(划分得越细,最终计算出来的精度就越高,效果也就越好,当然计算量也越大),这些值和高度图中的值是对应的。视线 e 会和等分线产生交点(红点),直接使用交点的 uv 对高度图进行采样,会得到对应的几个高度值(蓝点)。最理想的情况下计算出来的结果是正好在黄点上,观察下红点和蓝点,在黄点左边的蓝点高于红点,在黄点右边的红点高于蓝点,我们可以通过这个规律找到位于黄点两边最近的两个红点和蓝点。这样就可以确定黄点就在这两个红点的中间。最后,沿着 e 的方向,在这两个红点之间进行插值,即可获得黄点的位置了,而插值需要用到 h1 和 h2 这两个线段的长度(红蓝两点的间距)。差值的精确度和一开始划分的精细度有关。这就是原理描述了。

6、Parallax Occlusion Mapping 视差遮蔽贴图

参考文章https://segmentfault.com/a/1190000003920502

7、Cone Mapping 圆锥跟踪贴图

openGL之API学习(五十五)凹凸贴图技术相关推荐

  1. windows内核开发学习笔记十五:IRP结构

    windows内核开发学习笔记十五:IRP结构   IRP(I/O Request Package)在windows内核中,有一种系统组件--IRP,即输入输出请求包.当上层应用程序需要访问底层输入输 ...

  2. Java学习 第十五天

    Java学习 第十五天 第一章 StringBuilder类 1.1 字符串的不可变 1.2 StringBuilder概述 1.3 构造方法 1.4 两个常用方法 1.4.1 append方法 1. ...

  3. python数据挖掘学习】十五.Matplotlib调用imshow()函数绘制热图

    python数据挖掘学习]十五.Matplotlib调用imshow()函数绘制热图 #2018-03-28 14:47:19 March Wednesday the 13 week, the 087 ...

  4. 花书+吴恩达深度学习(十五)序列模型之循环神经网络 RNN

    目录 0. 前言 1. RNN 计算图 2. RNN 前向传播 3. RNN 反向传播 4. 导师驱动过程(teacher forcing) 5. 不同序列长度的 RNN 如果这篇文章对你有一点小小的 ...

  5. JavaScript学习(五十五)—组合继承

    JavaScript学习(五十五)-组合继承 组合继承:就是借用构造方法继承和原型链继承的组合形式

  6. JavaScript学习(十五)—内部样式与外部样式的修改与设置

    JavaScript学习(十五)-内部样式与外部样式的修改与设置 (一).行内样式 获取方式:元素节点.style.CSS属性名称: 注意:如果CSS属性中包含"-",那么需要采用 ...

  7. python复制指定字符串_python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)...

    python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...

  8. BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略)

    BT源代码学习心得(十五):客户端源代码分析(下载过程中的块选取策略) 发信人: wolfenstein (NeverSayNever), 个人文集 标  题: BT源代码学习心得(十五):客户端源代 ...

  9. java学习记录十五:集合二Collections、Set、Map

    java学习记录十五:集合二 一.Collections工具类 一.解释 二.常用方法 1.打乱集合顺序 2.按照默认规则排序 3.按指定规则排序 4.批量添加元素 二.可变参数 一.解释 二.写法 ...

  10. python学习[第十五篇] 文件系统

    python学习[第十五篇] 文件系统 对文件系统访问大多数都通过os模块实现. os 模块文件/目录访问函数 文件处理 mkfifo() 创建命名通道只用于linux remove(path)/un ...

最新文章

  1. binary_crossentropy(二元交叉熵)的定义
  2. linux 网络传输压塑文件,萌新的Linux学习之路(十一)文件压缩传输
  3. vb与S7200PLC通信源代码下载
  4. java删除不,Java文件不能删除,该怎么解决
  5. JSF, MyFaces, RichFaces 和 Facelets的区别
  6. python classmethod_对Python中的@classmethod用法详解
  7. python在函数内部有没有办法定义全局变量_主函数内部的全局变量python
  8. Raid及mdadm命令
  9. linux 安装simg2img,linux可执行文件执行时提示No such file or directory(docker环境中运行的ubuntu镜像)...
  10. NodeJS基础2---1 Promise小球运动
  11. MVC中Action参数绑定的过程
  12. 基于JAVA实现的WEB端UI自动化 -自动化测试简单介绍
  13. php 网站的多语言设置(IP地址区分国内国外)
  14. WORD打印出现错误,未定义书签.
  15. Linpack安装测试流程记录
  16. unlikely和likely的使用
  17. C语言教程-main函数
  18. c# 游戏设计:地图移动
  19. 组态王上位机西门子1200PID温度PID恒压
  20. Android 关于wifi管理的代码

热门文章

  1. Windows系统win10系统磁力种子文件下载软件推荐
  2. 站在两个世界的边缘——知无崖
  3. mysql计算1000天后的日期_Mysql中常用的日期函数
  4. 支付业务与技术架构学习总结(10)——第三方支付账务系统论述
  5. PCIe数据卡设计资料第611篇:基于VU9P的双路5Gsps AD 双路6Gsps DA PCIe数据卡
  6. key too large to index, failing 3346解决
  7. 巴别鱼雏形,谷歌推出端到端语音翻译技术,还能模仿你说话
  8. SOT-23三极管、MOS管、LDO封装对应图汇总
  9. 手机拍证件照的工具哪个好用
  10. WinEdit 的algorithm2e包自定义一个带竖线的模块代码