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 番目の球体だけの写真です。
(出典: 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 に上げてテストしましたが、問題は解決しませんでした。
- 法線。
球の法線を正しく計算していると確信しています。交点を取り、球の中心を引き、半径で割ります。