gpt4 book ai didi

math - 改进了 WebGL 和 ThreeJS 中的区域照明

转载 作者:行者123 更新时间:2023-12-03 05:44:41 24 4
gpt4 key购买 nike

我一直致力于在 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 的改进来解决这个问题。目前我已将正常计算纳入解决方案,但结果也有缺陷。

这是我当前实现的先睹为快:

area lighting teaser

介绍

计算每个片段的漫反射项的步骤如下:

  • 将顶点投影到区域灯光所在的平面上,以便投影矢量与灯光的法线/方向重合。
  • 通过将投影向量与光的法线进行比较,检查顶点是否位于区域光平面的正确一侧。
  • 计算平面上此投影点与灯光中心/位置的 2D 偏移。
  • 夹住这个 2D 偏移向量,使其位于灯光区域内(由其宽度和高度定义)。
  • 导出投影和夹紧的 2D 点的 3D 世界位置。这是最近点 在区域光到顶点。
  • 通过取顶点到最近点向量(归一化)和顶点法线之间的点积,对点光源执行通常的漫反射计算。

  • 问题

    此解决方案的问题在于照明计算是从 完成的。最近点 并且不考虑灯光表面上可能更照亮片段的其他点。让我试着解释为什么……

    考虑下图:

    problematic area lighting situation

    区域光既垂直于表面又与其相交。表面上的每个片段将始终返回 最近点 在表面和光相交的区域光上。由于表面法线和顶点到光向量始终垂直,因此它们之间的点积为零。随后,尽管有大面积的光在表面上隐约可见,但漫反射贡献的计算为零。

    潜在解决方案

    我建议,而不是计算来自 的光。最近点 在区域光上,我们从区域光上的一个点计算它,该点在顶点到光向量(归一化)和顶点法线之间产生最大的点积。在上图中,这将是紫点,而不是蓝点。

    帮助!

    所以,这就是我需要你帮助的地方。在我的脑海中,我对如何推导出这一点有一个很好的想法,但没有得出解决方案的数学能力。

    目前,我的片段着色器中有以下可用信息:
  • 顶点位置
  • 顶点法线(单位向量)
  • 光位、宽高
  • 光法线(单位向量)
  • 光右(单位向量)
  • 点亮(单位向量)
  • 从顶点投影到灯光平面(3D)
  • 投影点偏离灯光中心 (2D)
  • 夹紧偏移 (2D)
  • 此钳位偏移的世界位置 – 最近点 (3D)

  • 为了将所有这些信息放在一个可视化的上下文中,我创建了这个图表(希望它有帮助):

    available lighting information

    为了测试我的提议,我需要 铸点在区域灯上 - 由红点表示,以便我可以在顶点到转换点(标准化)和顶点法线之间执行点积。同样,这应该产生最大可能的贡献值。

    更新!!!

    我在 CodePen 上创建了一个交互式草图,将我目前实现的数学可视化:

    http://codepen.io/wagerfield/pen/ywqCp

    codepen

    您应该关注的相关代码是行 318 .
    castingPoint.locationTHREE.Vector3 的一个实例并且是拼图的缺失部分。您还应该注意到草图的左下方有 2 个值——它们会动态更新以显示相关向量之间的点积。

    我想该解决方案将需要另一个与顶点法线方向对齐且垂直于光平面的伪平面,但我可能错了!

    最佳答案

    好消息是有一个解决方案;但首先是坏消息。

    您使用使点积最大化的点的方法从根本上是有缺陷的,并且在物理上不合理。

    在上面的第一个插图中,假设您的区域光仅由左半部分组成。

    “紫色”点 - 最大化左半部分的点积的点 - 与最大化两半组合的点积的点相同。

    因此,如果要使用您提出的解决方案,人们会得出结论,区域光的左半部分发出与整个光相同的辐射。显然,这是不可能的。

    计算区域光转换在给定点上的总光量的解决方案相当复杂,但作为引用,您可以在 1994 年的论文 The Irradiance Jacobian for Partially Occluded Polyhedral Sources here 中找到解释。 .

    建议你看图1 ,还有几段第 1.2 节 ——然后停下来。 :-)

    为了方便起见,我编写了一个非常简单的着色器,它使用three.js WebGLRenderer 实现了解决方案。 ——不是延期的。

    编辑:这是一个更新的 fiddle :http://jsfiddle.net/hh74z2ft/1/

    enter image description here

    片段着色器的核心非常简单

    // 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 );

    更多好消息:
  • 这种方法在物理上是正确的。
  • 衰减是自动处理的。 (请注意,较小的灯将需要较大的强度值。)
  • 理论上,这种方法应该适用于任意多边形,而不仅仅是矩形。

  • 注意事项:
  • 我只实现了漫反射组件,因为这就是您的问题所解决的问题。
  • 您必须使用合理的启发式方法来实现镜面反射组件——我希望类似于您已经编写的代码。
  • 这个简单的例子不处理区域光“部分低于地平线”的情况——即并非所有 4 个顶点都在面部平面之上。
  • WebGLRenderer不支持区域灯光,您不能“将灯光添加到场景中”并期望它起作用。这就是我将所有必要数据传递到自定义着色器的原因。 (WebGLDeferredRenderer 确实支持区域灯,当然。)
  • 不支持阴影。

  • 三.js r.73

    关于math - 改进了 WebGL 和 ThreeJS 中的区域照明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17021264/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com