我一直在为一个课程编写光线追踪算法,但是遇到了一个奇怪的问题。
这是我正在处理的基本场景,没有什么大问题。现在,我的代码组织如下:
Image* Tracer::render()
{
int w = _scr.width();
int h = _scr.height();
Image* im = new Image(w, h);
int i, j;
for(i = 0; i < h; i++)
{
for(j = 0; j < w; j++)
{
im->setColour(i, j, render(i, j));
}
}
return im;
}
我调用此函数生成图像。为了给每个像素上色:
Vec Tracer::render(int i, int j)
{
Vec pxlcol(0,0,0);
Vec p(0,0,0);
int obj;
Vec dir = _scr.point(i,j);
dir = dir - _obs;
obj = intercept(_obs, dir, p);
if(obj != -1)
{
pxlcol = objCol(_obs, p, obj, _ref);
}
return pxlcol;
}
int Tracer::intercept(Vec o, Vec d, Vec& p)是以下函数:
int Tracer::intercept(Vec o, Vec d, Vec& p)
{
int obj, k;
Vec temp = o;
Vec ptry = o;
obj = -1;
for(k = 0; k < _nobj; k++)
{
temp = _obj[k]->intercept(o, d);
if( !(temp == o) && (((temp - o).mod() < (ptry - o).mod()) || (ptry == o)))
{
ptry = temp;
obj = k;
}
}
p = ptry;
return obj;
}
Vec Tracer::objCol(Vec o, Vec p, int obj, int r) 是一个函数,用于查找从起点为 o,方向为 d 的光线所经过的物体的索引 k,并返回该光线与物体相交的点 p。
Vec Tracer::objCol(Vec o, Vec p, int obj, int r)
{
Vec colour(0,0,0);
Vec point(0,0,0), reflected(0,0,0);
unit ref = _obj[obj]->ref(p);
if((1 - ref) > 0)
point = pointCol(o, p, obj);
if(ref > 0 && r > 0)
reflected = refCol(o, p, _obj[obj]->normal(o, p), r - 1);
colour = (point*(1 - ref)) + (reflected*ref);
return colour;
}
该算法会查找点p在方向o下发送的颜色,并知道它属于对象obj,且允许反射的最大次数为r。
当我使后面的(白色)墙成为反射面时,效果如下:
看起来还不错,没有问题。现在,如果我使右边(蓝色)的墙面成为反射面,结果是这样:
(我还不能发布超过2个链接,去掉括号以查看图片)。如果我决定让球体成为反射面,情况会更糟:
它变得透明了!我不知道为什么会发生这种情况,因为我在获得颜色之前寻找射线截距。
以下是查找点颜色和反射颜色的代码:
Vec Tracer::pointCol(Vec o, Vec p, int obj)
{
Vec pcol(0,0,0);
Vec inten(0,0,0);
unit cos = 0;
Vec c(0,0,0);
Vec normal = _obj[obj]->normal(o, p);
Vec inter = o;
Vec objcol = _obj[obj]->colour(p);
bool block = false;
if(_amb == 1)
return objcol;
int l = 0;
int k = 0;
for(l = 0; l < _nlight; l++)
{
c = _li[l]->getPos() - p;
block = false;
if(c*normal > 0)
{
for(k = 0; k < _nobj; k++)
{
if(k != obj)
{
inter = _obj[k]->intercept(p, c);
inter = inter - p;
if(!(inter.null()) && (inter.mod() < c.mod()))
{
block = true;
k = _nobj;
}
}
}
if(!block)
{
cos = (c*normal)/(c.mod()*normal.mod());
inten = inten + _li[l]->getInt()*cos;
}
}
}
inten = inten.div(_totalinten);
pcol = objcol*_amb + objcol.multi(inten)*(1 - _amb);
return pcol;
}
_amb常量定义了光线中环境光和漫反射光的比例。
函数Vec Vec::div(Vec v)返回向量的逐元素除法(例如,(a, b, c).div((x, y, z)) = (a/x, b/y, c/z))。函数Vec Vec::multi(Vec v)对乘法进行逐元素操作。
Vec Tracer::refCol(Vec o, Vec p, Vec n, int r)
{
Vec rcol(0,0,0);
Vec i = p - o;
Vec refl(0,0,0);
int obj = 0;
Vec point(0,0,0);
i.normalise();
refl = reflected(i, n);
obj = intercept(p, refl, point);
if(obj != -1)
{
rcol = objCol(p, point, obj, r);
}
return rcol;
}
objCol 调用带有参数 r-1 的 refCol 函数,反射次数受 _ref 上界限制。
你有什么想法是什么原因造成这些奇怪的反射效应吗?