2

Eric Haines の Standard Procedural Database (SPD)から「マウント」シーンをレンダリングしようとしていますが、屈折部分は協力したくありません。私はそれを修正するために考えられるすべてを試しました。

これは私のレンダリングです(ワットの式を使用):

私のレンダリング。
(出典: philosoraptor.co.za )

これは、「通常の」式を使用した私のレンダリングです。

通常の式。
(出典: philosoraptor.co.za )

そして、これは正しいレンダリングです:

正しいレンダリング。
(出典: philosoraptor.co.za )

ご覧のとおり、ほとんどが球の極の周りにいくつかのエラーしかありません。これは、屈折、または何らかの精度エラーが原因であると私に思わせます。

シーンには実際には 4 つの球体があり、それらの NFF 定義 ( s x_coord y_coord z_coord radius) は次のとおりです。

s -0.8 0.8 1.20821 0.17
s -0.661196 0.661196 0.930598 0.17
s -0.749194 0.98961 0.930598 0.17
s -0.98961 0.749194 0.930598 0.17

つまり、前景のより明白な 3 つの球体の後ろに 4 番目の球体があります。それは、これら 3 つの球体の間に残された隙間に見られます。

これは、その 4 番目の球体だけの写真です。

「4番目」の球。
(出典: philosoraptor.co.za )

そして、これは最初の球だけの写真です:

「最初の」球。
(出典: philosoraptor.co.za )

私のバージョンと正しいバージョンの両方に存在する奇妙な点の多くが欠落していることに気付くでしょう。これらの効果は、球体間の相互作用の結果であると結論付けることができます。問題は、どの相互作用かということです。

私は何を間違っていますか?以下は、私がすでに検討した潜在的なエラーの一部です。

  • 屈折ベクトル式。

私が知る限り、これは正しいです。これは、いくつかの Web サイトで使用されているのと同じ式であり、私はその導出を個人的に検証しました。これが私がそれを計算する方法です:

double sinI2 = eta * eta * (1.0f - cosI * cosI);

Vector transmit = (v * eta) + (n * (eta * cosI - sqrt(1.0f - sinI2)));

transmit = transmit.normalise();

Alan Watt による 3D Computer Graphics、第 3 版で別の公式を見つけました。これにより、正しい画像に近づけることができます。

double etaSq = eta * eta;
double sinI2 = etaSq * (1.0f - cosI * cosI);
Vector transmit = (v * eta) + (n * (eta * cosI - (sqrt(1.0f - sinI2) / etaSq)));
transmit = transmit.normalise();

唯一の違いは、最後に eta^2 で割っていることです。

  • 全反射。

残りの交差コードの前に次の条件を使用して、これをテストしました。

if (sinI2 <= 1)
  • イータの計算。

この問題には、スタックのようなアプローチを使用します。

        /* Entering object. */
        if (r.normal.dot(r.dir) < 0)
        {
           double eta1 = r.iorStack.back();
           double eta2 = m.ior;
           eta = eta1 / eta2;

           r.iorStack.push_back(eta2);
        }
        /* Exiting object. */
        else
        {
           double eta1 = r.iorStack.back();
           r.iorStack.pop_back();
           double eta2 = r.iorStack.back();

           eta = eta1 / eta2;
        }

ご覧のとおり、これにより、この光線を含む以前のオブジェクトがスタックに格納されます。コードを終了すると、現在の IOR がスタックからポップされ、それを使用して、その下の IOR とともに eta が計算されます。私の知る限り、これが最も正しい方法です。

これは、ネストされた送信オブジェクトに対して機能します。ただし、交差する送信オブジェクトでは機能しません。ここでの問題は、交差点の IOR を個別に定義する必要があることです。これは、NFF ファイル形式では行われません。その場合、「正しい」行動方針が何であるかは不明です。

  • 新しい光線の原点を移動します。

新しい光線の原点は、前の光線と同じ点で交差しないように、送信されたパスに沿ってわずかに移動する必要があります。

p = r.intersection + transmit * 0.0001f;

p += transmit * 0.01f;

この値を (0.001f) と (0.0001f) に小さくしようとしましたが、球体がソリッドに見えます。これらの値では、光線が前の交点から十分に離れていないと思います。

編集: ここでの問題は、リフレクション コードが同じことをしていたことです。そのため、オブジェクトが屈折するだけでなく反射する場合、光線の原点は完全に間違った場所になります。

  • 光線の跳ね返りの量。

レイ バウンスの量を人為的に 4 に制限しました。この制限を 10 に上げてテストしましたが、問題は解決しませんでした。

  • 法線。

球の法線を正しく計算していると確信しています。交点を取り、球の中心を引き、半径で割ります。

4

2 に答える 2

3

画像の差分を行うことに基づく推測です(残りの質問を読まずに)。問題は、球の裏側の屈折にあるように見えます。次のような場合があります。

  • 逆方向に行う: たとえば、屈折率を逆にする (または逆にしない)。
  • それを完全に見逃していますか?

これを確認する 1 つの方法は、ほぼカメラに面している立方体を通してマウントを見ることです。屈折が正しい場合、画像はわずかにオフセットされますが、それ以外は変更されません。正しくないと、写真が少し傾いて見えます。

于 2010-08-23T04:18:22.933 に答える
0

それで、1年以上経って、ようやくここで何が起こっているのかを理解しました。クリアな心とそのすべて。私はその式から完全に脱線しました。代わりに、今は Heckbert による公式を使用しています。これは、幾何学と離散数学を使用して自分で証明したため、正しいと確信しています。

正しいベクトル計算は次のとおりです。

double c1 = v.dot(n) * -1;
double c1Sq = pow(c1, 2);

/* Heckbert's formula requires eta to be eta2 / eta1, so I have to flip it here. */
eta = 1 / eta;
double etaSq = pow(eta, 2);

if (etaSq + c1Sq >= 1)
{
   Vector transmit = (v / eta) + (n / eta) * (c1 - sqrt(etaSq - 1 + c1Sq));
   transmit = transmit.normalise();
...
}
else
{
   /* Total internal reflection. */
}

上記のコードでは、eta は eta1 (光線が来るサーフェスの IOR) と eta2 (宛先サーフェスの IOR) を重ね合わせたもので、v は入射光線、n は法線です。

問題をさらに混乱させる別の問題がありました。オブジェクトを終了するときに法線を反転する必要がありました(これは明らかです - 他のエラーがそれを覆い隠していたため、それを見逃していました)。

最後に、(サーフェスが点光源によって照らされているかどうかを判断する) 私の視線アルゴリズムは、透明なサーフェスを適切に通過していませんでした。

だから今、私の画像は正しく並んでいます:)

于 2012-02-03T16:16:36.333 に答える