什么会导致 Phong 镜面反射着色产生色域溢出?
我目前正在用 C++ 实现一个基本的光线追踪器。到目前为止效果很好,哑光材质(具有环境和漫反射 brdf)到目前为止按预期工作。
添加镜面高光将产生完整的 Phong 模型,而这正是我试图做的。
不幸的是,我遇到了色域溢出,镜面反射常数 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
以下是代码的一些相关摘录:
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;
}
您知道可能导致错误的地方吗?导致这种结果的可能因素有哪些?
提前致谢, 帕特里克.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题的解决方案是你必须统一 wo 向量(在 Phong::shade 中)。
The solution to the problem is that you have to unify the wo vector (in Phong::shade).