GraphicsLab Project之基于物理的着色系统(Physical based shading) - 基于图像的光照(Image Based Lighting)(Diffuse篇)

作者:i_dovelemon
日期:2018-01-21
来源:CSDN
主题:PBR, Equrectangular Map, Cube Map, Irradiance Map, HDR Image, Pre-Filtering

引言

前面一篇文章讲述了怎么搭建一个PBS的直接光照系统。但是,想要发挥PBR的强大实力,就需要更加丰富的光照系统,本篇文章将要向大家展示,如何实现一个IBL-Diffuse的光照系统,实现的效果如下所示:

IBL-Diffuse场景

基于图像的光照(Image Based Lighting)

在开始之前,我们先来了解下什么是基于图像的光照(IBL)。一个物体,不会单独的存在一个空空的环境里面,它的周围一定有其他的物体。当光源照射到其他物体上的时候,一定也会反射,其中就有很多反射的光线会反射到该物体上去。上一篇文章中我们模拟的是直接光照。对于直接光照系统,像上面那种其他物体反射过来的光,我们一般就只是使用一个Ambient项来模拟。这种模拟方法只能够模拟单调的环境光照效果,想要更加丰富,更加精细的效果,我们就需要使用更加丰富的环境光照系统,而IBL就是实现它的一种方式。

一般来说,我们通过一张环境贴图(Environment Map)来保存一个物体周围的环境信息,然后通过某种处理,来实现丰富的环境光照效果。本文就是讲述,如何通过对环境贴图进行处理,然后实现丰富的环境光照效果。

从渲染方程解释IBL

还记得前面一篇文章中讲述的渲染方程嘛,这里再次的给出:

Lo=Ω(fd+fs)Li(pi,wi)nwidwi

根据前面对环境光照的描述,环境光照也应该符合这个公式,只不过相对于直接光照,它需要计算更多的入射光线。

同时从渲染方程可以看出,我们可以把渲染方程拆成两个部分进行处理:
Lo=ΩfdLinwidwi+ΩfsLinwidwi

本篇文章集中于处理:
Lo=ΩfdLinwidwi

对于这个方程,我们就可以将周围环境的所有光照信息保存在一张环境贴图中,而这个环境贴图就模拟了所有的 Li

环境贴图

在图形领域,用于保存周围环境信息的环境贴图有多种形式,如:


Cube Map



Dual-Paraboloid Map



Equirectangular Map


现在业界,对于IBL普遍使用的是Cube Map的形式。本篇文章也将主要使用Cube Map来进行IBL。

从前面一篇文章描述中我们知道,HDR对于PBR的重要性,没有了HDR,PBR的效果将大大折扣。所以,对于IBL来说,我们依然需要使用HDR。也就说,对于周围环境光照的描述,需要通过HDR的格式文件来保存。

本文的所有使用的环境光照贴图将从 sIBL中获取,这个网站里面有很多免费使用的HDR光照贴图,我们将从这些图中选择一些进行测试。

需要注意的是,这个网站里面的HDR贴图并不是CubeMap的形式,而是EquirectangularMap的形式进行保存的,所以接下来我们需要解决两个问题:如何读取.hdr文件,如何对这个贴图进行filter。

.hdr文件读取

在sIBL网站上,已经给出了.hdr文件格式的详细描述。我这里为了方便就直接使用了github上开源的stb_image库来读取.hdr文件。这个库里面都是一些单个文件的c代码库,感兴趣的读者可以自行探索。

使用它也很简单,只要简单的将stb_image.h包含到你的工程里面去,然后调用如下的代码:

stbi_set_flip_vertically_on_load(true);
int32_t width = 0, height = 0, component = 0;
float* data = stbi_loadf(file_name, &width, &height, &component, 0);
...
stbi_free(data);

你就能够得到.hdr文件保存的HDR数据了,然后可以通过图形API创建一个2D的HDR纹理,以便后续使用。

Equirectangular Map Filter

我们前面说过,我们将使用Cube Map来进行IBL。所以,我们需要一种方法来将该Equirectangular Map转换为Cube Map。为此,我们先简单的绘制一个球体,然后将这个Equirectangular Map贴上去,然后使用传统的创建Cube Map的方式产生一张Cube Map。

那么,我们怎么样将Equirectangular Map映射到球体上去了?通过一些简单的计算就能够完成这个操作,代码如下所示:

vec2 sampling_equirectangular_map(vec3 n) {
    float u = atan(n.z, n.x);
    u = (u + PI) / (2.0 * PI);

    float v = asin(n.y);
    v = (v * 2.0 + PI) / (2.0 * PI);

    return vec2(u, v);
}

上面代码中的n表示的是球体上某个点的法线,这个法线需要是归一化(normliaze)的。

通过计算atan(n.z, n.x)就能够得到具有该法线顶点的UV坐标的U值,通过计算asin(n.y)就能够得到具有该法线顶点的UV坐标的V值。同时,由于atan函数返回的结果在 [π,π] 之间,而asin返回的结果在 [π2,π2] 之间,所有需要把它们都映射到 [0,1] 之间。

下面是使用该方法得到的映射之后的结果:


Filter Equirectangular Map

完整的代码可以在 glb_equirectangularmap中查看。

在得到了这个球体之后,我们就可以简单的使用传统的方法来创建CubeMap,主要就是通过设置FOV为90度的摄像机,分别朝着+X,-X,+Y,-Y,+Z,-Z去观察该球体,然后渲染CubeMap的6个面,从而得到一张HDR的CubeMap。该过程在 GraphicsLab Project之Dynamic Environment Mapping中详细的讲述了,这里就不在赘述。

预计算辐射光照贴图

简化积分方程

我们已经能够使用HDR的

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值