在3D空间中反射光线

时间:2015-12-18 13:12:04

标签: c# math 3d

我试图将光反射到3D空间的三角形表面上。一切正常,直到我将光源移动到三角形的背面。

当光线面向三角形的背面时,光线会被反射,好像光源位于三角形的另一侧。反射光的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;

结果:

正常光源和光源位于同一侧时的反射 Reflection when Normal and light source are on the same side

正常光源和光源位于相对侧时的反射 Reflection when Normal and light source are on opposite sides

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

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

1 个答案:

答案 0 :(得分:1)

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

3D环境中的每个poligon都有一个名为 normal 的向量,法线是定义它的正面方向的向量。

使用poligon顶点计算法线向量,并且如果顺时针或逆时针进行此计算,法线将面向前方或后方。

来自维基百科的伪代码:

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°,如果是这种情况则反转法线,这将模拟双面多边形。

为此,首先计算从光源到面部的角度矢量(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;

你可以在互联网上找到很多矢量的实现和它的c#计算(规范化,点积,交叉积,长度等),如果你想要的东西也允许将来推进到你可以使用的OpenGL示例OpenTK,它具有所有向量的数学内容并且非常易于使用,否则您也可以转到OpenTK源代码并获取所需的功能(当然,您可以搜索数学解释并自行实现,这将是最好的选择,因为你将了解所有的工作方式,但这将是最难的方法。)

干杯。