我目前正在用 C++ 实现一个基本的光线追踪器。到目前为止效果很好,哑光 Material (带有环境和漫反射 brdf)到目前为止按预期工作。

添加镜面高光会产生完整的 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;
}

你有什么可能导致错误的想法吗?导致这种结果的可能因素是什么?

提前致谢,
帕特里克。

最佳答案

问题的解决方法是你必须统一这两个 vector (在 Phong::shade 中)。

关于c++ - 什么会导致 Phong 镜面反射着色产生色域溢出?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2384405/

10-12 13:36