1

全体をよりよく理解するために、基本的なレイトレーサーを作成しています。球体のディフューズ シェーディングです。次のソースからの数式を使用して、球の交差と拡散シェーディングを計算しました。

http://www.ccs.neu.edu/home/fell/CSU540/programs/RayTracingFormulas.htm

シェーディングを計算する私のコード (リンクでのソース コードの複製の試み) は前に示されています。ほとんどの場合、一部の球体では計算が正しく表示されることがありますが、ライトの位置によっては、球体のシェーディングがどの程度正しいか壊れているかによって異なります。

TVector intersect   (ray.getRayOrigin().getVectX() + t * (ray.getRayDirection().getVectX() - ray.getRayOrigin().getVectX()),
                    ray.getRayOrigin().getVectY() + t * (ray.getRayDirection().getVectY() - ray.getRayOrigin().getVectY()),
                    ray.getRayOrigin().getVectZ() + t * (ray.getRayDirection().getVectZ() - ray.getRayOrigin().getVectZ()));

//Calculate the normal at the intersect point
TVector NormalIntersect (intersect.getVectX() - (position.getVectX()/r), 
                        intersect.getVectY() - (position.getVectY()/r),
                        intersect.getVectZ() - (position.getVectZ()/r));

NormalIntersect = NormalIntersect.normalize();

//Find unit vector from intersect(x,y,z) to the light(x,y,z)
TVector L1 (light.GetPosition().getVectX() - intersect.getVectX(), 
            light.GetPosition().getVectY() - intersect.getVectY(),
            light.GetPosition().getVectZ() - intersect.getVectZ());
L1 = L1.normalize();
double Magnitude = L1.magnitude();

TVector UnitVector(L1.getVectX() / Magnitude,
                   L1.getVectY() / Magnitude,
                   L1.getVectZ() / Magnitude);

//Normalized or not, the result is the same
UnitVector = UnitVector.normalize();

float Factor = (NormalIntersect.dotProduct(UnitVector));
float kd = 0.9;             //diffuse-coefficient
float ka = 0.1;             //Ambient-coefficient
Color pixelFinalColor(kd * Factor * (color.getcolorRed())  +  (ka * color.getcolorRed()) ,
                      kd * Factor * (color.getcolorGreen())  + (ka * color.getcolorGreen())  ,
                      kd * Factor * (color.getcolorBlue()) +  (ka * color.getcolorBlue()) ,1);

拡散シェーディング エラー

写真からわかるように、一部の球は正しくシェーディングされているように見えますが、他の球は完全に壊れています。最初は UnitVector の計算に問題があるのではないかと思っていましたが、調べてみると問題を見つけることができませんでした。誰でも問題の理由を見ることができますか?

注: OpenGl を使用してシーンをレンダリングしています。

更新: 私はまだいくつかの問題を抱えていますが、皆さんの助けと、単位ベクトルの計算方法のいくつかの変更のおかげで、それらはほとんど解決されたと思います. 以下に示す更新。回答をくださった皆さん、どうもありがとうございました。

TVector UnitVector (light.GetPosition().getVectX() - intersect.getVectX(), 
                    light.GetPosition().getVectY() - intersect.getVectY(),
                    light.GetPosition().getVectZ() - intersect.getVectZ());

UnitVector = UnitVector.normalize();
float Factor = NormalIntersect.dotProduct(UnitVector);

//Set Pixel Final Color
Color pixelFinalColor(min(1,kd * Factor * color.getcolorRed())  +  (ka * color.getcolorRed()) ,
                      min(1,kd * Factor * color.getcolorGreen())  + (ka * color.getcolorGreen())  ,
                      min(1,kd * Factor * color.getcolorBlue()) +  (ka * color.getcolorBlue()) ,1);
4

2 に答える 2

1

通常の計算で中かっこを置き忘れました

TVector NormalIntersect ((intersect.getVectX() - position.getVectX())/r, 
                         (intersect.getVectY() - position.getVectY())/r,
                         (intersect.getVectZ() - position.getVectZ())/r);
于 2013-12-26T16:11:45.657 に答える
1

まず、あなたgetRayDirection()がそれが言うことをしているなら、それは視線ではなく方向を生成しているので、点である光線の原点をそこから差し引くべきではありません。(方向と点はどちらもベクトルで表されますが、方向に点を追加しても意味がありません)

また、正規化L1してから、その大きさを取り、その各成分をその大きさで割って を生成し、それを再度UnitVector呼び出します。これは不要です。最初の正規化後の の大きさは 1 です。同じベクトルを 3 回正規化しています。使用するだけです。normalizeL1L1

最後の問題は、クランプの問題です。呼び出す変数は、光の方向と法線の間の角度であるFactor値です。しかし、 の範囲があり、 のみの範囲が必要なため、その範囲にクランプする必要があります。cos(th)thcos(th)[1,-1][0,1]Factor

Factor = max(0, min( NormalIntersect.dotProduct(UnitVector), 1));

(そしてmin、プロダクションの呼び出しを削除しますcolor)。

このクランプは、法線がライトの反対側を向いている面に必要であり、負のcos(th)値になります。それらの法線と光の方向の間の角度は より大きいですpi/2。直観的に、それらは問題の光に対して可能な限り暗く見えるはずなので、それらを 0 にクランプします)。

これが動作するはずのコードの最終バージョンです。クラスにscale(float)and operator +(const TVector &)etc が定義されていると仮定して作業します。TVectorまた、簡潔にするために、次のように呼び出しNormalIntersectますnormal

TVector 
    intersect = ray.getRayOrigin() + ray.getRayDirection().scale(t),
    normal    = (intersect - position).normalize(),
    L1        = (light.GetPosition() - intersect).normalize();

float
    diffuse   = max(0, min(normal.dotProduct(L1), 1)),
    kd        = 0.1,
    ka        = 0.9;

Color pixelFinalColor = color.scale(kd * diffuse + ka);
于 2013-12-27T11:46:54.367 に答える