3

学校では、最近、独自のレイトレーサーの作成を開始しました。ただし、表示光線を計算するか、三角形と光線の交差をチェックすることで問題が発生しました。私の知る限り、カメラを原点に置き、カメラをその真正面のオブジェクトに向けて-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;
}

私の質問はかなり単純です。私は何が間違っているのですか?私はこのコードを調べてデバッグしましたが、エラーを特定することはできません。グーグルは、私が使用している本ですでに持っている理論以上のものを提供していません。また、コードをクリーンアップする前に動作させることに集中しているため、コードはまだかなりラフです。

前もって感謝します、

ケビン

4

1 に答える 1

1

何が悪いのか正確に言うのは難しい。特に、説明的な変数名(nX、nYなどとは何ですか??)を使用していないためです。

ここにいくつかのヒントがあります:

  • まず、表示コードのバグではないことを確認してください。交差点を偽造して、何かに当たったときに目に見える出力が得られることを証明します。たとえば、画面の右下にあるすべての光線を軸に沿った平面などに当てて、座標を簡単に確認できるようにします。
  • 最初に光線/球の交差を試してください。光線と三角形の交差点よりも簡単です。
  • すべてのコンポーネントを手動で計算するのではなく、ベクトル/行列演算を使用することを検討してください。乱雑な文字の多くの行を間違えるのは簡単すぎます。
  • スケールの問題がある場合(たとえば、オブジェクトが小さすぎる場合)、世界座標と画面座標の間の変換を再確認してください。世界座標は小さな倍数の範囲(たとえば0.2 .... 5.0)になりますが、画面座標はビューサイズ(たとえば0 .. 1024)に応じたピクセル位置である必要があります。ほとんどの計算は世界座標で行う必要があり、レンダリングコードの最初と最後で画面座標との間で変換するだけです。
  • デバッガーでトップレベルのレイトレーシングコードをステップ実行し、各画面座標(特に画面の隅)に対して適切な方向に光線を生成していることを確認します。
  • カメラの方向がターゲットオブジェクトを指していることを確認してください。まったく反対の方向を向いているのは非常に簡単な間違いです。

動作するはずのセットアップ例:

  • カメラの位置[004]
  • オブジェクトの位置[000]
  • Camera DIRECTION [0 0 -1](原点に向けて見たい場合は、マイナスに注意してください!)
  • UPベクトル[00.750]
  • 右ベクトル[+/-10 0]

次に、光線の方向は次のようになります(ピクセル[screenX、screenY]の場合):

ray = DIRECTION +(2 *(screenX / screenWidth)-1)* RIGHT +(1-2 *(screenY / screenHeight))* UP

ray = normalize(ray)

于 2012-10-26T17:57:18.173 に答える