问题十九:怎么模拟ray tracing中漫射材料球体的颜色(diffuse materials)

来源:互联网 发布:淘宝秒杀助手 编辑:程序博客网 时间:2024/05/08 09:52

前面画一个球时,球体的颜色设置为红色;

前面画多个球时,球体的颜色设置为球在该点的单位法向量的色彩表映射值;

现在画多个漫射材料的球,球体的颜色设置为背景颜色的系数倍。(姑且表述为“背景颜色”吧,将在“问题二十一”中确切说明)

 

漫射材料不发光,只吸收和反射环境的光(反射光的方向是随机的),所以将漫射材料的球体的颜色设置为背景颜色乘以某系数是合理的。系数怎么确定呢?光线每被反射一次*1/2(因为光线没被反射一次会被吸收一半)。

 

既然已经知道漫射材料球体的颜色和反射次数有关,那么怎么获得光线反射次数呢;

光线反射次数=光线撞击球的次数;

撞击次数由反射光线的方向和起点(前一个撞击点)决定;

第一撞击点,呵呵,容易,之前画一个球或者多个球都是根据撞击点画的(撞上了才是球嘛);

OK,现在问题归结于怎么获取反射光线的方向。

之前就说了,漫射材料的反射光线的方向是随机的,怎么模拟一个随机方向的向量呢?

在交点处单位法向量的基础上加上一个长度小于1的随机向量。

 

已知P为交点,PS为球C在P点的单位法向量,现在要模拟一个起点为P方向向球C外面的任何方向的向量。

书上是这么做的:

1,找一个辅助球O,该球是球心在原点的单位球体;

2,在球O里面随机找一点E或者F;(E点在球体里面,也就是向量OE的长度小于1,by the way,单位法向量PS的长度为1);

3,OP+PS=OS,OS+OE=OM,OM-OP=PM。所以,PM=OP+PS+OE-OP=PS+OE。(辅助球O选球心在原点的单位球的原因,其一,“球心在原点”,方便计算;其二,“单位球”,可以确保PM的方向不会指向球C内部)。PS是已知的,所以只要获得OE即可。


4,怎么描述“起点在原点,长度小于1,方向随机”的向量呢?书上说:We’ll use what is usually the easiest algorithm: a rejection method.First, we pick a random point in the unit cube where x, y, and z all range from-1 to +1. We reject this point and try again if the point is outside thesphere. A do/while construct is perfect for that:

    vec3 random_in_unit_sphere() {        vec3 p;        do {            p = 2.0*vec3((rand()%(100)/(float)(100)),                        (rand()%(100)/(float)(100)),                        (rand()%(100)/(float)(100)))                - vec3(1,1,1);        } while (p.squared_length() >= 1.0);        return p;    }

Rejectionmethod是什么鬼???

 

先回顾一下,怎么产生(-1,1)间的随机浮点数?

x=(rand()%(100)/(float)(100))∈(0,1)推出 2x ∈(0,2)推出2x-1∈(-1,1)

所以,y= 2*x -1 = 2 * (rand()%(100)/(float)(100)) -1即为(-1,1)间的随机浮点数。

 

同理,向量a  = (x, y, z),b = (2x-1, 2y-1, 2z-1), 其中x,y, z ∈(0,1)

推出2x-1, 2y-1, 2z-1∈(-1,1)推出(2x-1)2+(2y-1)2+(2z-1)2∈(0,3)推出|b|∈(0, 根号3)

而我们能接受的是|b|∈(0,1),所以采取“接受——拒绝”方式:只接受|b|∈(0,1)。

所以,就有了上面那段code啦!


将流程反过来看一遍:

1,起点为原点的光线撞击球C,获得撞击点P和单位法向量PS。

2,产生一个“起点在原点,长度小于1,方向随机”的向量OE。

3,OP+PS+OE-OP=PM,PM即为漫射材料的球体在P点的随机反射方向向量。

4,反射光线是以P为起点,PM为方向向量,所以,我们可以获得反射光线的方程

5,让反射光线去撞击其他球吧(回到第一步)

 

光线撞击球的次数=光线反射的次数è球体该像素点的颜色值对应背景颜色的系数值。


    vec3 color(const ray& r, hitable *world) {        hit_record rec;        if (world->hit(r, 0.0, (numeric_limits<float>::max)(), rec)) {            vec3 target = rec.p + rec.normal + random_in_unit_sphere();/*target为上图中OM向量, target-rec.p=OM-OP=PM*/            return 0.5*color( ray(rec.p, target-rec.p), world);/*撞击一次,乘以系数0.5。然后以反射光线(以P为起点,PM为方向向量)去撞击球,直到没有撞击到任何球,(下方else语句中)最后带着系数乘以背景颜色值作为球体该像素点的颜色*/        }        else {            vec3 unit_direction = unit_vector(r.direction());            float t = 0.5*(unit_direction.y() + 1.0);            return (1.0-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0);//white, light blue        }}


贴出运行结果图:

放大8倍看截图:


有没有觉得太黑了,反正我觉得是有问题的。


4 0
原创粉丝点击