GraphicsLab Project之光照贴图烘焙(一)

本文介绍了如何实现一个简单的基于Radiosity Algorithm的光照贴图烘焙程序,用于烘焙出场景中的全局光照效果。通过场景分割、计算LightPatch接受的光照值和权重贴图等步骤,最终得到光照贴图。并讨论了简单的优化技巧,如关闭垂直同步和利用mipmap计算像素之和,以提高烘焙效率。
摘要由CSDN通过智能技术生成

作者:i_dovelemon
来源:CSDN
日期:2018-05-19
主题:Radiosity Algorithm, Global Illumination, Barycentric Coordinate


Radiosity Light Baker


引言



早在Quake的时代,卡马克就首创了使用Surface Caching来实现预先烘焙的光照贴图(Light Map)效果。在这之后,光照贴图实现的GI效果慢慢的得到了游戏开发者和学术界的共同推进,慢慢的发展出了很多不同的算法。EA的DICE曾讲述了GI效果的前世今生,在这里可以了解到相关的技术。

接下来的几篇文章我将向大家讲述如何实现一个简单的光照贴图烘焙程序,用于烘焙出场景里面的GI效果。最终希望在此基础上,实现Valve在Source引擎中实现的Radiosity Normal Map的光照烘焙效果。

在实现Radiosity Normal Map之前,我们需要先实现一个Old School的光照烘焙程序,然后在此基础上进行改进。下面我们来看看如何实现一个最基本的Light Map Baker吧。(题图是本文实现的Baker所烘焙出来的效果)


光照贴图



在所有开始之前,我们先来了解下什么是光照贴图,以及我们为什么要烘焙光照贴图。

在大家初次学习光照的时候,所有的教程都会讲解如何实现一个平行光,点光源,聚光灯等等实时的光照效果。但是这些光照效果是直接光照(Direct Lighting),也就是只考虑了光源对物体本身的光照效果。实际上在现实世界里面,物体会反射光源的光,从而导致其他的物体被物体反射的光所照亮(Indirect Lighting)。这样就导致了影子看上去不是全黑的,一个颜色的墙壁会染上其他墙壁的颜色等等效果,见下图。


GI

而对于间接光照,现在没有太好的实时渲染方案。最简单的实现间接光照效果的方法,就是对一个静态的场景,预先使用支持GI的渲染器,烘焙出想要的GI效果。比如 这篇文章就讲述了如何使用Blender预先烘焙好光照贴图,然后在程序中使用。如果你的引擎仅仅是希望这样,那么直接使用现成的渲染器来烘焙光照贴图是最省力的做法,效果也不错。

由于我想实现的是Radiosity Normal Map,它的渲染需要对离线渲染器做一些修改,所以需要自己实现一套离线渲染程序,所以就有了这篇文章。当然,本来就是为了学习,做更多的东西才是最好的做法。

光照贴图的形式多种多样。一般来说,我们会给一个合适大小的场景单独烘焙一整张光照贴图,它看起来像这样:

Light Map

好了,在了解了光照贴图的作用之后,我们就需要了解如何烘焙光照贴图了。


辐射度算法(Radiosity Algorithm)



实现烘焙的算法有很多,比如Path Tracer, Photo Mapping还有Radiosity Algorithm等等。本文将要实现的方案是基于Radiosity Algorithm。

这里有一篇文章,很清晰的讲述了Radiosity Algorithm的机理。我不认为我能够讲解的比他的还要清楚明了,所以关于Radiosity Algorithm的解释,我就不在赘述了。当然,如果你和我一样相信他所讲的就是全部了,那么你依然无法根据那篇文章实现烘焙功能,至少效果是不太正确的。所以我在这里讲述一些它所没有涉及的部分。

大体上,基于Radiosity Algorithm的烘焙程序,是由如下的步骤组成的:

  • 预先分割场景,准备LightPatch
  • 循环迭代,计算每一个LightPatch所受到的光照
  • 根据每一个LightPatch最终接受到的光照值,生成LightMap

    下面将依次讲解每一个步骤。


  • 光照烘焙程序



    分割场景



    场景分割方案有多种不同的方式。我这里由于最终需要的结果是一张LightMap,所以就根据LightMap来分割场景。

    正如前面我们讲述了那样,对于一个场景,我们使用一整张LightMap,来表示它的光照烘焙结果,而不是每一个物体一张光照贴图。这就导致了,场景中所有物体的UV,除了本身进行光照渲染时需要使用的访问Albedo,Normal等等的传统UV,还需要另外一套对应于光照贴图的UV坐标,也就是说整个场景的第二套UV坐标是统一在一个UV坐标系里面的。这样才能够统一的访问光照贴图,得到对应的光照结果。

    根据辐射度算法一文的描述,一个LightPatch就对应了光照贴图里面的一个像素。而对于一个LightPatch,我们需要知道它所在场景的点的位置(Position)以及法线(Normal)。那么,对于光照贴图里面的任意一个像素,我们都能够知道它的UV坐标。而模型文件中保存了场景中所有三角形的顶点位置,法线和UV的信息。我们能否根据LightMap中像素的UV坐标,来得到对应的LightPatch所在点的位置及法线信息了。答案当然是可以的了。

    Barycentric coordinate


    在这里我们需要使用三角形的barycentric coordinate system来求出我们需要的信息。关于barycentric coordinate system的详细信息,可以看这里

    根据wiki的描述,我们能够得到一个三角形的如下关系式:

    r=λ0r0+λ1r1+λ2r2 r = λ 0 ∗ r 0 + λ 1 ∗ r 1 + λ 2 ∗ r 2

    其中:


    (λ0+λ1+λ2=1) ( λ 0 + λ 1 + λ 2 = 1 )
    0
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值