光线跟踪 - 几何球体交点 - 尽管没有交叉,但交叉函数对所有光线都返回true

时间:2014-12-16 18:08:50

标签: c++ opengl geometry intersection raytracing

我正在用C ++和OpenGL编写一个光线追踪项目,并且我的球体交叉功能遇到了一些障碍:我检查了多个来源并且数学看起来正确,但由于某些原因,对于每一条射线,交集方法返回true。以下是球体交叉函数的代码以及其他一些澄清的代码:

bool intersect(Vertex & origin, Vertex & rayDirection, float intersection)
{
    bool insideSphere = false;
    Vertex oc = position - origin;
    float tca = 0.0;
    float thcSquared = 0.0;

    if (oc.length() < radius)
        insideSphere = true;

    tca = oc.dot(rayDirection);

    if (tca < 0 && !insideSphere)
        return false;

    thcSquared = pow(radius, 2) - pow(oc.length(), 2) + pow(tca, 2);

    if (thcSquared < 0)
        return false;

    insideSphere ? intersection = tca + sqrt(thcSquared) : intersection = tca - sqrt(thcSquared);

    return true;
}

以下是调用交集函数的光线跟踪函数的一些上下文。仅供参考我的相机位于(0,0,0),这就是我的#34;起源&#34;光线跟踪功能中的变量:

#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480

#define WINDOW_METERS_WIDTH 30
#define WINDOW_METERS_HEIGHT 20
#define FOCAL_LENGTH 25


rayDirection.z = FOCAL_LENGTH * -1;
for (int r = 0; r < WINDOW_HEIGHT; r++)
{
    rayDirection.y = (WINDOW_METERS_HEIGHT / 2 * -1) + (r * ((float)WINDOW_METERS_HEIGHT / (float)WINDOW_HEIGHT));
    for (int c = 0; c < WINDOW_WIDTH; c++)
    {
        intersection = false;
        t = 0.0;

        rayDirection.x = (WINDOW_METERS_WIDTH / 2 * -1) + (c * ((float)WINDOW_METERS_WIDTH / (float)WINDOW_WIDTH));

        rayDirection = rayDirection - origin;

        for (int i = 0; i < NUM_SPHERES; i++)
        {
            if (spheres[i].intersect(CAM_POS, rayDirection, t))
            {
                intersection = true;
            }
        }

感谢您查看是否有任何其他可能有用的代码让我知道!

1 个答案:

答案 0 :(得分:2)

看来你的数学有点混乱了。函数的第一部分,即直到第一个return false,是正常的,如果光线从球体外部开始并且没有朝向它,则返回false。但是,我认为你把相机放在你所有球体的外面,这样所有球体都是可见的,这就是为什么这个部分永远不会丢失的原因。

thcSquared确实是错的,我不知道应该代表什么。

让我们以数学方式进行交叉。我们有:

  • origin:光线的开始,我们称之为A
  • rayDirection:无限光线的方向,我们称之为d
  • position:球体的中心,名为P
  • radius:不言自明,名为r

你想要的是球体和线条上的一个点,我们称之为M

  • M = A + t * d因为它在线
  • |M - P| = r因为它在球体上

第二个等式可以更改为|A + t * d - P|² = r²,即(A - P)² + 2 * t * (A - P).dot(d) + t²d² = r²。这是一个简单的二次方程。一旦解决,你有0,1或2个解决方案,选择最接近光线原点(但它是正的)。

编辑:您将被迫使用其他方法,我将在此详细说明:

  1. 计算球体中心与线条之间的距离(称之为l)。这是通过在线上“投射”中心来完成的。所以:

    tca = ( (P - A) dot d ) / |d|,或您的变量名称tca = (OC dot rd) / |rd|。预测为H = A + tca * dl = |H - P|

  2. 如果l > R然后返回false,则没有交集。

  3. 让我们调用M一个交叉点。三角形MHP有一个直角,所以MH² + HP² = MP²,换句话为thc² + l² = r²,所以我们现在有thc,即H到球体的距离。

  4. 尽管如此,t = tca +- thc,只需取两者中最低的非负数。

  5. 你链接的论文解释了这一点,但没有说它假设光线方向的范数是1.我没有看到代码中的规范化,这可能是你的代码失败(未经验证)的原因。 / p>

    旁注:3d矢量的名称Vertex选择得非常糟糕,Vector3vec3会更好。