球谐光照(Spherical Harmonics Lighting)及其应用-应用篇
上一篇介绍了球谐函数的一些原理和性质,本篇主要介绍如何实现球谐光照,将这种光照应用到实际的场景中去。
我们知道,球谐光照实际上就是将周围的环境光采样成几个系数,然后渲染的时候用这几个系数来对光照进行还原,这种过程可以看做是对周围环境光的简化,从而简化计算过程。因为如果按照采样的方法进行渲染,每次渲染的时候都得对周围环境采样,从而都会耗费大量的计算时间。所以球谐光照的实现可以分成两个部分,一是环境光贴图的采样和积分运算,生成球谐参数,二是利用球谐参数对模型进行渲染。
采样器
采样是从环境光上面采,而环境光我们可以用环境光贴图表示。环境光贴图则可以采用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)及其应用-应用篇的更多相关文章
- 球谐光照(Spherical Harmonics Lighting)及其应用-实验篇
简介 之前在一篇实时深度图优化的论文中看到球谐光照(Spherical Harmonics Lighting)的应用,在查阅了许许多多资料之后还是无法完全理解,我个人觉得如果之前对实时渲染技术不是很了 ...
- Spherical Harmonics Lighting
[转自:http://www.cnblogs.com/daniagger/archive/2012/05/29/2524133.html] 1.背景知识 1.1 光照表示 之前我们都只考虑光源点和物体 ...
- Luckily general gradient for spherical harmonics is defined
http://web4.cs.ucl.ac.uk/staff/j.kautz/publications/gradientSH_RS04.pdf
- Thinking in Unity3D:渲染管线中的Rendering Path
关于<Thinking in Unity3D> 笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙.不得不说,笔者最近几年的 ...
- 基于预计算的全局光照(Global Illumination Based On Precomputation)
目录 基于图像的光照(Image Based Lighting,IBL) The Split Sum Approximation 过滤环境贴图 预计算BRDF积分 预计算辐射度传输(Precomput ...
- Unity3D光照前置知识——Rendering Paths(渲染路径)及LightMode(光照模式)译解
简述 Unity supports different Rendering Paths. You should choose which one you use depending on your g ...
- 全局光照:光线追踪、路径追踪与GI技术进化编年史
全局光照(Global Illumination,简称 GI), 作为图形学中比较酷的概念之一,是指既考虑场景中来自光源的直接光照,又考虑经过场景中其他物体反射后的间接光照的一种渲染技术. 大家常听到 ...
- 【Unity Shaders】Shader中的光照
写在前面 自己写过Vertex & Fragment Shader的童鞋,大概都会对Unity的光照痛恨不已.当然,我相信这是因为我们写得少...不过这也是由于官方文档对这方面介绍很少的缘故, ...
- 【Unity Shader】(六) ------ 复杂的光照(上)
笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Sha ...
随机推荐
- SQL Server 2012 - 数据库的基础操作
数据库基本操作 --新建数据库卡 use master go create database SchoolDB on ( Name=SchoolDB, FileName='D;\DB\SchoolDB ...
- 【Xilinx-Petalinux学习】-06-OpenCV通过USB摄像头采集图像。
占位, 实现USB摄像头的图像采集与保存
- Python3基础 在print中用 %d 输出一个整数
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- IM 之 融云
官方网站:http://www.rongcloud.cn 官方开发文档:http://www.rongcloud.cn/docs/ IM 融云 之 开发基础概念 IM 融云 之 通讯能力库API IM ...
- IOS 使用GCD改善性能
1.GCD介绍 GCD:Grand Central Dispathch,核心中央调度,是一种异步技术.但是它是系统级的. 负责管理队列,是线程之上的抽象层.队列可以并行或串行运行,能够在系统级自动管理 ...
- Spinnerd的功能和用法
此处的Spinner其实是一个列表选择框.不过Android的列表选择框并不是需要下拉列表的,而是相当于弹出一个菜单供用户选择. Spinner和Gallery都继承了AbsSpinner,AbsSp ...
- 车大棒浅谈for循环+canvas实现黑客帝国矩形阵
背景: 一日在网上闲逛的之时,突然看到一个利用JQ插件实现canvas实现的电影黑客帝国的小Demo.觉得创意不错,就下载下来研究一下. 网上浏览jQuery的写法 $(document).ready ...
- inline「一」:从 image 底部白边初识 line-height
本文首发于个人博客 http://www.lijundong.com/image-and-line-height/ 今天在做一个静态页面时,图片底部出现一条 3px 高度的白边,既不是 margin ...
- JWebFileTrans: 一款可以从网络上下载文件的小程序(一)
一 摘要 JWebFileTrans是一款基于socket的网络文件传输小程序,目前支持从HTTP站点下载文件,后续会增加ftp站点下载.断点续传.多线程下载等功能.其代码已开源到github上面,下 ...
- leetcode刷题总结
题外话 今年大三,现正值寒假时间,开学就开始大三下学期的生活了. 在大三临近结束的时间,也就是复习考试的时间里,我每天都会用早上的时间来刷codewars.刚开始玩的时候,一到8kyu的题目如果稍微难 ...