球谐光照(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 ...
随机推荐
- Java XML解析器
使用Apache Xerces解析XML文档 一.技术概述 在用Java解析XML时候,一般都使用现成XML解析器来完成,自己编码解析是一件很棘手的问题,对程序员要求很高,一般也没有专业厂商或者开源组 ...
- highcharts设置Y轴范围及根据Y轴范围设置不同颜色
yAxis : { title : { text : '数据' }, plotLines : [ { value : 0, width : 1, color : '#808080' } ], min: ...
- mobile meta iphone
<!doctype html> <html> <head> <title>iOS touch test ( Multi-touch )</titl ...
- 职业定位(Web前端、后台、PC端)
Web前端 Web前端开发工程师:http://baike.sogou.com/v18499271.htm WEB前端开发面试题集锦:http://wenku.baidu.com/view/47bbc ...
- centos 单独安装nginx
安装包下载网址: http://nginx.org/en/download.html 进入Linux文件夹执行 wget http://nginx.org/download/nginx-1.8.0.t ...
- YII 1.0 增删改查
查询 查询多条返回数据集合 //1.该方法是根据一个条件查询一个集合 $admin=Admin::model()->findAll($condition,$params); $admin=Adm ...
- 贴一份用delphi修改注册表改网卡MAC地址的代码
//提示:此代码需要use Registry, Common; function WriteMAC(model:integer):integer; var reg:TRegistry; begin r ...
- HDU-5123-who is the best?
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5123 水题一个,直接hash: 代码 #include<stdio.h>#include& ...
- js原生设计模式——2面向对象编程之闭包2
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- 初识SuperSocket
有一些企业由于以前使用的操作系统是被淘汰的操作系统,例如OpenVMS.现需要将针对openvms开发的通讯程序进行移植到现在的windows操作系统上,通过一段时间的了解,现在需要花时间去找商业性的 ...