光线追踪阴影问题

3

我在我的光线追踪器中遇到了阴影光线的问题。

请看以下两张图片:

3D sMax:

alt text http://neo.cycovery.com/shadow_problem.gif

我的光线追踪器:

alt text http://neo.cycovery.com/shadow_problem2.jpg

场景由一个非常明亮的光源照亮,从后方照射。它非常亮,以至于阴影没有渐变,只有黑色或白色(由于过度曝光)。

这两张图片都是使用3DStudioMax渲染的,并且都使用相同的几何形状,只是在一个版本中法线沿三角形进行了插值。

现在考虑表面上的红点。在未平滑版本中,它位于一个黑暗区域。这意味着光源从这个三角形面朝背面,因此不可见。

然而,在平滑版本中,它位于照亮的区域,因为插值法线会表明光线在该点可见(尽管三角形的实际几何形状面向光源的方向)。

我的问题是当光线跟踪阴影出现时。如果从红点向场景射出一个阴影光线,以测试光源是否可见(以确定阴影),则阴影光线将返回一个交点,无论是否插值法线(因为交点只取决于几何形状)。因此像素会被着暗色。
3dsamx正确处理了这种情况——渲染图像是使用启用光线跟踪阴影生成的。但是,当我在我的光线追踪器中开启光线跟踪阴影时,它也遇到了这个问题(在我的光线追踪器中,两种情况下该点都很暗,因为光线跟踪阴影确定了处于阴影中的点),我不知道如何解决它。
我希望有人知道这个问题以及如何处理它。
谢谢!

1
你正在进行普通平滑吗?位置在空间中是基于几何学的,但阴影状态是基于光源角度的,这又基于表面法线。因此,如果你没有对法线进行平滑处理,三角形上将会有相同的法线。 - Simeon Pilgrim
你的意思是什么?就像我说的,我在三角形之间插值法计算法线!问题不在于着色!问题在于光线追踪阴影!如果我关闭光线追踪阴影,一切看起来都很好(当然,没有阴影!) - Mat
Mat,你能否请附上另外两张图片吗:一张只有RT阴影而没有阴影和一张只有RT阴影而没有遮蔽吗? - avp
6个回答

3
“正确”的解决方案是将三角形进行细分,或者解出三角形所属表面的方程。我只见过细分法被使用。细分法可以让你更好地控制精度等等...
否则,你应该测试点上的法线(我相信“3DStudio”这样做),如果法线不朝向光源,就将该点设置为未照亮。这与“自阴影”没有任何关系。只有通过细分法才能轻松解决这个问题。祝你好运!

+1 只需将其细分到所需精度即可 :-) 我曾经读过 Pixar 将其细分到亚像素三角形,这应该完全消除了插值法的需要。这并不容易,但也不是一个 hack。 - phkahler
细分曲面在解决如此小的问题时似乎非常昂贵。如果根据法线弯曲表面并从该点发射阴影光线,则可以获得完美的结果。对于难以处理的问题,例如位移映射,请使用细分曲面。 - sapanoia
@sapanoia:对于这种特定情况是的,但您会为更扭曲的情况打赌吗?无论如何,我同意您的观点,对于简单情况可以使用更简单的解决方案。(顺便说一下,通过“弯曲表面”你是否意味着法线插值或者更复杂的东西?) - avp
@avp:我认为我想到的最终需要解决表面方程。然而,这可能太昂贵了,这可能是实现镶嵌的常见原因。 - sapanoia

0

我曾经遇到过同样的问题,在我的情况下,如果光线方向和法线的点积为正,则使用if语句解决了这个问题。

伪代码如下:

bool shadow_hit(light, shader_ctx){
   ....
   if(dot(light.dir, shader_ctx.normal) > 0) return false
   ...
   return true;
}

0

我不确定我是否正确理解了你的问题。 很难确定哪种版本/结果是通过哪种方法获得的,以及你认为哪个结果是正确的。

当你需要将阴影光线与三角形相交处理为特殊情况时,这不是情况吗? 你不进行几何相交,就像任何其他三角形一样, 而只是在插值法线和阴影光线之间进行方向检查。

或者更一般地说,当以下条件满足时,你会说阴影光线停在一个三角形上,任何一个三角形: a)它们相交,并且 b)相交点处的三角形插值法线方向与阴影光线相反。


你好! 我认为平滑后的3dsmax结果是正确的,我想要得到相同的结果。不幸的是,我不能将当前三角形视为特殊情况。如果当前三角形背对光源,则阴影射线将会进入我的对象中,并且由于它正在向内射入,所以当它再次离开对象时,它必须击中另一个三角形。 - Mat
为什么你要考虑与物体内部的三角形相交的情况呢? 无论如何,我更新了我的答案,采用了更一般的方法。 抱歉,我已经很久没有编写这方面的程序了。 - Tomek Szpakowicz
如果在投射阴影光线时不考虑背面多边形,那么例如一个平面无法将阴影投射到另一个平面上。 - Mat
这听起来像是一个黑客技巧.. 必须有一些通用的技术来处理这个问题。 - Mat
所以去读一下关于光线追踪“通用有效技术”的书吧。 我告诉你的是,平滑和非平滑物体在几何上没有区别。 只是每个点有不同的法向量。 你必须想办法使用它们。 思考一下。 - Tomek Szpakowicz
显示剩余2条评论

0
如何实现: 如果在某点插值的法线面向光源,那么表面可能会面向光源。如果朝向相反,则处于阴影中。
在第一种情况下,导致阴影的两个因素是其他物体和自身(如果您是凹形物体)。在另一个物体中很容易解决。
现在,在您自己的情况下,当您将射线投射到光源时,如果您真正是“内部凸点”,则进入并离开对象时会击中自己两次,因此处于阴影中。
如果您只被击中了一次,则必须位于光线照射的边缘处,但是我们知道在这一点上我们面对着光线(通过平滑的法线),这意味着我们没有被遮挡。

以上假设您没有对物体进行背面剔除处理,使其朝向光源。如果您这样做了,那么就不会存在相交情况。我认为这正是Tomek的观点。 - Simeon Pilgrim

0
Mat,我认为你的问题可能是因为你的阴影光线击中了与其起始点相同的三角形,因为它非常接近于切线(请注意,它发生在光影过渡的边界上)。解决这个问题有两种方法:一种方法是使用“偏差”,测试射线起点的距离,但我认为更好的解决方案是将射线的起始三角形存储一个引用。如果你对这个三角形进行测试,就简单地忽略它。
如果你正在使用像BVH这样的空间索引,那么在进行任何交叉测试之前,你可以尝试走出包含三角形的“盒子”,但这比前面提到的方法更加复杂,必须更加小心地处理。

0

在发射阴影光线时,将交点沿着光源方向微移是很正常的。

例如:shadowRay.dir = shadowRay.dir * 0.0001

这样可以避免阴影光线与主光线/反射光线/折射光线相交于同一物体表面。

也许你的问题就是因为没有进行这个操作?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接