反射 3D 光线 space

Reflect light in 3D space

我正在尝试将光反射到 3D 的三角形表面上 space。一切正常,直到我将光源移到三角形的背面。

看起来,当光线朝向三角形的背面时,光线会被反射,就像光源在三角形的另一边一样。反射光的 theta(入射光和反射光之间的角度)也将是法线(绿线)的一半而不是两倍。

在提供的图像上,黄点是光源,白线是入射光,绿线是三角形的法线,红线是反射光

    public Location Reflect(Line A, ref Line B)
    {
        double lA = A.length;
        double lB = B.length;

        Location unitA = (A.Head - A.Tail) / lA;
        Location unitB = (B.Head - B.Tail) / lB;
        Location result = (unitB - (unitA - unitB)) * lA;

        return result;
    }

临时解决方案:

            if (Line.theta(A, B) < 0)
            unitB *= -1;

结果:

法线和光源在同一侧时的反射

法线和光源在相对侧时的反射

我没有使用任何额外的 3D 资源。一切都是用纯 C# 编码的。

任何修复它的帮助将不胜感激。感谢您的时间。

这个行为真的很正确,让我解释一下反射是如何计算的,发生了什么以及如何解决它。

3D 环境中的每个多边形都有一个称为 法线 的矢量,法线是定义其正面方向的矢量。

法向量是使用多边形顶点计算的,根据顺时针或逆时针计算,法向量将面向正面或背面。

来自维基百科的伪代码:

Begin Function CalculateSurfaceNormal (Input Triangle) Returns Vector

    Set Vector U to (Triangle.p2 minus Triangle.p1)
    Set Vector V to (Triangle.p3 minus Triangle.p1)

    Set Normal.x to (multiply U.y by V.z) minus (multiply U.z by V.y)
    Set Normal.y to (multiply U.z by V.x) minus (multiply U.x by V.z)
    Set Normal.z to (multiply U.x by V.y) minus (multiply U.y by V.x)

    Returning Normal

End Function

如果光线从背面射出,而法线朝向正面,反之亦然,那么反射将在发生在您身上时反转。

我看到你把法线表示为一条线,这个概念是错误的,法线没有像线段那样的起点和终点,它只存储一个角度,所以它是一个单位向量(参考来自维基百科:https://en.wikipedia.org/wiki/Unit_vector).

无论如何,要解决您的问题,您需要检查法线和入射光线之间的角度是否大于 180º,如果是这种情况,则反转法线,这将模拟一个双面多边形。

为此,首先计算从光源到面部的 angular 向量 (Normalize(LightPosition - FacePosition)),然后检查该向量与法线之间的角度。

这里有一个很好的解释如何计算两个向量之间的角度:http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors

着色器上用于计算点光源照明的典型函数正是您要计算的,它通常具有以下形式:

 float factor = clamp(dot(lightNormal, faceNormal), 0.0, 1.0);

两个向量的点积会给你一个介于 -1 和 1 之间的值,你可以用它来检查是否必须反转角度:

bool reversed = Dot(LightNormal, FaceNormal) < 0;

你可以在 Internet 上找到很多矢量的实现及其 c# 的计算(归一化、点积、叉积、长度等),如果你想要一些在未来也可以推进到 OpenGL 的东西,你可以使用每个示例 OpenTK,它具有向量的所有数学内容并且非常易于使用,否则您也可以转到 OpenTK 源代码并获取您需要的功能(或者当然您可以搜索数学解释并通过你自己,这将是最好的选择,因为你会理解所有的工作原理,但这将是最困难的方法。

干杯。