- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在研究一个类的光线追踪算法,遇到了一个奇怪的问题。
这是我正在处理的基本场景。没什么大不了的,没事。现在,我的代码是这样组织的:
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;
}
找到点 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) 返回 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/
如标题所示,我正在寻找有关伪/冒号 header 字段用途的一些信息,即我想知道为什么我们有第二种类型的 header 字段... 另外 - 我知道在 http2 中使用伪/冒号 header 字段代
(伪)多线程:借助外力 利用WEB服务器本身的多线程来处理,从WEB服务器多次调用我们需要实现多线程的程序。 QUOTE: 我们知道PHP本身是不支持多线程的, 但是我们的WEB服务器是支持多线程的
您如何在 HDL (verilog) 中实现硬件随机数生成器? 需要考虑哪些选项? 这个问题是在self-answer之后格式。鼓励添加答案和更新。 最佳答案 正如摩根的回答中所指出的,这只会产生一个
我写了这个CSS: div { width: 500px; height:150px; margin-left:150px; background: lightblue; } div:
这是我要解决的问题:从数据库A读取一个字符串,将该字符串转换为Date对象,将Date对象存储到数据库B中。 例)数据库A:从数据库A读入日期字符串“ 2015-03-08 02:00:00”,转换为
我想创建 std::fscanf() 的 sibling (我知道这是一个 C 函数)。所以,我的界面是这样的: template std::size_t ts_scanf(is, format,
运行 PostgreSQL 7.x(是的,我正在升级) 问题: 如果没有返回数据,我有三到四个字段需要设置。 正在考虑这样的事情 SELECT CASE WHEN default_fie
出于某种原因,我很难在 JS 中为我的游戏执行以下代码: 假设我们要求用户在棋盘上移动一个棋子。他们可以做的位置是位置A、位置B或位置C。每个位置一次只能容纳一件。否则为无效移动。 第一个用户决定
我已经毫无问题地编写了霍夫曼树的代码,但现在我希望在文件和树中添加伪 EOF,以便我知道何时停止从文件中读取。 我完全掌握了伪 EOF 的概念。我还了解到没有 ASCII 值 > 255 的字符。 我
给定一个按钮 ::after 当被触发时,伪 :after 类需要有一个类 search-active 切换,为按钮设置背景颜色 .primary .search:after, .primary
我想让第一行的文本像第二行一样缩进 (50px)。有什么办法吗?非常感谢! body{ counter-reset: h2counter; } h1{ counter-reset: h2counter
:before 或 :after 这样的伪元素是否可以从父元素的不同属性继承值? 在我的例子中,我有一个第三方组件设置其元素运行时的背景颜色...我需要继承该颜色并将其设置为伪元素的边框颜色。 最佳答
在并行循环中请求随机数总是返回相同的伪随机数。我怎样才能避免这种情况? % workers initialization: if matlabpool('size') == 0 matlabp
假设最大IP可以包含每个“点”括号中的最大数量999,即999.999.999.999 是最大的可用值。 我已经在计算器中检查了正则表达式 ([0-9]+.){3}[0-9]。那么,为什么程序抛出运行
我对随机数生成的概念非常陌生,我需要为用c编写的工作创建自己的算法(内置的随机数生成器对我不起作用)。 有人能给我介绍一个很好的主题,这样我就可以理解这个概念了吗?到目前为止,我所发现的一切似乎都是用
假设我有一个数字序列:{n, n+1, n+2, ... n+m} 在不提前存储数字的情况下,我想创建一个函数 f(),给定序列 {1,2,3,...m} 将以随机(或至少伪)的方式吐出原始集合随机)
什么是伪 tcp channel ,如何实现? 最佳答案 伪 TCP 是一种协议(protocol),它实现了 TCP 的一些思想,以通过不可靠的、基于数据包的接口(interface)提供可靠的数据
我正在尝试展开一些嵌套循环,以牺牲内存为代价(可能)获得更好的性能。在我的场景中,我最终会得到一个包含大约 3 亿个元素(元组)的列表,我必须以(或多或少)随机顺序产生这些元素。 在这个数量级上,ra
如何在 PHP 中生成(伪)随机字母数字字符串,例如:'d79jd8c'? 最佳答案 首先创建一个包含所有可能字符的字符串: $characters = 'abcdefghijklmnopqrstu
我有一段代码可以为玩家生成迷你任务。这很简单,要获得两个不同的点(起点和终点),我有一个如下所示的算法: std::vector missions; missions.push_bac
我是一名优秀的程序员,十分优秀!