【问题标题】:Raytracer, computing viewing rays (Java)Raytracer,计算观察光线(Java)
【发布时间】:2012-10-29 08:20:15
【问题描述】:

为了学校,我最近开始创建自己的光线追踪器。但是,我在计算观察光线或检查三角形和光线之间的交点时遇到了障碍。据我所知,计算似乎执行正确,因为我将相机放在原点并让它面向 -z 轴朝向它前面的对象,从而允许手动进行简单的矢量数学运算。一切似乎都已检查完毕,但屏幕上没有任何内容。

我将发布我正在使用计算视角的代码。

public Ray generateRay(float nX, float nY , Point2f coordinates)
{
    // Compute l, r, b and t.
    Vector3f temp = VectorHelper.multiply(u, nX/2.0f);
    float r = temp.x + Position.x;
    temp = VectorHelper.multiply(u, -nX/2.0f);
    float l = temp.x + Position.x;
    temp = VectorHelper.multiply(v, nY/2.0f);
    float t = temp.y + Position.y;
    temp = VectorHelper.multiply(v, -nY/2.0f);
    float b = temp.y + Position.y;

    // Compute the u and v coordinates.
    float uCo = (l + (r - l) * (coordinates.x + 0.5f)/nX);
    float vCo = (b + (t - b) * (coordinates.y + 0.5f)/nY);

    // Compute the ray's direction.
    Vector3f rayDirection = VectorHelper.multiply(w, -FocalLength);
    temp = VectorHelper.add(VectorHelper.multiply(u, uCo), VectorHelper.multiply(v, vCo));
    rayDirection = VectorHelper.add(rayDirection, temp);
    rayDirection = VectorHelper.add(rayDirection, Position);
    rayDirection = VectorHelper.normalize(VectorHelper.add(rayDirection, temp));

    // Create and return the ray.
    return new Ray(Position, rayDirection);
}

以下代码是我用来计算交点的代码。它使用克莱默法则来求解矩阵方程。

public static Point3f rayTriangleIntersection(
        Ray ray, Point3f vertexA, Point3f vertexB, Point3f vertexC)
{
    // Solve the linear system formed by the ray and the parametric surface
    // formed by the points of the triangle.
    // | a d g |   | B |   | j |
    // | b e h | * | Y | = | k |
    // | c f i | * | t | = | l |
    // The following uses Cramer's rule to that effect.
    float a = vertexA.x - vertexB.x; float d = vertexA.x - vertexC.x; float g = ray.getDirection().x;
    float b = vertexA.y - vertexB.y; float e = vertexA.y - vertexC.y; float h = ray.getDirection().y;
    float c = vertexA.z - vertexB.z; float f = vertexA.z - vertexC.z; float i = ray.getDirection().z;

    float j = vertexA.x - ray.getOrigin().x;
    float k = vertexA.y - ray.getOrigin().y;
    float l = vertexA.z - ray.getOrigin().z;

    // Compute some subterms in advance.
    float eihf = (e * i) - (h * f);
    float gfdi = (g * f) - (d * i);
    float dheg = (d * h) - (e * g);
    float akjb = (a * k) - (j * b);
    float jcal = (j * c) - (a * l);
    float blkc = (b * l) - (k * c);
    // Compute common division number.
    float m = (a * eihf) + (b * gfdi) + (c * dheg);

    // Compute unknown t and check whether the point is within the given
    // depth interval.
    float t = -((f * akjb) + (e * jcal) + (d * blkc)) / m;
    if (t < 0)
        return null;

    // Compute unknown gamma and check whether the point intersects the
    // triangle.
    float gamma = ((i * akjb) + (h * jcal) + (g * blkc)) / m;
    if (gamma < 0 || gamma > 1)
        return null;

    // Compute unknown beta and check whether the point intersects the
    // triangle.
    float beta = ((j * eihf) + (k * gfdi) + (l * dheg)) / m;
    if (beta < 0 || beta > (1 - gamma))
        return null;

    // Else, compute the intersection point and return it.
    Point3f result = new Point3f();
    result.x = ray.getOrigin().x + t * ray.getDirection().x;
    result.y = ray.getOrigin().y + t * ray.getDirection().y;
    result.z = ray.getOrigin().z + t * ray.getDirection().z;
    return result;
}

我的问题很简单。我究竟做错了什么?我已经查看并调试了这段代码,无法找出错误,谷歌提供的只是我正在使用的书中已有的理论。此外,代码仍然相当粗糙,因为我只是专注于在清理之前让它工作。

提前致谢,

凯文

【问题讨论】:

  • 对我来说没有什么错...但是如果一切似乎都在调试模式下检查出来,也许您在显示步骤中做错了什么?我会尝试将 Ray tracer 代码放在一边,并尝试使用相同的显示代码打印一个测试用例,并确保它有效。

标签: java


【解决方案1】:

很难准确地说出了什么问题。特别是因为您没有使用描述性变量名称(什么是 nX、nY 等??)

这里有一些提示:

  • 首先确保它不是您的显示代码中的错误。伪造一个十字路口以证明您在撞到某物时会获得可见的输出,例如使屏幕右下角的所有光线都照射到轴对齐的平面或类似的东西上,这样您就可以轻松验证坐标
  • 首先尝试射线/球体相交。它比射线/三角形相交更容易。
  • 考虑使用向量/矩阵运算,而不是手动计算所有分量。多行乱七八糟的字母太容易出错了。
  • 如果您遇到比例问题(例如对象太小),请仔细检查您在世界坐标和屏幕坐标之间的转换。世界坐标将在小的双数范围内(例如 0.2 ....5.0),而屏幕坐标应该是根据您的视图大小的像素位置(例如 0 .. 1024)。您应该在世界坐标中进行大部分数学运算,只在渲染代码的开头和结尾转换屏幕坐标。
  • 在调试器中单步调试顶级光线跟踪代码,并确保为每个屏幕坐标(尤其是屏幕的角落)生成合理方向的光线
  • 检查您的相机方向是否指向目标对象。让它朝完全相反的方向看是很容易的错误!

应该工作的示例设置:

  • 摄像头位置 [0 0 4]
  • 对象位置 [0 0 0]
  • Camera DIRECTION [0 0 -1](如果您希望它朝向原点,请注意减号!)
  • 向上向量 [0 0.75 0]
  • 右向量 [+/-1 0 0]

那么你的光线方向应该是这样的(对于一个像素 [screenX, screenY]):

射线 = 方向 + (2*(screenX / screenWidth)-1)*RIGHT + (1-2*(screenY/screenHeight))*UP

射线 = 归一化(射线)

【讨论】:

  • 我一直在尝试一些调试的东西,比如第一个建议,但我会尝试一些更硬编码的东西。我会看一下光线-球体的交集,它听起来确实更容易,如果这比我至少知道这两个函数中的哪一个没有做它应该做的事情。感谢您的帮助!
  • 感谢您 (mikera) 和 durron 的建议,我已经找到了错误,而且我几乎不好意思承认它很简单。虽然代码中有一些小错误,但主要问题在于我的球体很小......换句话说,你只是看不到它。现在我只测试了正交透视,但是带有透视的版本应该也可以。无论如何,感谢您提供有用的建议。
  • 显然我操之过急。仅当相机也很远时,增加对象大小才有意义。我基本上在 (0, 0, 4) 位置有一个相机,看着 (0, 0, -1)。然后我在中心有一个半径为 1.5 的球体。这应该出现在屏幕上,不是吗?考虑到相机和球体之间的距离是如此之小。然而,我必须让球体的半径为 50 或更大,才能在屏幕中心看到更多的几个或红点。结果,我再次检查了光线的方向。也许我会在另一条评论中发布相关数字。
  • 当程序到达屏幕中心或多或少的一个像素时,我基本上设置了一个断点,在这种情况下应该会导致一个交叉点。面板大小为 (640, 480),正在处理的坐标为 (299,277),当我重新定向到屏幕中心和像素中心时得到的坐标是 (-12.5, 6.5)。随后,我计算了方向向量并对其进行归一化,得到的是(-0.88665867, 0.4610625, -0.035466347)。
  • 我由此推断出方向向量全错了。如果它是屏幕的中心,z 分量不应该是最大的,因为光线基本上是直线前进的吗?相反,它向左飞得更远。这可能是问题吗?
猜你喜欢
  • 2011-08-22
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多