views:

47

answers:

1

I am currently implementing a basic raytracer in c++. Works pretty well so far, matte materials (with ambient and diffuse brdf) work as expected so far.

Adding specular highlights would result in the full Phong Model and that's exactly what i tried to do.

Unfortunately, i encounter gamut overflow, with all kinds of values for the specular reflection constant ks and the exponent. Here are some examples.

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

image: 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);

image: 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);

image: http://dl.dropbox.com/u/614366/cornell_3.png

and here are some relevant excerpts of the code:

in 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;
}

in 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;
}

in 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;
}

in 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;
}

do you have ideas where the error could be caused? what are possible factors that lead to such results?

thanks in advance, patrick.

+1  A: 

The solution to the problem is that you have to unify the wo vector (in Phong::shade).

padde