2021-04-21

美妙的随机数和宇宙🌌


最近的交了WWDC2021作品,然后我凑巧通过伪随机数生成一个SkyBox,说一下思路嘿嘿

最近的交了WWDC2021作品,然后我凑巧通过伪随机数生成一个SkyBox,说一下思路嘿嘿

然后这篇文主要是写给有了解过Ray Tracing in one weekend看的
下面代码都是Metal
这个随机书算法是从StackOverflow拿过来的,日常CV嘿嘿,但是原回答没说怎么用,这几我姑且把x和y算作屏幕像素的texturecoord的x和y
z是从CPU那边buffer过来的时钟信号,主要是每一帧能z+1就好了

1
2
3
4
5
6
7
// Generate a random float in the range [0.0f, 1.0f] using x, y, and z (based on the xor128 algorithm)
float randomer_gen_float(thread const uint2& position, int z)
{
int seed = position.x + position.y * 57 + z * 241;
seed= (seed<< 13) ^ seed;
return (( 1.0 - ( (seed * (seed * seed * 15731 + 789221) + 1376312589) & 2147483647) / 1073741824.0f) + 1.0f) / 2.0f;
}

这里写了一个SkyBox的Material,参数什么的姑且不看,
主要是c:和原书中生成天空渐变色一样
float rd是vec3的三维随机数,别忘了z要+1、+2,不然一个像素内的时间种子z是一样的
pow是滤波,需要把rd中偏向灰白色的像素过滤掉,只留下发亮的星星✨,把✨给我们的star,然后SkyBox这支Material会反射回去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class SkyBox {
public:
SkyBox() {}

bool radiate(thread const Ray& r_in,
thread const HitRecord& rec,
thread float3& attenuation,
thread Ray& radiated,
thread const uint2& position, float seed) const {
float3 unit_direction = unit_vector(r_in.direction());
float t = 0.9f*(unit_direction.y + 1.0f);
float3 c = (1.0f-t)*float3(0.53, 0.5, 0.4) + t*float3(0.05, 0.05, 0.05); // space background
float gradient = 4;
float rd = pow(randomer_gen_float(uint2(gradient*abs(rec.p.x), gradient*abs(rec.p.y)), gradient*abs(rec.p.x+rec.p.y+rec.p.z)), 1000);
float3 star = float3(rd, rd, rd-0.01);
float3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
radiated = Ray(rec.p, reflected);
attenuation = star + c;
attenuation *= 2.5;
return (dot(radiated.direction(), rec.normal) < 0);
}
};

最后就是因为这支SkyBox是天空盒,相机在里面,需要把反射的方向取个反,这行代码所在位置相当于书里的ray_color里,我的写法里的cur_ray是去掉了递归,循环的写法

1
cur_ray = Ray(radiated.orig, -radiated.direction());
看看效果咯