【发布时间】:2013-06-05 22:54:14
【问题描述】:
我一直致力于在 WebGL 中实现类似于此演示的区域照明:
http://threejs.org/examples/webgldeferred_arealights.html
three.js 中的上述实现是从 Gamedev.net 上 ArKano22 的工作中移植过来的:
http://www.gamedev.net/topic/552315-glsl-area-light-implementation/
尽管这些解决方案令人印象深刻,但它们都有一些局限性。 ArKano22 最初实现的主要问题是漫反射项的计算没有考虑表面法线。
几周以来,我一直在扩充这个解决方案,并使用 redPlant 的改进来解决这个问题。目前我在解决方案中加入了正常的计算,但结果也有缺陷。
这是我当前实现的预览:
简介
计算每个片段的漫反射项的步骤如下:
- 将顶点投影到区域灯光所在的平面上,使投影矢量与灯光的法线/方向一致。
- 通过将投影矢量与光的法线进行比较,检查顶点是否位于区域光平面的正确一侧。
- 计算平面上此投影点与灯光中心/位置的 2D 偏移。
- 钳制此 2D 偏移矢量,使其位于灯光区域(由其宽度和高度定义)内。
- 导出投影和夹紧的 2D 点的 3D 世界位置。这是区域光上到顶点的最近点。
- 通过获取顶点到最近点向量(归一化)和顶点法线之间的点积,执行通常的点光源漫反射计算。
问题
此解决方案的问题在于,照明计算是从最近点完成的,并且没有考虑灯光表面上可能更照亮片段的其他点。让我试着解释一下为什么……
考虑下图:
区域光既垂直于表面又与表面相交。表面上的每个片段将始终返回表面和光源相交的区域光源上的最近点。由于表面法线和顶点到光的向量总是垂直的,所以它们之间的点积为零。随后,尽管表面上隐约可见大面积的光,但漫反射贡献的计算为零。
潜在解决方案
我建议不是从区域光上的最近点计算光,而是从区域光上产生顶点到光之间的最大点积的点计算它向量(归一化)和顶点法线。在上图中,这将是紫点,而不是蓝点。
救命!
所以,这就是我需要你帮助的地方。在我的脑海中,我很清楚如何得出这一点,但我不具备得出解决方案的数学能力。
目前我的片段着色器中有以下可用信息:
- 顶点位置
- 顶点法线(单位向量)
- 灯光位置、宽度和高度
- 光法线(单位向量)
- 光右(单位向量)
- 点亮(单位矢量)
- 从顶点到灯光平面的投影点 (3D)
- 投影点偏离灯光中心 (2D)
- 钳位偏移 (2D)
- 此固定偏移的世界位置 - 最近点 (3D)
为了将所有这些信息放入可视化上下文中,我创建了这个图表(希望对您有所帮助):
为了测试我的建议,我需要区域光上的投射点——用红点表示,这样我就可以在顶点到投射点之间进行点积(标准化) 和顶点法线。同样,这应该会产生最大可能的贡献值。
更新!!!
我在 CodePen 上创建了一个交互式草图,可视化了我目前已经实现的数学:
http://codepen.io/wagerfield/pen/ywqCp
您应该关注的相关代码是第 318 行。
castingPoint.location 是THREE.Vector3 的一个实例,是拼图中缺失的部分。您还应该注意到草图的左下方有 2 个值 - 这些值会动态更新以显示相关向量之间的点积。
我想这个解决方案需要另一个伪平面,它与顶点法线的方向对齐并且垂直于光的平面,但我可能错了!
【问题讨论】:
-
为什么说“漫反射项不考虑表面法线”? three.js 实现中的扩散项不是一个,而是两个余弦项。
-
对不起,我的意思是说 ArKano22 的原始实现没有考虑表面法线。我已经更新了问题以反映这一点。与 three.js 实现将 2 个余弦项相乘的方式非常相似,我也在做同样的事情,但引入了一个衰减因子,该因子使最近点到顶点向量和光法线之间的点积产生偏差。这给出了我在上面的预览中显示的灯光周围的照明区域,但牺牲了正常计算的包含。
-
由于您提出的找到使点积最大化的点的方法无论如何都是一个近似值,因此请考虑计算来自每个角(或侧面中点)的总光贡献(包括衰减)的替代方法轻,并选择最大值。至少你可以看到它的样子。
-
@WestLangley Paul Lewis 早些时候在 Twitter 上提出了相同的迭代方法,这绝对是我明天想尝试的东西。想了这么久,我的大脑有些发火,但我仍然相信,鉴于现有的大量信息,有一个确切的解决方案?
-
寻找投射点的伪代码是否可以接受?我需要知道一些事情才能解决它。在链接代码中,请提及 1)表面法线向量 2)光平面边界(四个线段)和 3)光法线。
标签: math 3d three.js webgl lighting