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

198 篇文章 12 订阅
195 篇文章 27 订阅

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

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

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

 

漫射材料不发光,只吸收和反射环境的光(反射光的方向是随机的),所以将漫射材料的球体的颜色设置为背景颜色乘以某系数是合理的。系数怎么确定呢?光线每被反射一次*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倍看截图:


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


  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值