【问题标题】:Ray-tracing triangles光线追踪三角形
【发布时间】:2016-11-12 14:32:03
【问题描述】:

我正在用 java 编写一个光线追踪器,我能够追踪球体,但我认为我追踪三角形的方式有问题。

据我所知,这是基本算法:

  1. 首先确定射线是否与三角形所在的平面相交。
  2. 剪裁所有点,使它们与三角形位于同一平面上(以xy 平面为例)。
  3. 根据您在沿新平面向任意方向发出光线时穿过的多边形边的数量,确定潜在的交点是落在三角形内部还是外部。

现在,这是我的实现(特别是第一点):

public Vector getIntersectionVector(Ray ray)
{
    Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal());
    if (planeIntersectionVector != null)
    {
        if (isIntersectionVectorInsideTriangle(planeIntersectionVector))
        {
            return planeIntersectionVector;
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
}

getPlaceIntersectionVector() 在哪里:

private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal)
{
    double vd = planeNormal.dotProduct(ray.getDirection());
    //(p_n \dot r_d) == 0, parallel. (p_n \dot r_d) > 0 Plane normal pointing away from ray.
    if (vd >= 0)
    {
        return null;
    }
    double distance = planeNormal.distance(0d, 0d, 0d);
    double vo = -(planeNormal.dotProduct(ray.getOrigin()) + distance);
    double intersectionDistance = vo / vd;

    //intersectionDistance <= 0 means the "intersection" is behind the ray, so not a real intersection
    return (intersectionDistance <= 0) ? null : ray.getLocation(intersectionDistance);
} 

基本上是在模仿这个:

还有这个:

其中t是点击中沿射线的距离,ro是射线的原点,rd是射线的方向, pn指的是三角形/平面的平面法线,d是三角形所在平面到原点(0,0,0)的距离@

我做错了吗?当我从图像(0,0) 中的第一个像素发出光线时,我看到intersectionDistance(或t)几乎是1100,这在我看来直觉上是错误的。我认为交叉点会更近。

以下是相关数据: 射线原点(0,0,1),射线方向大致为(0.000917, -0.4689, -0.8833)。
三角形的顶点为(-0.2, 0.1, 0.1)、(-0.2, -0.5, 0.2)、(-0.2, 0.1, -0.3),这使得平面正常(-1, 0, 0)。
根据我的代码,Ray 与距离 1090 的平面相交,正如我之前提到的,这对我来说似乎是错误的。场景在各个方向上只有-1.0到1.0,这意味着距离很远。
我做错飞机交叉口了吗?

如果您需要更多信息,请告诉我在哪里澄清要点。

【问题讨论】:

    标签: java algorithm 3d intersection raytracing


    【解决方案1】:

    问题出在这一行:

    double distance = planeNormal.distance(0d, 0d, 0d);
    

    平面由法线和从平面到原点的距离定义。向量到原点的距离是向量的长度,所以你计算的只是平面法线的长度(如果已经标准化,它将始终为 1.0)。

    平面到原点的距离是一个额外的信息,需要传递给你的函数,你不能只从法线计算它,因为它独立于它(你可以有很多平面法线指向同一方向,距原点不同距离)。

    所以像这样定义你的函数:

    private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal, double planeDistance)
    

    然后这样称呼它:

    Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal(), getPlaneDistance());
    

    然后你可以这样计算vo:

    double vo = -(planeNormal.dotProduct(ray.getOrigin()) + planeDistance);
    

    【讨论】:

    • 假设我从三角形的法线定义了平面。在这种情况下,我如何获得从飞机到原点的距离?从this answer 开始,我认为它只是平面中法线和向量(在本例中为顶点之一)之间的点积,但这似乎是错误的,因为现在交点约为 218。
    • “我认为这只是平面中法线和向量之间的点积” - 这应该是正确的。仔细检查您的平面法线向量是否已归一化
    • 其实,你确定结果不正确?相交距离是在射线方向,而不是平面上最近点到射线原点的距离。由于您的光线几乎垂直于平面的法线(在平面法线方向上的值仅为 0.000917),因此您必须在相交之前沿该方向行进很远。
    • 好点。我想那可能是正确的。谢谢!这基本上解决了我现在遇到的问题。
    【解决方案2】:

    略有不同的方法:

    让我们的三角形顶点是V0, V1, V2
    边向量是

    A = V1-V0
    B = V2 - V0
    

    Ray 有参数方程(如你所写)

    P = R0 + t * Rd
    

    从另一边看,交点在三角形平面上有参数坐标u,v

    P = V0 + u * A + v * B
    

    因此,您可以为 x、y、z 坐标编写三线性方程组并求解 t, u, v。如果行列式 ius 非零(射线不平行于平面),并且t &gt;=0 和u, v, u+v 位于0..1 范围内,则 P 在三角形内。

    R0.X + t * Rd.X = V0.X + u * A.X + v * B.X
    R0.Y + t * Rd.Y = V0.Y + u * A.Y + v * B.Y
    R0.Z + t * Rd.Z = V0.Z + u * A.Z + v * B.Z
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-09
      • 2019-12-01
      • 2017-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      相关资源
      最近更新 更多