2010-03-28 28 views
6

我已經實現了一個Phong照明方案,它使用一個以(0,0,0)爲中心並直接觀察球體基元的相機。以下是用於查看使用OpenGL以及使用我自己的實現來渲染場景的場景的場景文件的相關內容:OpenGL渲染與自己的Phong照明實現

ambient 0 1 0 

dir_light 1 1 1  -3 -4 -5 

# A red sphere with 0.5 green ambiance, centered at (0,0,0) with radius 1 
material 0 0.5 0 1 0 0 1 0 0 0 0 0 0 0 0 10 1 0 
sphere 0 0 0 0 1 

Here

通過OpenGL圖像產生的最終圖像。

Here

我渲染應用程序生成的圖像。

正如你所看到的,有這兩個之間的各種差異:

  1. 我的形象上的鏡面高光比一個在OpenGL小。
  2. 漫反射表面似乎不以正確的方式漫射,導致我的圖像中的黃色區域不需要很大,而在OpenGL中,有一個很好的深綠色區域更靠近球體底部
  3. 產生的顏色通過OpenGL比我的圖像中的要暗得多。

這些是我看到的最突出的三個差異。下面是我實現的Phong光照:

R3Rgb Phong(R3Scene *scene, R3Ray *ray, R3Intersection *intersection) 
{ 
    R3Rgb radiance; 
    if(intersection->hit == 0) 
    { 
    radiance = scene->background; 
    return radiance; 
    } 

    R3Vector normal = intersection->normal; 
    R3Rgb Kd = intersection->node->material->kd; 
    R3Rgb Ks = intersection->node->material->ks; 

    // obtain ambient term 
    R3Rgb intensity_ambient = intersection->node->material->ka*scene->ambient; 

    // obtain emissive term 
    R3Rgb intensity_emission = intersection->node->material->emission; 

    // for each light in the scene, obtain calculate the diffuse and specular terms 
    R3Rgb intensity_diffuse(0,0,0,1); 
    R3Rgb intensity_specular(0,0,0,1); 
    for(unsigned int i = 0; i < scene->lights.size(); i++) 
    { 
    R3Light *light = scene->Light(i); 
    R3Rgb light_color = LightIntensity(scene->Light(i), intersection->position); 
    R3Vector light_vector = -LightDirection(scene->Light(i), intersection->position); 

    // calculate diffuse reflection 
    intensity_diffuse += Kd*normal.Dot(light_vector)*light_color; 

    // calculate specular reflection 
    R3Vector reflection_vector = 2.*normal.Dot(light_vector)*normal-light_vector; 
    reflection_vector.Normalize(); 
    R3Vector viewing_vector = ray->Start() - intersection->position; 
    viewing_vector.Normalize(); 
    double n = intersection->node->material->shininess; 
    intensity_specular += Ks*pow(max(0.,viewing_vector.Dot(reflection_vector)),n)*light_color; 

    } 

    radiance = intensity_emission+intensity_ambient+intensity_diffuse+intensity_specular; 
    return radiance; 
} 

下面是相關LightIntensity(...)和LightDirection(...)功能:

R3Vector LightDirection(R3Light *light, R3Point position) 
{ 
    R3Vector light_direction; 
    switch(light->type) 
    { 
    case R3_DIRECTIONAL_LIGHT: 
     light_direction = light->direction; 
     break; 

    case R3_POINT_LIGHT: 
     light_direction = position-light->position; 
     break; 

    case R3_SPOT_LIGHT: 
     light_direction = position-light->position; 
     break; 
    } 
    light_direction.Normalize(); 
    return light_direction; 
} 

R3Rgb LightIntensity(R3Light *light, R3Point position) 
{ 
    R3Rgb light_intensity; 
    double distance; 
    double denominator; 
    if(light->type != R3_DIRECTIONAL_LIGHT) 
    { 
    distance = (position-light->position).Length(); 
    denominator = light->constant_attenuation + 
         light->linear_attenuation*distance + 
         light->quadratic_attenuation*distance*distance; 
    } 

    switch(light->type) 
    { 
    case R3_DIRECTIONAL_LIGHT: 
     light_intensity = light->color; 
     break; 

    case R3_POINT_LIGHT: 
     light_intensity = light->color/denominator; 
     break; 

    case R3_SPOT_LIGHT: 
     R3Vector from_light_to_point = position - light->position; 
     light_intensity = light->color*(
         pow(light->direction.Dot(from_light_to_point), 
          light->angle_attenuation)); 
     break; 
    } 
    return light_intensity; 
} 

我將不勝感激任何建議,到任何明顯的執行錯誤。我想知道是否可能僅僅因爲用於OpenGL顯示的伽馬值和我的顯示器的默認伽瑪值而發生差異。我也知道,OpenGL(或至少是我提供的部分)不能在對象上投射陰影。並不是說這與問題的關係有關,但它只是讓我想知道它是否僅僅是OpenGL和我正在嘗試做的顯示和性能差異。

謝謝你的幫助。

回答

0

在我的情況下,我對伽馬值差異的初步猜測是正確的。調用我的渲染算法的主程序通過執行image->TosRGB()調用來校正圖像的每個像素的RGB值,從而執行伽瑪校正。在發表評論後,我獲得了OpenGL生成的圖像。

3

作爲第一步,我會檢查交點表面法線是否歸一化,在計算漫反射和鏡面術語點積時尤其重要。

爲了調試目的,您可以逐個檢查照明術語的輸出(例如場景環境輸出,光線環境漫反射鏡面輸出,光衰減因子等),以及其他術語方程。一些簡單的術語可能會產生相同的輸出,並且您可以使用此方法將搜索範圍縮小爲更少的代碼行。它甚至可能與您實現中的其他對象/方法有關。另外,請記住,OpenGL的Phong着色不嚴格遵循Phong着色模型,因爲法線是按頂點計算的,然後在三角形內插入,它們不是在表面上的每個點進行計算。你的球體模型似乎足夠細分,所以這不應該是一個實際問題。

據我所知,OpenGL不會執行伽馬校正,除非您使用sRGB色彩空間作爲渲染目標。我期望一個正確的軟件實現產生非常類似於硬件OpenGL實現的結果。快速調試:)