2010-03-05 116 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中)。

相关问题