2010-03-05 91 views
3

我目前在C++中實現了一個基本的raytracer。到目前爲止工作得非常好,無光澤材料(具有環境和漫反射brdf)迄今爲止按預期工作。什麼會導致Phong鏡面陰影產生色域溢出?

添加鏡面高光會導致完整的Phong Model,這正是我試圖做的。

不幸的是,我遇到了色域溢出,其中鏡面反射常數ks和指數的各種值。這裏有些例子。

// Sphere material definition: 
ka = 0.9; 
kd = 1.0; 
ks = 0.3; 
exp = 1.0; 
color = rgb(1.0, 1.0, 0.98); 

圖像:http://dl.dropbox.com/u/614366/cornell_1.png

// Sphere material definition: 
ka = 0.9; 
kd = 1.0; 
ks = 0.3; 
exp = 20.0;     // only changed exp 
color = rgb(1.0, 1.0, 0.98); 

圖像:http://dl.dropbox.com/u/614366/cornell_2.png

// Sphere material definition: 
ka = 0.9; 
kd = 1.0; 
ks = 0.1;     // only changes here 
exp = 0.1;     // and here 
color = rgb(1.0, 1.0, 0.98); 

圖像:http://dl.dropbox.com/u/614366/cornell_3.png

,這裏是代碼的一些相關摘錄:

在raycast.cpp

namespace { 
    const float floatmax = std::numeric_limits<float>::max(); 
} 

rgb 
RayCast::trace (const Ray& ray) const 
{ 
    HitRecord rec(scene_ptr_); 
    float tmax = floatmax; 
    float tmin = 0.0; 

    if (scene_ptr_->shapes.hit(ray,tmin,tmax,rec)) 
    { 
     rec.ray = ray; 
     return rec.material_ptr->shade(rec); 
    } 

    return scene_ptr_->bgcolor; 
} 

在phong.cpp

rgb 
Phong::shade (HitRecord& hitrec) const 
{ 
    Vector wo = - hitrec.ray.dir(); 

    rgb L = ambient_brdf_ptr_->rho(hitrec,wo) * 
     hitrec.scene_ptr->ambient_ptr->L(hitrec); 

    int num_lights = hitrec.scene_ptr->lights.size(); 

    for (int i = 0; i < num_lights; ++i) 
    { 
     Vector wi  = hitrec.scene_ptr->lights[i]->get_direction(hitrec); 
     float ndotwi = dot(hitrec.normal, wi); 

     if (ndotwi > 0.0) 
     { 
      L += (diffuse_brdf_ptr_->f (hitrec, wo, wi) + 
        specular_brdf_ptr_->f(hitrec, wo, wi) 
       ) * hitrec.scene_ptr->lights[i]->L(hitrec) * ndotwi; 
     } 
    } 

    return L; 
} 

在specular.cpp

namespace { 
    const rgb black(0.0,0.0,0.0); 
} 

rgb 
Specular::f (const HitRecord& hitrec, const Vector& wo, const Vector& wi) const 
{ 
    rgb L(0,0,0); 
    float ndotwi = dot(hitrec.normal, wi); 

    Vector r = -wi + 2.0 * hitrec.normal * ndotwi; 
    float rdotwo = dot(r, wo); 

    // reflection detected 
    if (rdotwo > 0.0) 
     L = ks_ * pow(rdotwo, exp_); 

    return L; 
} 

rgb 
Specular::rho (const HitRecord& hitrec, const Vector& wo) const 
{ 
    return black; 
} 

在sphere.cpp

bool 
Sphere::hit (const Ray& ray, interval_t tmin, interval_t tmax, HitRecord& hitrec) const 
{ 
    Vector org = ray.origin() - center_; 
    Vector dir = ray.dir(); 
    float a = dot(dir, dir); 
    float b = dot(dir, org) * 2; 
    float c = dot(org, org) - pow(radius_, 2); 
    float discriminant = pow(b,2) - 4*a*c; 

    if (discriminant > 0) 
    { 
     discriminant = sqrt(discriminant); 
     double t = (-b - discriminant)/(2*a); 

     if (t < tmin) 
      t = (-b + discriminant)/(2*a); 

     if (t > tmin and t < tmax) 
     { 
      // hit detected 
      hitrec.t   = t; 
      hitrec.hit   = true; 
      hitrec.normal  = unify(t*ray.dir() + org); 
      hitrec.material_ptr = material_ptr_; 
      hitrec.hitpoint  = ray.origin() + t * ray.dir(); 
      hitrec.ray   = ray; 

      return true; 
     } 
    } 

    return false; 
} 

你有想法,可能會導致錯誤嗎?導致這種結果的可能因素是什麼?

在此先感謝, 帕特里克。

+1

反射表面上的色域點對我來說並不特別令人驚訝。從側面指向它的典型銀球應具有比明亮更明亮的鏡面高光。 – msw 2010-03-05 03:41:17

+0

是的,這是事實,但通常情況下,如果我增加指數,點應該變小。但它沒有:( – 2010-03-05 11:52:21

+1

我被'反射'標籤愚弄,darn,預期.net反射 – Axarydax 2010-03-05 12:56:45

回答

2

問題的解決方案是你必須統一wo矢量(在Phong :: shade中)。

相關問題