改进了WebGL和ThreeJS的区域照明。

时间:2021-10-16 05:31:29

I have been working on an area lighting implementation in WebGL similar to this demo:

我在WebGL的一个区域照明实现工作类似于这个演示:

http://threejs.org/examples/webgldeferred_arealights.html

http://threejs.org/examples/webgldeferred_arealights.html

The above implementation in three.js was ported from the work of ArKano22 over on gamedev.net:

上述实现在三个方面。js从ArKano22的工作中移植到gamedev:

http://www.gamedev.net/topic/552315-glsl-area-light-implementation/

http://www.gamedev.net/topic/552315-glsl-area-light-implementation/

Though these solutions are very impressive, they both have a few limitations. The primary issue with ArKano22's original implementation is that the calculation of the diffuse term does not account for surface normals.

虽然这些解决方案非常令人印象深刻,但是它们都有一些局限性。ArKano22最初实现的主要问题是,漫射项的计算不考虑表面法线。

I have been augmenting this solution for some weeks now, working with the improvements by redPlant to address this problem. Currently I have normal calculations incorporated into the solution, BUT the result is also flawed.

我已经对这个解决方案进行了几个星期的改进,并通过redPlant的改进来解决这个问题。目前我已经将正常的计算纳入到解决方案中,但结果也是有缺陷的。

Here is a sneak preview of my current implementation:

以下是对我当前实现的预览:

改进了WebGL和ThreeJS的区域照明。

Introduction

The steps for calculating the diffuse term for each fragment is as follows:

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

  1. Project the vertex onto the plane that the area light sits on, so that the projected vector is coincident with the light's normal/direction.
  2. 将该顶点投射到该区域光所在的平面上,使投影的向量与光线的正常/方向重合。
  3. Check that the vertex is on the correct side of the area light plane by comparing the projection vector with the light's normal.
  4. 通过将投影矢量与光线的正常情况进行比较,确定该顶点在区域光平面的正确一侧。
  5. Calculate the 2D offset of this projected point on the plane from the light's center/position.
  6. 从光的中心/位置计算这个投影点在平面上的二维偏移量。
  7. Clamp this 2D offset vector so that it sits inside the light's area (defined by its width and height).
  8. 夹住这个二维偏移矢量,使它位于光线的区域(由其宽度和高度定义)。
  9. Derive the 3D world position of the projected and clamped 2D point. This is the nearest point on the area light to the vertex.
  10. 导出投影和夹紧2D点的3D世界位置。这是在区域光到顶点的最近点。
  11. Perform the usual diffuse calculations that you would for a point light by taking the dot product between the the vertex-to-nearest-point vector (normalised) and the vertex normal.
  12. 执行通常的漫射计算,你可以通过在顶点到最接近点的向量(标准化)和顶点法线之间取点积来得到点光。

Problem

The issue with this solution is that the lighting calculations are done from the nearest point and do not account for other points on the lights surface that could be illuminating the fragment even more so. Let me try and explain why…

这个解决方案的问题是,灯光计算是从最近的点进行的,并且不考虑灯光表面上的其他点,这可能会更加照亮碎片。让我来解释一下为什么……

Consider the following diagram:

考虑下面的图:

改进了WebGL和ThreeJS的区域照明。

The area light is both perpendicular to the surface and intersects it. Each of the fragments on the surface will always return a nearest point on the area light where the surface and the light intersect. Since the surface normal and the vertex-to-light vectors are always perpendicular, the dot product between them is zero. Subsequently, the calculation of the diffuse contribution is zero despite there being a large area of light looming over the surface.

面积光是垂直于表面并与之相交的。表面上的每一个碎片都会在表面和光线相交的地方返回一个最近的点。由于表面法线和垂直于光的矢量总是垂直的,所以它们之间的点积是零。随后,漫射贡献的计算是零,尽管在表面有大面积的光。

Potential Solution

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.

我的建议是,我们不需要计算区域光的最近点的光,而是从区域光的一个点上计算它,这个点在垂直于光的矢量(normalised)和顶点法线之间产生最大的点积。在上图中,这是紫色的点,而不是蓝色的点。

Help!

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:

目前,我的片段着色器中有以下信息:

  • vertex position
  • 顶点的位置
  • vertex normal (unit vector)
  • 顶点正常(单位向量)
  • light position, width and height
  • 光的位置,宽度和高度。
  • light normal (unit vector)
  • 光正常(单位向量)
  • light right (unit vector)
  • 光对(单位向量)
  • light up (unit vector)
  • 点亮(单位向量)
  • projected point from the vertex onto the lights plane (3D)
  • 从顶点到灯光平面的投影点(3D)
  • projected point offset from the lights center (2D)
  • 灯光中心投影点偏移(2D)
  • clamped offset (2D)
  • 夹抵消(2 d)
  • world position of this clamped offset – the nearest point (3D)
  • 这个夹紧偏移的世界位置-最近的点(3D)

To put all this information into a visual context, I created this diagram (hope it helps):

为了将所有这些信息放到一个可视化的环境中,我创建了这个图表(希望它有帮助):

改进了WebGL和ThreeJS的区域照明。

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.

为了测试我的建议,我需要在区域光上的浇注点——用红点表示,这样我就可以在vertexto - castpoint(标准化)和顶点法线之间执行点积。同样,这应该会产生最大可能的贡献值。

UPDATE!!!

I have created an interactive sketch over on CodePen that visualises the mathematics that I currently have implemented:

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

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

改进了WebGL和ThreeJS的区域照明。

The relavent code that you should focus on is line 318.

您应该关注的relavent代码是第318行。

castingPoint.location is an instance of THREE.Vector3 and is the missing piece of the puzzle. You should also notice that there are 2 values at the lower left of the sketch – these are dynamically updated to display the dot product between the relevant vectors.

castingPoint。位置是三个的实例。Vector3是拼图的缺失部分。您还应该注意到,在草图的左下方有两个值——这些值是动态更新的,以显示相关向量之间的点积。

I imagine that the solution would require another pseudo plane that aligns with the direction of the vertex normal AND is perpendicular to the light's plane, but I could be wrong!

我想,解决方案需要另一个伪平面,它与顶点法线的方向一致,垂直于光的平面,但我可能是错的!

5 个解决方案

#1


38  

The good news is there is a solution; but first the bad news.

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

Your approach of using the point that maximizes the dot product is fundamentally flawed, and not physically plausible.

你的方法是用点来最大化点积,从本质上讲是有缺陷的,而且在物理上是不可信的。

In your first illustration above, suppose that your area light consisted of only the left half.

在你上面的第一个例子中,假设你的区域光只有左边的一半。

The "purple" point -- the one that maximizes the dot-product for the left half -- is the same as the point that maximizes the dot-product for both halves combined.

“紫色”点——即最大限度地为左半边的点积——的点,与将两半组合的点积最大化的点是一样的。

Therefore, if one were to use your proposed solution, one would conclude that the left half of the area light emits the same radiation as the entire light. Obviously, that is impossible.

因此,如果一个人使用你的建议的解决方案,你会得出结论:该区域的左半边光发出的辐射与整个光的辐射相同。很明显,这是不可能的。

The solution for computing the total amount of light that the area light casts on a given point is rather complicated, but for reference, you can find an explanation in the 1994 paper The Irradiance Jacobian for Partially Occluded Polyhedral Sources here.

计算在给定的点上的区域光投射的总光量是相当复杂的,但是为了便于参考,你可以在1994年的论文中找到一种解释,即在这里部分遮挡的多面体源的辐照雅可比矩阵。

I suggest you look at Figure 1, and a few paragraphs of Section 1.2 -- and then stop. :-)

我建议您看一下图1和1.2节的几个段落——然后停止。:-)

To make it easy, I have coded a very simple shader that implements the solution using the three.js WebGLRenderer -- not the deferred one.

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

EDIT: Here is an updated fiddle: http://jsfiddle.net/hh74z2ft/1/

编辑:这里有一个更新的小提琴:http://jsfiddle.net/hh74z2ft/1/。

改进了WebGL和ThreeJS的区域照明。

The core of the fragment shader is quite simple

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

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

More Good News:

更多的好消息:

  1. This approach is physically correct.
  2. 这种方法在物理上是正确的。
  3. Attenuation is handled automatically. ( Be aware that smaller lights will require a larger intensity value. )
  4. 衰减是自动处理的。(要意识到较小的灯光需要更大的强度值。)
  5. In theory, this approach should work with arbitrary polygons, not just rectangular ones.
  6. 从理论上讲,这种方法应该适用于任意的多边形,而不仅仅是矩形的。

Caveats:

警告:

  1. I have only implemented the diffuse component, because that is what your question addresses.
  2. 我只实现了漫反射组件,因为这是您的问题地址。
  3. You will have to implement the specular component using a reasonable heuristic -- similar to what you already have coded, I expect.
  4. 您将必须使用一个合理的启发式方法实现specular组件——我想这与您已经编写的代码类似。
  5. This simple example does not handle the case where the area light is "partially below the horizon" -- i.e. not all 4 vertices are above the plane of the face.
  6. 这个简单的例子没有处理区域光“部分低于地平线”的情况——也就是说,不是所有四个顶点都在平面上。
  7. Since WebGLRenderer does not support area lights, you can't "add the light to the scene" and expect it to work. This is why I pass all necessary data into the custom shader. ( WebGLDeferredRenderer does support area lights, of course. )
  8. 由于WebGLRenderer不支持区域灯光,你不能“添加灯光到场景”,并期望它工作。这就是为什么我将所有必要的数据都传递给定制的着色器。(当然,WebGLDeferredRenderer确实支持区域灯光。)
  9. Shadows are not supported.
  10. 不支持阴影。

three.js r.73

三。js r.73

#2


2  

Hm. Odd question! It seems like you started out with a very specific approximation and are now working your way backward to the right solution.

嗯。奇怪的问题!看起来你是从一个非常具体的近似开始的,现在正朝着正确的解决方案前进。

If we stick to only diffuse and a surface that is flat (has only one normal) what is the incoming diffuse light? Even if we stick to every incoming light has a direction and intensity, and we just take allin = integral(lightin) ((lightin).(normal))*light this is hard. so the whole problem is solving this integral. with point light you cheat by making it a sum and pulling the light out. That works fine for point lights without shadows etc. now what you really want to do is to solve that integral. that's what you can do with some kind of light probes, spherical harmonics or many other techniques. or some tricks to estimate the amount of light from a rectangle.

如果我们只停留在漫射和平坦的表面上(只有一个正常的),进来的漫射光是什么?即使我们坚持每一个入射光都有一个方向和强度,我们只要把所有的光都取下来(光)(光)。(正常的)*光这是很难的。所以整个问题就是解这个积分。有了点灯,你就可以把它变成一个和,然后把灯拉出来。这对于没有阴影的点光很适用,现在你真正想做的是解决这个积分。这就是你可以用一些光探针,球面谐波或者其他技术来做的。或者用一些方法来估计一个矩形的光量。

For me it always helps to think of the hemisphere above the point you want to light. You need all of the light coming in. Some is less important, some more. That's what your normal is for. In a production raytracer you could just sample a few thousand points and have a good guess. In realtime you have to guess a lot faster. And that's what your library code does: A quick choice for a good (but flawed) guess.

对我来说,它总是能帮助你想到你想要照亮的那个半球。你需要所有的光线进来。有些不那么重要,有些更重要。这就是你的正常状态。在一个生产射线追踪器中,你可以只采样几千个点,并有一个很好的猜测。在现实中,你必须更快地猜测。这就是你的库代码所做的:快速选择一个好的(但有缺陷的)猜测。

And that's where I think you are going backwards: You realized that they are making a guess, and that it sucks sometimes (that's the nature of guessing). Now, don't try to fix their guess, but come up with a better one! And maybe try to understand why they picked that guess. A good approximation is not about being good at corner cases but at degrading well. That's what this one looks like to me. (Again, sorry, I'm to lazy to read the three.js code now).

这就是我认为你在往后退的地方:你意识到他们在猜测,而且有时很糟糕(这就是猜测的本质)。现在,不要试图修正他们的猜测,但是想出一个更好的!也许试着去理解为什么他们选择了这个猜想。一个好的近似值并不是要擅长于角落处,而是要善于体面地处理。这就是我想要的。(再一次,抱歉,我懒得读这三个。js代码现在)。

So to answer your question:

所以为了回答你的问题:

  • I think you are going about it the wrong way. You are starting with a highly optimized idea, and are trying to fix that. Better to start from the problem.
  • 我认为你走错路了。你从一个高度优化的想法开始,并试图解决这个问题。最好从问题开始。
  • Solve one thing at a time. Your screenshot has a lot of specular, that is unrelated to your problem but very visual and was probably a big influence to the people designing the model.
  • 一次只解决一件事。你的屏幕截图有很多镜面,这与你的问题无关,但很直观,可能对设计模型的人有很大的影响。
  • You are on the right track and have a much better idea about rendering than most people. That can work for and against you. Read up on some modern game engines and their lighting models. You will always find a fascinating combination of hacks and deep understanding. The deep understanding is what drives picking the right hacks :)
  • 你在正确的轨道上,比大多数人对渲染有更好的想法。这对你是有好处的。阅读一些现代的游戏引擎和他们的照明模型。你总是会发现一个迷人的组合,技巧和深刻的理解。深刻的理解是选择正确的技巧的动力:)

Hope this helps. I might be totally wrong here and rambling at somebody who is just looking for some quick math, in that case I apologize.

希望这个有帮助。我可能是完全错了,随便找一个人在找一些简单的数学题,在那种情况下我道歉。

#3


1  

Let's agree that casting point is always on the edge.

让我们同意,铸造点总是在边缘。

Let's say that "lit part" is the part of space that is represented by extruded light's quad along its normal.

让我们假设,“被照亮的部分”是空间的一部分,它是由挤压光的四边形沿着它的正常轨道来表示的。

If surface point sits in the lit part, then you need to calculate the plane that holds that point, it's normal vector and light's normal. Intersection between that plane and light's would give you two points as options (only two, because casting point is always on the edge). So test those two to see which one contributes more.

如果表面点位于被点燃的部分,那么你需要计算保持那个点的平面,它是法向量和光线的正常。这个平面和光线的交点会给你两个点作为选项(只有两个点,因为浇注点总是在边缘上)。因此,测试这两种情况,看看哪一个贡献更大。

If the point is not in the lit part, then you could calculate four planes, each has surface point, its normal and one of the vertices of the light's quad. For each light-quad vertex you would have two points (vertex + one more intersection point) to test which contributes the most.

如果点不在点上,那么你可以计算4个平面,每一个都有表面点,它的正态和光的四边形的顶点之一。对于每一个光四顶点,你会有两点(顶点+一个交点)来测试哪个是最重要的。

This should do the trick. Please give me feedback if you encounter any counterexample.

这应该会奏效。如果你遇到任何反例,请给我反馈。

#4


1  

http://s3.hostingkartinok.com/uploads/images/2013/06/9bc396b71e64b635ea97725be8719e79.png

http://s3.hostingkartinok.com/uploads/images/2013/06/9bc396b71e64b635ea97725be8719e79.png

If I understand correctly:

如果我理解正确的话:

define L "Light for point x0"

定义L“点x0点的光”

L ~ K/S^2

L ~ K / S ^ 2

S = sqrt(y^2+x0^2)

S =√y ^ 2 + x0 ^ 2)

L = sum(k/(sqrt(y^2+x0^2))^2), y=0..infinity

L =总和(k /(√(y ^ 2 + x0 ^ 2))^ 2),y = 0 . .无穷

L = sum(k/(y^2+x0^2)), y=0..infinity, x > 0, y > 0

L =总和(k /(y ^ 2 + x0 ^ 2)),y = 0 . .无穷大,x > 0, y > 0。

L = integral(k/(y^2+x0^2)), y=0..infinity = k*Pi/(2*x0)

L =积分(k /(y ^ 2 + x0 ^ 2)),y = 0 . .∞= k *π/(2 * x0)

http://s5.hostingkartinok.com/uploads/images/2013/06/6dbb7b6d3babc092d3daf18bb3c6e6d5.png

http://s5.hostingkartinok.com/uploads/images/2013/06/6dbb7b6d3babc092d3daf18bb3c6e6d5.png

Answer:

答:

L = k*Pi/(2*x0)

L = k *π/(2 * x0)

k depends on the environment

k取决于环境。

#5


1  

it's been a while, but there is an article in gpu gems 5 that uses "the most important point" rather than the "nearest point" to approximate the illumination integral for area lights:

已经有一段时间了,但是gpu gems 5中有一篇文章使用了“最重要的点”而不是“最近点”来近似区域照明的照明积分:

http://gpupro.blogspot.com/2014/03/gpu-pro-5-physically-based-area-lights.html

http://gpupro.blogspot.com/2014/03/gpu-pro-5-physically-based-area-lights.html

#1


38  

The good news is there is a solution; but first the bad news.

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

Your approach of using the point that maximizes the dot product is fundamentally flawed, and not physically plausible.

你的方法是用点来最大化点积,从本质上讲是有缺陷的,而且在物理上是不可信的。

In your first illustration above, suppose that your area light consisted of only the left half.

在你上面的第一个例子中,假设你的区域光只有左边的一半。

The "purple" point -- the one that maximizes the dot-product for the left half -- is the same as the point that maximizes the dot-product for both halves combined.

“紫色”点——即最大限度地为左半边的点积——的点,与将两半组合的点积最大化的点是一样的。

Therefore, if one were to use your proposed solution, one would conclude that the left half of the area light emits the same radiation as the entire light. Obviously, that is impossible.

因此,如果一个人使用你的建议的解决方案,你会得出结论:该区域的左半边光发出的辐射与整个光的辐射相同。很明显,这是不可能的。

The solution for computing the total amount of light that the area light casts on a given point is rather complicated, but for reference, you can find an explanation in the 1994 paper The Irradiance Jacobian for Partially Occluded Polyhedral Sources here.

计算在给定的点上的区域光投射的总光量是相当复杂的,但是为了便于参考,你可以在1994年的论文中找到一种解释,即在这里部分遮挡的多面体源的辐照雅可比矩阵。

I suggest you look at Figure 1, and a few paragraphs of Section 1.2 -- and then stop. :-)

我建议您看一下图1和1.2节的几个段落——然后停止。:-)

To make it easy, I have coded a very simple shader that implements the solution using the three.js WebGLRenderer -- not the deferred one.

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

EDIT: Here is an updated fiddle: http://jsfiddle.net/hh74z2ft/1/

编辑:这里有一个更新的小提琴:http://jsfiddle.net/hh74z2ft/1/。

改进了WebGL和ThreeJS的区域照明。

The core of the fragment shader is quite simple

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

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

More Good News:

更多的好消息:

  1. This approach is physically correct.
  2. 这种方法在物理上是正确的。
  3. Attenuation is handled automatically. ( Be aware that smaller lights will require a larger intensity value. )
  4. 衰减是自动处理的。(要意识到较小的灯光需要更大的强度值。)
  5. In theory, this approach should work with arbitrary polygons, not just rectangular ones.
  6. 从理论上讲,这种方法应该适用于任意的多边形,而不仅仅是矩形的。

Caveats:

警告:

  1. I have only implemented the diffuse component, because that is what your question addresses.
  2. 我只实现了漫反射组件,因为这是您的问题地址。
  3. You will have to implement the specular component using a reasonable heuristic -- similar to what you already have coded, I expect.
  4. 您将必须使用一个合理的启发式方法实现specular组件——我想这与您已经编写的代码类似。
  5. This simple example does not handle the case where the area light is "partially below the horizon" -- i.e. not all 4 vertices are above the plane of the face.
  6. 这个简单的例子没有处理区域光“部分低于地平线”的情况——也就是说,不是所有四个顶点都在平面上。
  7. Since WebGLRenderer does not support area lights, you can't "add the light to the scene" and expect it to work. This is why I pass all necessary data into the custom shader. ( WebGLDeferredRenderer does support area lights, of course. )
  8. 由于WebGLRenderer不支持区域灯光,你不能“添加灯光到场景”,并期望它工作。这就是为什么我将所有必要的数据都传递给定制的着色器。(当然,WebGLDeferredRenderer确实支持区域灯光。)
  9. Shadows are not supported.
  10. 不支持阴影。

three.js r.73

三。js r.73

#2


2  

Hm. Odd question! It seems like you started out with a very specific approximation and are now working your way backward to the right solution.

嗯。奇怪的问题!看起来你是从一个非常具体的近似开始的,现在正朝着正确的解决方案前进。

If we stick to only diffuse and a surface that is flat (has only one normal) what is the incoming diffuse light? Even if we stick to every incoming light has a direction and intensity, and we just take allin = integral(lightin) ((lightin).(normal))*light this is hard. so the whole problem is solving this integral. with point light you cheat by making it a sum and pulling the light out. That works fine for point lights without shadows etc. now what you really want to do is to solve that integral. that's what you can do with some kind of light probes, spherical harmonics or many other techniques. or some tricks to estimate the amount of light from a rectangle.

如果我们只停留在漫射和平坦的表面上(只有一个正常的),进来的漫射光是什么?即使我们坚持每一个入射光都有一个方向和强度,我们只要把所有的光都取下来(光)(光)。(正常的)*光这是很难的。所以整个问题就是解这个积分。有了点灯,你就可以把它变成一个和,然后把灯拉出来。这对于没有阴影的点光很适用,现在你真正想做的是解决这个积分。这就是你可以用一些光探针,球面谐波或者其他技术来做的。或者用一些方法来估计一个矩形的光量。

For me it always helps to think of the hemisphere above the point you want to light. You need all of the light coming in. Some is less important, some more. That's what your normal is for. In a production raytracer you could just sample a few thousand points and have a good guess. In realtime you have to guess a lot faster. And that's what your library code does: A quick choice for a good (but flawed) guess.

对我来说,它总是能帮助你想到你想要照亮的那个半球。你需要所有的光线进来。有些不那么重要,有些更重要。这就是你的正常状态。在一个生产射线追踪器中,你可以只采样几千个点,并有一个很好的猜测。在现实中,你必须更快地猜测。这就是你的库代码所做的:快速选择一个好的(但有缺陷的)猜测。

And that's where I think you are going backwards: You realized that they are making a guess, and that it sucks sometimes (that's the nature of guessing). Now, don't try to fix their guess, but come up with a better one! And maybe try to understand why they picked that guess. A good approximation is not about being good at corner cases but at degrading well. That's what this one looks like to me. (Again, sorry, I'm to lazy to read the three.js code now).

这就是我认为你在往后退的地方:你意识到他们在猜测,而且有时很糟糕(这就是猜测的本质)。现在,不要试图修正他们的猜测,但是想出一个更好的!也许试着去理解为什么他们选择了这个猜想。一个好的近似值并不是要擅长于角落处,而是要善于体面地处理。这就是我想要的。(再一次,抱歉,我懒得读这三个。js代码现在)。

So to answer your question:

所以为了回答你的问题:

  • I think you are going about it the wrong way. You are starting with a highly optimized idea, and are trying to fix that. Better to start from the problem.
  • 我认为你走错路了。你从一个高度优化的想法开始,并试图解决这个问题。最好从问题开始。
  • Solve one thing at a time. Your screenshot has a lot of specular, that is unrelated to your problem but very visual and was probably a big influence to the people designing the model.
  • 一次只解决一件事。你的屏幕截图有很多镜面,这与你的问题无关,但很直观,可能对设计模型的人有很大的影响。
  • You are on the right track and have a much better idea about rendering than most people. That can work for and against you. Read up on some modern game engines and their lighting models. You will always find a fascinating combination of hacks and deep understanding. The deep understanding is what drives picking the right hacks :)
  • 你在正确的轨道上,比大多数人对渲染有更好的想法。这对你是有好处的。阅读一些现代的游戏引擎和他们的照明模型。你总是会发现一个迷人的组合,技巧和深刻的理解。深刻的理解是选择正确的技巧的动力:)

Hope this helps. I might be totally wrong here and rambling at somebody who is just looking for some quick math, in that case I apologize.

希望这个有帮助。我可能是完全错了,随便找一个人在找一些简单的数学题,在那种情况下我道歉。

#3


1  

Let's agree that casting point is always on the edge.

让我们同意,铸造点总是在边缘。

Let's say that "lit part" is the part of space that is represented by extruded light's quad along its normal.

让我们假设,“被照亮的部分”是空间的一部分,它是由挤压光的四边形沿着它的正常轨道来表示的。

If surface point sits in the lit part, then you need to calculate the plane that holds that point, it's normal vector and light's normal. Intersection between that plane and light's would give you two points as options (only two, because casting point is always on the edge). So test those two to see which one contributes more.

如果表面点位于被点燃的部分,那么你需要计算保持那个点的平面,它是法向量和光线的正常。这个平面和光线的交点会给你两个点作为选项(只有两个点,因为浇注点总是在边缘上)。因此,测试这两种情况,看看哪一个贡献更大。

If the point is not in the lit part, then you could calculate four planes, each has surface point, its normal and one of the vertices of the light's quad. For each light-quad vertex you would have two points (vertex + one more intersection point) to test which contributes the most.

如果点不在点上,那么你可以计算4个平面,每一个都有表面点,它的正态和光的四边形的顶点之一。对于每一个光四顶点,你会有两点(顶点+一个交点)来测试哪个是最重要的。

This should do the trick. Please give me feedback if you encounter any counterexample.

这应该会奏效。如果你遇到任何反例,请给我反馈。

#4


1  

http://s3.hostingkartinok.com/uploads/images/2013/06/9bc396b71e64b635ea97725be8719e79.png

http://s3.hostingkartinok.com/uploads/images/2013/06/9bc396b71e64b635ea97725be8719e79.png

If I understand correctly:

如果我理解正确的话:

define L "Light for point x0"

定义L“点x0点的光”

L ~ K/S^2

L ~ K / S ^ 2

S = sqrt(y^2+x0^2)

S =√y ^ 2 + x0 ^ 2)

L = sum(k/(sqrt(y^2+x0^2))^2), y=0..infinity

L =总和(k /(√(y ^ 2 + x0 ^ 2))^ 2),y = 0 . .无穷

L = sum(k/(y^2+x0^2)), y=0..infinity, x > 0, y > 0

L =总和(k /(y ^ 2 + x0 ^ 2)),y = 0 . .无穷大,x > 0, y > 0。

L = integral(k/(y^2+x0^2)), y=0..infinity = k*Pi/(2*x0)

L =积分(k /(y ^ 2 + x0 ^ 2)),y = 0 . .∞= k *π/(2 * x0)

http://s5.hostingkartinok.com/uploads/images/2013/06/6dbb7b6d3babc092d3daf18bb3c6e6d5.png

http://s5.hostingkartinok.com/uploads/images/2013/06/6dbb7b6d3babc092d3daf18bb3c6e6d5.png

Answer:

答:

L = k*Pi/(2*x0)

L = k *π/(2 * x0)

k depends on the environment

k取决于环境。

#5


1  

it's been a while, but there is an article in gpu gems 5 that uses "the most important point" rather than the "nearest point" to approximate the illumination integral for area lights:

已经有一段时间了,但是gpu gems 5中有一篇文章使用了“最重要的点”而不是“最近点”来近似区域照明的照明积分:

http://gpupro.blogspot.com/2014/03/gpu-pro-5-physically-based-area-lights.html

http://gpupro.blogspot.com/2014/03/gpu-pro-5-physically-based-area-lights.html