Ward BRDF实现心得
最近做了Ward BRDF的实现,相对于之前的lambert,phong来说,Ward是一个真正意义上的各向异性BRDF,但同样的,Ward模型也是一个基于经验的模型,并不是物理上正确的。它由ward本人于1992年在《Measuring and modeling anisotropic reflection》一文中首次提出,到目前为止它已经是图形学中广泛应用的一种BRDF了。有不少文章专门讲述了Ward的理论与实现,其中比较著名的是Bruce Walter在2005年写的《Notes on the Ward BRDF》,该文章从理论到实现都讲了一遍。我在做Ward实现的时候就主要参考了这篇文章。Ward的BRDF定义用到了half vector的概念,half vector定义为h=(wi+wo)/|wi+wo|,就是入射光向量与出射光向量求和再标准化。按照ward本人的描述,Ward BRDF有两个组成部分,一个是经典的漫反射部分ρd/π,另外一个部分有3个参数ρs,αx与αy。其实ρs就跟phong模型中的镜面反射系数是差不多的,而αx与αy控制了高光在x和y方向上的范围(也可以理解成表面在x和y方向上的粗糙程度)。当αx=αy的时候,该brdf描述的是一个各向同性的反射模型,其效果和phong很类似,反之则描述各向异性反射模型。接下来出场的是一个非常重要的函数:

f函数描述的是该表面上已知入射角向量i,那么得到出射角向量为o的概率是多少。由于BRDF具有对称性,所以反过来也是一样的,即已知出射角向量o,得到入射角向量为i的概率就是这个函数要求的东西。这其中的θi,θo,θh,Φh都是在表面局部坐标系下计算的,见下图:

(图中的向量v与z轴夹角写为θv,Φv则是v在平面xOy上的投影与x方向的夹角)
在表面局部坐标系下,z方向就是表面法线方向,x和y方向分别表示了表面的切向量和副法线向量方向(这其实是表面的切向空间,之前在介绍法线贴图的文章中已经讲过了,这里就不重复了,详情可以参考http://www.cnblogs.com/starfallen/archive/2013/03/29/2989277.html)。于是可以知道公式中的θi,θo,θh分别代表了入射向量i,出射向量o以及半角h与表面法向量的夹角,Φh则是h在物体表面上的投影与表面切向量的夹角。这里有一个必须要注意的问题,就是公式中的入射与出射向量i,o都是局部坐标系下的值,如果我们将世界坐标系中的相关向量带入进去则会出错。正确的做法是每次计算该公式前时做一次世界坐标系到局部坐标系的转换,在完成后再转换回去。所以这就是pbrt等开源构架在做bsdf采样的时候要求入射向量与出射向量都是基于局部坐标系下的原因。光有f函数显然是不够的,为了能使Ward BRDF应用在全局光照中,必须要能对其进行重要性采样,《Notes on the Ward BRDF》一文中详细介绍了其方法。Ward BRDF重要性采样的主要思想在于根据已知条件先确定半角h,再利用反射公式o=2*(i*h)h-i得到最终的出射向量。文中给出了h的具体求法:

其中u和v是两个不相关的0~1间的随机数,由于θh的公式中包含有Φh项,所以在实际计算的时候应当先算Φh。在计算Φh的时候,有一个必须注意的地方,就是要保证2πv和Φh在同一个象限,因为在程序设计时,我们通常用到的atan函数得到的结果是在-π/2~π/2之间的。
另外,在编写程序的时候,还有一个细节值得注意,那就是重要性采样函数在某些情况下得出的向量o可能不在法线一边,通俗地说就是光线与表面作用后穿透到物体内部去了。为了更好地说明这一现象出现的根源,我用一个示意图来解释它:

该图描述了在物体表面某处的各个向量的情况,绿色的向量z是表面法向量,红色的i是已知的入射向量,蓝色的h是随机采样得到的半角向量,由于h一定会与法向量z有一定夹角(那种h刚好与z重合的情况实在是太罕见了),那么就一定存在着采样得到的出射向量o位于法向量另一侧的情况(这种情况出现的几率随着i与z的夹角的增大而增大)。这一问题有很多处理方法,最简单的,也是我采用的方法是忽略这样的采样值,认为它被表面吸收了。实际上这样处理并不会导致错误,随着采样值的增多,最终结果会逐渐收敛到正确的解。在这个问题上,我们不用过多地担心,因为Ward模型本身是一个经验上的模型,并不保证物理上的正确性。实际上即使是phong模型,当入射角度与法线夹角很大的时候也会出现这种情况。
再说αx与αy两个参数,一般我们会在0-1之间取值,取值越大,得到的高光区域越大。如果说对于一个点光源,当αx=αy的时候,高光呈现圆形的话,αx≠αy时高光就是椭圆形的,而且αx与αy的比例越大,椭圆越扁。当αx与αy其中一项取值为1的时候,高光在这个方向上的范围为无限大(理论上如此,但实际上会受限于表面大小等因素)。下面一组图中我实验了比较有代表性的三种情况:

由此可见,我们可以很方便地调节这两个参数来模拟各类各向异性材质。实际上,Ward BRDF很适合被用来模拟各向异性高光,以及各向异性反射,比如各种磨光的金属表面。
最后,放上一张我渲染的含有Ward模型的结果:

Ward BRDF实现心得的更多相关文章
- Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF
在实时渲染中Physically-Based Rendering(PBR)中文为基于物理的渲染它能为渲染的物体带来更真实的效果,而且能量守恒 稍微解释一下字母的意思,为对后文的理解有帮助,从右到左L为 ...
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- NoSql数据库使用半年后在设计上面的一些心得
NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...
- 我的MYSQL学习心得(二) 数据类型宽度
我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(三) 查看字段长度
我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(四) 数据类型
我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(五) 运算符
我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...
- 我的MYSQL学习心得(六) 函数
我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(七) 查询
我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
随机推荐
- 替换空格-请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
class Solution { public: void replaceSpace(char *str,int length) { char *tmp; ; int i; ;i<length; ...
- 反射中使用 BindingFlags.IgnoreCase
我们经常需要通过反射来调用目标对象的方法或获取/设置目标对象的属性,Type.InvokeMember 方法签名如下: public object InvokeMember(string name,B ...
- Android一个大众化的设置界面
布局代码如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:an ...
- [CareerCup] 2.3 Delete Node in a Linked List 删除链表的节点
2.3 Implement an algorithm to delete a node in the middle of a singly linked list, given only access ...
- LeetCode-Decode String
Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...
- 证书与keytool
证书的来源与使用: 对数据进行签名是我们在网络中最常见的安全操作.签名有双重作用,作用一就是保证数据的完整性,证明数据并非伪造,而且在传输的过程中没有被篡改,作用二就是防止数据的发布者否认其发布了该数 ...
- Jenkins进阶系列之——14配置Jenkins用户和权限
今天给大家说说使用Jenkins专有用户数据库的配置,和一些常用的权限配置. 配置用户注册 在已运行的Jenkins主页中,点击左侧的系统管理—>Configure Global Securit ...
- brew-cask之本地安装应用
cask 固然好用,但是无奈很多资源在墙外,能下载的非常有限,就是能下载,也慢的要死.但是很多下载软件却可以下载这些资源,很奇怪,要么是有人FQ下载了,缓存到他们的服务器了,要么就是软件可以FQ下载. ...
- 编写高质量代码--改善python程序的建议(六)
原文发表在我的博客主页,转载请注明出处! 建议二十八:区别对待可变对象和不可变对象 python中一切皆对象,每一个对象都有一个唯一的标识符(id()).类型(type())以及值,对象根据其值能否修 ...
- Java学习笔记(四)——google java编程风格指南(上)
[前面的话] 年后开始正式上班,计划着想做很多事情,但是总会有这样那样的打扰,不知道是自己要求太高还是自我的奋斗意识不够?接下来好好加油.好好学学技术,好好学习英语,好好学习做点自己喜欢的事情,趁着自 ...