我一直在研究 WebGL 中的区域照明实现,类似于这个演示:
http://threejs.org/examples/webgldeferred_arealights.html
three.js 中的上述实现是从 ArKano22 在 gamedev.net 上的工作中移植的:
http://www.gamedev.net/topic/552315-glsl-area-light-implementation/
尽管这些解决方案令人印象深刻,但它们都有一些局限性。ArKano22 最初实现的主要问题是漫反射项的计算没有考虑表面法线。
几个星期以来,我一直在扩充这个解决方案,使用 redPlant 的改进来解决这个问题。目前我已将正常计算纳入解决方案,但结果也存在缺陷。
这是我当前实现的预览:
介绍
计算每个片段的扩散项的步骤如下:
- 将顶点投影到区域灯光所在的平面上,以便投影矢量与灯光的法线/方向重合。
- 通过将投影矢量与光的法线进行比较,检查顶点是否位于区域光平面的正确一侧。
- 计算平面上此投影点与灯光中心/位置的 2D 偏移。
- 夹住这个 2D 偏移矢量,使其位于灯光的区域内(由其宽度和高度定义)。
- 导出投影和夹紧的 2D 点的 3D 世界位置。这是区域光上离顶点最近的点。
- 通过获取顶点到最近点向量(归一化)和顶点法线之间的点积,执行通常的点光源漫射计算。
问题
这个解决方案的问题是光照计算是从最近的点开始的,并且没有考虑灯光表面上可能更照亮片段的其他点。让我试着解释一下为什么……</p>
考虑下图:
区域光既垂直于表面又与表面相交。表面上的每个片段将始终返回表面和光相交的区域光上最近的点。由于表面法线和顶点到光的向量总是垂直的,所以它们之间的点积为零。随后,尽管表面上有大面积的光隐约可见,但漫反射贡献的计算为零。
潜在解决方案
我建议,我们不是从区域光上最近的点计算光,而是从区域光上的一个点计算它,该点在顶点到光向量(归一化)和顶点法线之间产生最大的点积。在上图中,这将是紫点,而不是蓝点。
帮助!
所以,这就是我需要你帮助的地方。在我的脑海中,我对如何得出这一点有一个很好的想法,但没有数学能力来得出解决方案。
目前,我的片段着色器中有以下可用信息:
- 顶点位置
- 顶点法线(单位向量)
- 灯光位置、宽度和高度
- 光法线(单位向量)
- 光右(单位向量)
- 点亮(单位向量)
- 从顶点投影到灯光平面上的点 (3D)
- 投影点偏离灯光中心 (2D)
- 夹紧偏移 (2D)
- 此钳位偏移的世界位置 -最近点(3D)
为了将所有这些信息放入可视化上下文中,我创建了这个图表(希望它有所帮助):
为了测试我的建议,我需要区域光上的投射点——用红点表示,这样我就可以在顶点到投射点(标准化)和顶点法线之间进行点积。同样,这应该产生最大可能的贡献值。
更新!!!
我在 CodePen 上创建了一个交互式草图,可视化了我目前已经实现的数学:
http://codepen.io/wagerfield/pen/ywqCp
您应该关注的相关代码是第318行。
castingPoint.location
是一个实例,THREE.Vector3
并且是拼图的缺失部分。您还应该注意到草图的左下角有 2 个值——这些值是动态更新的,以显示相关向量之间的点积。
我想该解决方案将需要另一个与顶点法线方向对齐并且垂直于光平面的伪平面,但我可能错了!