wag*_*eld 59 math 3d lighting webgl three.js
我一直在研究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的改进来解决这个问题.目前我将正常的计算结合到解决方案中,但结果也存在缺陷.
以下是我当前实施的预览:

计算每个片段的扩散项的步骤如下:
该解决方案的问题在于,照明计算是从最近的点完成的,并且不考虑光表面上可能照亮片段的其他点.让我试着解释一下为什么......
请考虑以下图表:

区域光线垂直于表面并与之相交.表面上的每个碎片将始终返回表面和光相交的区域光上的最近点.由于曲面法线和顶点到光线矢量总是垂直的,因此它们之间的点积为零.随后,尽管在表面上隐藏着大面积的光,但漫射贡献的计算为零.
I propose that rather than calculate the light from the nearest point on the area light, we calculate it from a point on the area light that yields the greatest dot product between the vertex-to-light vector (normalised) and the vertex normal. In the diagram above, this would be the purple dot, rather than the blue dot.
And so, this is where I need your help. In my head, I have a pretty good idea of how this point can be derived, but don't have the mathematical competence to arrive at the solution.
Currently I have the following information available in my fragment shader:
To put all this information into a visual context, I created this diagram (hope it helps):

To test my proposal, I need the casting point on the area light – represented by the red dots, so that I can perform the dot product between the vertex-to-casting-point (normalised) and the vertex normal. Again, this should yield the maximum possible contribution value.
I have created an interactive sketch over on CodePen that visualises the mathematics that I currently have implemented:

The relavent code that you should focus on is line 318.
castingPoint.location是THREE.Vector3拼图的一个实例并且是缺失的部分.您还应该注意到草图左下方有2个值 - 这些值会动态更新以显示相关矢量之间的点积.
我想这个解决方案需要另一个与顶点法线方向对齐并且垂直于光线平面的伪平面,但我可能错了!
Wes*_*ley 40
好消息是有一个解决方案; 但首先是坏消息.
使用最大化点积的点的方法从根本上是有缺陷的,并且在物理上是不合理的.
在上面的第一张图中,假设您的区域光仅由左半部分组成.
"紫色"点 - 最大化左半部分点积的点 - 与最大化两半点积相结合的点相同.
因此,如果要使用您提出的解决方案,可以得出结论,区域光的左半部分发出与整个光相同的辐射.显然,这是不可能的.
用于计算该地区光在给定的点投射出总量的解决方案是相当复杂的,但供参考,你可以找到在1994年的论文解释辐照雅可比部分遮挡多面体源 在这里.
我建议你看一下图1和1.2节的几段- 然后停下来.:-)
为了方便起见,我编写了一个非常简单的着色器,它使用three.js实现解决方案WebGLRenderer- 而不是延迟的.
编辑:这是一个更新的小提琴:http://jsfiddle.net/hh74z2ft/1/

片段着色器的核心非常简单
// direction vectors from point to area light corners
for( int i = 0; i < NVERTS; i ++ ) {
    lPosition[ i ] = viewMatrix * lightMatrixWorld * vec4( lightverts[ i ], 1.0 ); // in camera space
    lVector[ i ] = normalize( lPosition[ i ].xyz + vViewPosition.xyz ); // dir from vertex to areaLight
}
// vector irradiance at point
vec3 lightVec = vec3( 0.0 );
for( int i = 0; i < NVERTS; i ++ ) {
    vec3 v0 = lVector[ i ];
    vec3 v1 = lVector[ int( mod( float( i + 1 ), float( NVERTS ) ) ) ]; // ugh...
    lightVec += acos( dot( v0, v1 ) ) * normalize( cross( v0, v1 ) );
}
// irradiance factor at point
float factor = max( dot( lightVec, normal ), 0.0 ) / ( 2.0 * 3.14159265 );
更多好消息:
注意事项:
WebGLRenderer不支持区域灯光,因此无法"将灯光添加到场景中"并期望它能够正常工作.这就是我将所有必要的数据传递到自定义着色器的原因.(WebGLDeferredRenderer当然,确实支持区域灯.)three.js r.73