gpt4 book ai didi

c++ - 光线追踪反射伪像和透明度

转载 作者:太空狗 更新时间:2023-10-29 21:21:53 24 4
gpt4 key购买 nike

我一直在研究一个类的光线追踪算法,遇到了一个奇怪的问题。

img

这是我正在处理的基本场景。没什么大不了的,没事。现在,我的代码是这样组织的:

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

它找到从 o 开始被射线 d 截获的对象的索引 k,并返回发生这种截获的点 p , Vec Tracer::objCol(Vec o, Vec p, int obj, int r) 是函数

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

找到点 po 方向发送的颜色,知道它属于对象 obj 并且反射的最大次数允许的是 r

当我使后(白)墙反射时,结果如下:

img

看起来还不错,没有问题。现在,如果我让右边的(蓝色)墙反射,结果是这样的:

img

(我还不能发布超过 2 个链接,删除括号以查看图像)。如果我决定让球体反射,情况会变得更糟:

img

变透明了!而且我不知道为什么会发生这种情况,因为我在获得颜色之前会寻找光线拦截。

这是我用于查找点颜色和反射颜色的代码:

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) 返回 vector 的逐点除法(例如 (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 限制。

知道是什么导致了这些奇怪的反射效果吗?

最佳答案

这是一条评论,我从中做出了回答,因为它似乎有效:

虽然我还没有检查代码,但这看起来像是一个 z-fighting/floating point comparison problem - try move the intersection point a bit away from the reflecting object along the its normal or make sure the reflected ray can' t 与原始对象发生碰撞,这可以修复它。

这里最有可能发生的是光线随机地被物体反射,但由于交点不准确( float 不准确)而再次击中物体 - 这将导致反射光线再次翻转并被反射更频繁地或最终朝着正确的(反射的)方向前进 - 或者以错误的(原始)方向穿过物体,看起来物体是透明的。

关于c++ - 光线追踪反射伪像和透明度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21705203/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com