上一篇介绍了球谐函数的一些原理和性质,本篇主要介绍如何实现球谐光照,将这种光照应用到实际的场景中去。

我们知道,球谐光照实际上就是将周围的环境光采样成几个系数,然后渲染的时候用这几个系数来对光照进行还原,这种过程可以看做是对周围环境光的简化,从而简化计算过程。因为如果按照采样的方法进行渲染,每次渲染的时候都得对周围环境采样,从而都会耗费大量的计算时间。所以球谐光照的实现可以分成两个部分,一是环境光贴图的采样和积分运算,生成球谐参数,二是利用球谐参数对模型进行渲染。

采样器

采样是从环境光上面采,而环境光我们可以用环境光贴图表示。环境光贴图则可以采用cubemap的形式,也就是上一篇里面十字状的贴图,不过这里我们为了方便,把cubemap分成6个面,分别表示一个立方体的正x、负x、正y、负y、正z、负z。有了这六个贴图,通过一种映射关系,我们就能知道空间中的一点周围各个方向的光照值。具体的映射方法可以参考cubemap的wiki页面:https://en.wikipedia.org/wiki/Cube_mapping

知道了每一个方向的光照值,要进行采样,还需要计算出球谐基。球谐基实际上相当于某个方向上分量的多少,多个球谐基在不同的方向上分量不同,所以才能够利用球谐基和球谐参数进行光照的还原。球谐基的计算方法,上一篇已经给出,例如,前四个分量的球谐基实际计算过程如下:

 
basis[] = .f / .f * sqrt(.f / PI);
basis[] = sqrt(.f / (.f*PI))*y / r;
basis[] = sqrt(.f / (.f*PI))*z / r;
basis[] = sqrt(.f / (.f*PI))*x / r;

这样,每采样到一个像素,就计算相应的球谐基,并且对像素与对应的球谐基相乘后再求和,这样就相当于每个球谐基在所有像素上的积分。不过,为了得到球谐基上的平均光照强度,还需要将积分得到的数值乘以立体角并且除以总像素。简单说来就是运用这个公式求得球谐系数:

至于具体的实现,可以借助opencv,读取图片上的各个像素。值得注意的是,因为环境光贴图往往比较大,比如我选用的贴图每张大小为2048*2048,这样如果全部一次性读入内存的话将会导致程序运行内存占用过大,从而导致分配内存失败。针对这个问题,一个比较好的方式是传入一个函数对象给环境光采样器,这样环境光采样器每采到一个像素就立即调用函数对象处理。这样的话,就能把球鞋系数积分器实现成一个函数对象,传递给环境光采样器,最后再从球谐系数积分器函数对象里面取出计算出的球谐系数即可。这样可能会损失一些性能,因为需要频繁调用函数对象,然而这种性能损失是完全可以忽略的,首先对于一组环境光贴图,只需要运行一次采样器就能得到球谐系数,运行时间长短不是很重要,其次是采样过程中需要对外部数据进行频繁访问,所以瓶颈主要在于IO方面。

渲染器

我们现在只考虑环境光对一个物体的光照影响,不去考虑自阴影等问题,所以场景很简单:一个贴上环境光贴图的天空盒和一个位于中心位置的模型。有一点值得注意的是,我们是使用球谐参数来对模型进行着色,而不会涉及到天空盒,天空盒只是为了可视化对比的方便而已。对于模型上的每一点,需要知道对应的法向量,这样就能计算出对应的球谐基,然后用下列公式进行光线的还原:

还原出来的亮度值L即为该点的光照。当然这里只是最简单的光照模型,其BRDF的入射光可以看做是垂直入射的,而出射光强度与入射光相同,并且各个方向也相同,也就是对于模型的每一个顶点,其光照值与观察点无关。

具体的实现可以采用OpenGL,并且在我实现的过程中,使用了Cinder来简化一些模型加载和初始化等繁琐的操作,只注重于光照模型的实现。程序的主要过程如下:

1. 纹理和模型的加载

2. 相机、模型、shader的初始化

3. 绘制

重点就在于shader的实现。光照的shading部分应该放在fragment shader里面,实现球谐光照需要两个部分的参数,一个是法向量,另一个是球谐光照参数。法向量首先从vbo(顶点缓冲对象)传入,由vertex shader进行接收并传递给fragment shader。球谐光照参数则通过OpenGL的uniform方式传递一个大小为16的vec3数组。然后fragment shader利用法向量首先计算出球谐基,渲染过程的球谐基计算方法与采样过程一致,利用这些球谐基再与球谐系数进行光照的还原,从而就能得到每个点的亮度值了。具体的实现参考源代码中的assets/sh_lighting.vert。

此外为了方便观察,需要添加一些交互式操作,这些Cinder里面都提供了相应的IO接口,通过旋转移动相机位置,从而可以实现视角的变化。

光照渲染结果

程序实际运行效果如下:

从程序运行的情况上看,效果比较理想。模型的各个面的朝向可以大致反映出该方向的光照情况,并且从整体上看,模型与周围的天空盒融合得比较好,达到了一定的真实感。

总结

利用球谐光照,能够很好的对空间中一个模型所受到的环境光进行采样和还原。特别是在复杂的场景当中,如果依靠实时的环境光采样,以现在硬件水平的计算能力是达不到实时的。而如果采用球谐函数进行预计算,然后在实时渲染中进行光照的还原,则可以兼顾效率与光照效果。

源代码: https://github.com/lianera/SphericalHarmonicsLighting

下载可执行文件

球谐光照(Spherical Harmonics Lighting)及其应用-应用篇的更多相关文章

  1. 球谐光照(Spherical Harmonics Lighting)及其应用-实验篇

    简介 之前在一篇实时深度图优化的论文中看到球谐光照(Spherical Harmonics Lighting)的应用,在查阅了许许多多资料之后还是无法完全理解,我个人觉得如果之前对实时渲染技术不是很了 ...

  2. Spherical Harmonics Lighting

    [转自:http://www.cnblogs.com/daniagger/archive/2012/05/29/2524133.html] 1.背景知识 1.1 光照表示 之前我们都只考虑光源点和物体 ...

  3. Luckily general gradient for spherical harmonics is defined

    http://web4.cs.ucl.ac.uk/staff/j.kautz/publications/gradientSH_RS04.pdf

  4. Thinking in Unity3D:渲染管线中的Rendering Path

      关于<Thinking in Unity3D> 笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙.不得不说,笔者最近几年的 ...

  5. 基于预计算的全局光照(Global Illumination Based On Precomputation)

    目录 基于图像的光照(Image Based Lighting,IBL) The Split Sum Approximation 过滤环境贴图 预计算BRDF积分 预计算辐射度传输(Precomput ...

  6. Unity3D光照前置知识——Rendering Paths(渲染路径)及LightMode(光照模式)译解

    简述 Unity supports different Rendering Paths. You should choose which one you use depending on your g ...

  7. 全局光照:光线追踪、路径追踪与GI技术进化编年史

    全局光照(Global Illumination,简称 GI), 作为图形学中比较酷的概念之一,是指既考虑场景中来自光源的直接光照,又考虑经过场景中其他物体反射后的间接光照的一种渲染技术. 大家常听到 ...

  8. 【Unity Shaders】Shader中的光照

    写在前面 自己写过Vertex & Fragment Shader的童鞋,大概都会对Unity的光照痛恨不已.当然,我相信这是因为我们写得少...不过这也是由于官方文档对这方面介绍很少的缘故, ...

  9. 【Unity Shader】(六) ------ 复杂的光照(上)

    笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题.              [Unity Sha ...

随机推荐

  1. 安装pip工具

    Python 2.7.9+ and 3.4+ Good news! Python 3.4 (released March 2014) and Python 2.7.9 (released Decemb ...

  2. Linux_System11

    1.查看/var目录的大小:1)ll -hd /var 查看目录的实际大小2)du -sh /var 查看目录所占磁盘空间大小修改权限:chmod 750 hunan修改属主和属组:groupadd ...

  3. 在ubuntu中为navicat创建快捷方式

    在ubuntu中,解压navicat并不会生成快捷方式,每次运行都需要进入软件解压的目录,然后运行命令开启navicat,十分不便.今天尝试引入快捷方式,直接双击运行,感觉挺不错. 首先下载一个合适的 ...

  4. UIscrollView 代理

    // // UIDemoViewController.m // 06-1UIScrollDemo // // Created by k on 14-9-4. // Copyright (c) 2014 ...

  5. STM8S003/005/007芯片解密单片机解密程序提取复制经验分享!

    STM8S003/005/007芯片解密单片机解密程序提取复制 芯片解密型号: STM8S003K3T6,STM8S005K6T6,STM8S007C8T6,STM8S003F3P6 STM8S005 ...

  6. CSS中设置margin:0 auto; 水平居中无效的原因分析

    很多初学制作网页的朋友,可能会遇到的一个常见问题,就是在CSS中加了margin:0 auto;却没有效果,不能居中的问题,margin:0 auto;的意思就是:上下边界为0,左右根据宽度自适应,其 ...

  7. Java 页面的工具包

    所谓工具包,是指把页面的功能划分出来,放到另外一个包里面.方面工程管理.结构清晰.团队协作等. 根据原来的例子:要做一个com.myweb包的工具包com.myweb.tool 为导航栏统一创建接口 ...

  8. 利用phpcms-v9站群功能建立多个分站

    用一套CMS软件系统,做多个网站,统一管理,用户可以互通,这就是所谓的站群功能.这对于运营和维护都能节省很多时间,否则要同时调试和维护不同系统会非常吃力. 我在用PHPcms v9做了zhencms1 ...

  9. doubango简介

    1.doubango官网:http://www.doubango.org/ doubango常用项目国内镜像(放在淘宝的svn服务器),目前有4个项目:doubango, idoubs, imsdro ...

  10. 巧用css text-indent减小中文标点符号的占位大小

    由于设计需要,我们的页面中经常会有如下效果: 可是我们实现出来的效果确实这样的: 看起来两行文本没有对齐嘛,仔细检查后原来是[字符的原因,因为是中文标点符号占半个字的位置.不信?选中下汉字标点符号看一 ...