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

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

采样器

采样是从环境光上面采,而环境光我们可以用环境光贴图表示。环境光贴图则可以采用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. eclipse安装maketplace插件

    对于默认eclipse是没有marketplace插件的,但是marketplace确实是非常好用的,可以在上面下载各种插件. 1.Help-->Install new Software 2.输 ...

  2. UVa 11308 - Bankrupt Baker

    题目大意:给出一些原料和价钱和若干份菜谱,每份菜谱都标明所需的原料和数量,找出所有不超过预算的菜谱. 没什么好说的,主要是对map的运用. #include <cstdio> #inclu ...

  3. java系列--JSP的属性和内置对象

    一.JSP指令: <%@ 指令名 属性=" " %> 1.page指令 import属性 errorPage属性 language属性 session属性 isErro ...

  4. 【T】并行调度

    /** * 并行调度相关处理 * * 按卫星*日期 ,将待处理的任务分解为 卫星+日期 粒度的子任务 添加到paramMapList列表中 */ List<Map<String, Obje ...

  5. 一张图告诉你什么是Linux distributions...

  6. C++第四天学习

    回顾: 1.初始化表 2.this指针 3.拷贝构造 Test(const Test& rt) { //1.分配新空间 //2.给新空间赋值 } 4.static成员 类::函数(): 类型 ...

  7. HTML URL

    HTML 统一资源定位器(Uniform Resource Locators) URL 是一个网页地址. URL可以由字母组成,如"runoob.com",或互联网协议(IP)地址 ...

  8. ACE首页更改

    @{ Layout = null; } <!DOCTYPE html> <html lang="zh-cn"> <head> <meta ...

  9. SSM框架整合(注解)-Spring+SpringMVC+MyBatis+MySql

    准备工作: 下载整合所需的jar包 点击此处下载 使用MyBatis Generator生成dao接口.映射文件和实体类 如何生成 搭建过程: 先来看一下项目的 目录结构 1.配置dispatcher ...

  10. IE6浏览器常见的bug及其修复方法

    IE6不支持min-height,解决办法使用css hack: .target { min-height: 100px; height: auto !important; height: 100px ...