2013-03-25 164 views
9

我一直在閱讀大量關於光線追蹤和陰影的文章,但我的光線追蹤圖像看起來不太好。我正在談論鏡面高光附近非常明亮的綠色區域。結果綠色在這裏最大,看起來像。 如何調整顏色和/或陰影計算以使其看起來正確?光線追蹤 - 如何將漫反射和鏡面反射色相結合?

(不要介意愚蠢的代碼,我只是試圖讓原則正確第一)。

下面是它的外觀:

enter image description here

這裏只有擴散成分:

enter image description here

這裏只是鏡面分量:

enter image description here

編輯:改變漫反射到顏色diffuseColor = ColorMake(0.0f,0.6f,0.0f); 然後圖像看起來是這樣的:

enter image description here

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]; 

回答

6

問題是,當你計算出球的漫反射顏色你已經是1或非常接近1個像素的小區域(以綠色通道)。將「phong」分量(在所有通道中具有接近1的值)添加到該分量中,會得到> = 1的像素區域。然後,當您將顏色值限制爲1時,該區域> = 1出。

您可以使用圖片編輯程序進行測試,並對兩層進行「疊加」疊加(擴散層以上的phong層)。這給你看到的結果 - 以及預期的結果。

您可以通過一些措施,避免問題:

  1. 可以調暗光源的一點,那就是乘漫強度,你計算的形式,通過亮度餘弦 - 比如說0.8或0.7 。
  2. 您可以限制球體的顏色飽和度(即綠色)並使球體不會變綠;)
  3. 使用色調映射運算符將像素的顏色值標準化爲[0..1]範圍 - 但是這個話題非常廣泛 - 維基百科可能會給出一個很好的介紹。你甚至不必全面使用這些,至於非基於物理的渲染更簡單的色調映射操作符可能就足夠了,併產生令人愉快的結果。

我的光線追蹤實驗可追溯到幾年前,但您可以嘗試這些事情。


更新1:

一件事我注意到,當你伽瑪糾正你的輸出圖像 - 效果不太明顯;) - 行,就是有點片狀。

最終的解決方案是去phsically正確或只使用另一個着色模型:Wikipedia on Specular highlight


更新2:

一個實際的解決辦法是計算出最終的像素顏色海防貢獻(這是你的變量mySpec)。這個想法是隻使用漫反射組件的一部分,其中鏡面反射實際上不是0,也就是說,如果你有一些鏡面反射組件,你實際上並沒有看到漫反射組件太多(或根本就沒有),所以它可以是調整:

float diffuseContrib = 1.f - mySpec; 

這應該看起來不錯,但我真的不知道正確它是如何實際上是:)。

然而請注意;這假定你的鏡面反射和散射分量在[0..1]範圍內。

我的結果看起來是這樣:

diffuse contribution calculated using the specular contribution

4

這早已與「鏡面+漫+環境」照明模式的問題。也就是說,這是一種黑客行爲,因此不能保證其正確性。

如果您非常熱衷於鞏固您的基礎知識,請參閱由Matt Pharr和Greg Humphreys撰寫的優秀書籍「物理光線追蹤」。

+0

這是不正確的,這是重點。不能有「正確性的保證」;) - 這實際上只是一種用便利的數學函數着色像素的方法(例如,用於phong的函數,以及用於環境的任意值)。至少這是我看到它的方式。最重要的是; PBRT FTW !! 1 – 2013-03-26 15:48:46

+0

雖然你的觀點是100%有效的,但很多進入光線追蹤的人都沒有意識到這一點 - 他們通常被漂亮的圖片所左右,不知道需要一大堆的調整:) – 2013-03-26 18:44:51

0

您應該閱讀Blinn/Phong model。這裏有一些示例着色器片段代碼。 基本上,您可以用單獨的角度縮放單個組件(環境,漫反射,鏡面術語)並添加它們。

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

0

爲什麼不在(燈+環境溫度)* +擴散鏡面?即在將漫反射光與陰影相乘之後添加鏡面反射分量?這將給予明確的亮點。