10

レイトレーシングとシェーディングに関する記事をたくさん読んでいますが、レイトレーシングされた画像の見栄えがよくありません。鏡面ハイライトの近くの非常に明るい緑の領域について話しています。結果の緑色はここで最大になります、それはのように見えます。これを正しく見せるために、色やシェーディングの計算を調整するにはどうすればよいですか?

(ばかげたコードを気にしないでください、私は最初に原則を正しくしようとしているだけです)。

外観は次のとおりです。

ここに画像の説明を入力してください

これは拡散コンポーネントのみです。

ここに画像の説明を入力してください

スペキュラコンポーネントのみを次に示します。

ここに画像の説明を入力してください

編集:diffuseをColordiffuseColor = ColorMake(0.0f、0.6f、0.0f);に変更します。次に、画像は次のようになります。

ここに画像の説明を入力してください

Point lightPosition = PointMake(-100.0f, 100.0f, -100.0f);
Color diffuseColor  = ColorMake(0.0f, 1.0f, 0.0f);
Color specularColor = ColorMake(1.0f, 1.0f, 1.0f);
Color pixelColor    = ColorMake(0.0f, 0.0f, 0.0f);

//  Trace...

            // Diffuse
            Point intersectionPosition = PointMake(x, y, z);
            Vector intersectionNormal = VectorMake((x - xs) / rs, (y - ys) / rs, (z - zs) / rs);
            Vector intersectionNormalN = VectorNormalize(intersectionNormal);
            Vector lightVector          = VectorSubtract(lightPosition, intersectionPosition);
            VectorlightVectorN         = VectorNormalize(lightVector);
            float      cosTheta        = VectorDotProduct(intersectionNormalN, lightVectorN);
            if (cosTheta < 0.0f)
            {
                cosTheta = 0.0f;
            }

            pixelColor = ColorMultScalar(diffuseColor, cosTheta);

            // Specular
            Vector incomVector    = VectorSubtract(intersectionPosition, lightPosition);
            Vector incomVectorN   = VectorNormalize(incomVector);

            float myDot = - VectorDotProduct(incomVectorN, intersectionNormalN);
            float myLen = 2.0f * myDot;

            Vector tempNormal     = VectorMultScalar(intersectionNormalN, myLen);
            Vector reflectVector  = VectorAdd(tempNormal, incomVectorN);
            Vector reflectVectorN = VectorNormalize(reflectVector);

            float mySpec = MAX(-VectorDotProduct(reflectVectorN, incomVectorN), 0);
            mySpec       = powf(mySpec, 5);

            specularColor = ColorMultScalar(specularColor, mySpec);
            pixelColor    = ColorAdd(pixelColor, specularColor);
            pixelColor    = ColorClamp(pixelColor);

            [self putPixelatX:i andY:j andR:pixelColor.r andG:pixelColor.g andB:pixelColor.b];
4

4 に答える 4

7

問題は、球の拡散色を計算するときに、1または1に非常に近い(緑のチャネル内の)ピクセルの小さな領域がすでにあることです。「phong」コンポーネント(すべてのチャネルで1に近い値を持つ)をそれに加算すると、1より大きいピクセルの領域が得られます。次にカラー値を1にクランプすると、=1より大きい領域が成り立ちます。アウト。

これは、画像編集プログラムを使用してテストし、2つのレイヤー(拡散レイヤーの上のフォンレイヤー)の「追加」オーバーレイを実行できます。これにより、表示される結果と、期待される結果が得られます。

この問題は、いくつかの方法で回避できます。

  1. 光源を少し暗くすることができます。つまり、コサインから計算した拡散強度に明るさを掛けます(たとえば、0.8または0.7)。
  2. 球の彩度(つまり緑)を制限して、球の彩度を低くすることができます;)
  3. トーンマッピング演算子を使用して、ピクセルのカラー値を[0..1]の範囲に正規化します。ただし、このトピックは広大ですが、ウィキペディアで十分な紹介が得られる場合があります。非物理ベースのレンダリングに関しては、より単純なトーンマッピング演算子で十分であり、目に心地よい結果が得られる可能性があるため、これらを完全に理解する必要はありません。

私のレイトレーシング実験は数年前にさかのぼりますが、これらのことを試すことができます。


アップデート1:

私が気づいたことの1つは、出力画像をガンマ補正すると、効果があまり目立たなくなります;)-OK、それはちょっとパッチがあります。

究極の解決策は、物理的に正しくするか、別のシェーディングモデルを使用することです:スペキュラーハイライトに関するウィキペディア


アップデート2:

実際の解決策の1つは、最終的なピクセルカラー(つまり変数mySpec)へのフォンの寄与を計算することです。アイデアは、鏡面反射光が実際には0ではない拡散反射光コンポーネントの一部のみを使用することです。つまり、鏡面反射光コンポーネントがある場合、実際には拡散反射光コンポーネントはそれほど(またはまったく)表示されないため、調整済み:

float diffuseContrib = 1.f - mySpec;

それは見栄えがするはずですが、実際にどれほど正しいかはわかりません:)。

ただし、注意してください。これは、鏡面反射光成分と拡散反射光成分が[0..1]の範囲にあることを前提としています。

私の結果はそのように見えます:

鏡面反射を使用して計算された拡散寄与

于 2013-03-25T16:51:27.890 に答える
6

これは、照明の「鏡面反射+拡散+周囲」モデルで長い間問題になっています。つまり、これはハックであるため、正確性を保証するものではありません。

最初にファンダメンタルズを固めることに熱心な場合は、MattPharrとGregHumphreysによる優れた本「PhysicallyBasedRayTracing」をご覧ください。

于 2013-03-25T21:20:57.117 に答える
1

Blinn/Phongモデルをよく読んでください。ここにいくつかのサンプルシェーダーフラグメントコードがあります。基本的に、単一のコンポーネント(アンビエント、ディフューズ、スペキュラーターム)をそれぞれの角度でスケーリングし、それらを合計します。

varying vec3 N;
varying vec3 v;    
void main (void)  
{  
   vec3 L = normalize(gl_LightSource[0].position.xyz - v);   
   vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)  
   vec3 R = normalize(-reflect(L,N));  

   //calculate Ambient Term:  
   vec4 Iamb = gl_FrontLightProduct[0].ambient;    

   //calculate Diffuse Term:  
   vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
   Idiff = clamp(Idiff, 0.0, 1.0);     

   // calculate Specular Term:
   vec4 Ispec = gl_FrontLightProduct[0].specular 
                * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
   Ispec = clamp(Ispec, 0.0, 1.0); 
   // write Total Color:  
   gl_FragColor = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;     
}

取得元:http ://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php

于 2013-08-28T18:10:47.820 に答える
1

(光+周囲)*拡散+鏡面反射をしないのはなぜですか?つまり、照明と影にディフューズを掛けた後、鏡面反射成分を追加しますか?これにより、明確なハイライトが得られます。

于 2014-03-01T21:50:16.070 に答える