点光源想必大家都很熟悉了,它也非常简单,其相比方向光源的主要区别包括:具有一个Position属性、具有一定的可照射范围、对于任意方向光照强度相同。在本章节,我们首先会实现其实时光照,并不会涉及点光源的实时阴影(由于考虑到光源特性,点光源的阴影需要使用CubeMap,在下一篇会实现)。
1.1 其他光源数据 Other Light Data
类似于方向光源,我们同样在CPU端先定义需要传递给GPU的数组,其包括有效光源数量、光源颜色、光源位置。值得一提的是,Unity会限制每帧的有效光源数量,而不会限制场景中的有效光源数量。当一帧内可能有效的光源数量大于上限时,Unity会根据光源的重要程度进行排序,忽略掉重要度低的光源。为了避免Unity忽略光源导致的频闪,将有效光源最大值设置为64,保证支持足够多的光源。
1.2 点光源设置 Point Light Setup
目前,我们对于一个片元,依然会遍历所有的光源来计算其光照计算结果,但是对于点光源和聚光灯,因为其作用范围往往很小,这些光源并不会对所有片元都产生作用。因此,我们可以通过Unity的PerObject的光源索引来获取作用于一个物体的所有光源的索引。但它其实也不完美,并且可能有一些Bug,因此将其作为管线的可选配置项。
4.1 每物体光源数据 Per-Object Light Data
首先,我们通过激活PerObjectData.LightData和LightIndices来让Unity完成CPU端的工作。
4.2 过滤光源索引 Sanitizing Light Indices
Unity会对每个物体构建一个有效光源的列表,其包括了所有光源(无论是否可见,以及包括了方向光源),我们需要过滤掉不可见光源,并且忽略掉所有方向光源。我们通过构造IndexMap来实现它。
IndexMap数据属于CullingResults,其映射了VisibleLight索引到每个物体的内部光源列表的索引,因此为了实现PerObjectLights,我们需要自己构建这个IndexMap。
另外,我们会创建新的Shader变体来使用PerObjectLights的这套逻辑。
4.3 使用索引 Using the Indices