第5个示例 递归反射、抗锯齿
抗锯齿】
可以看到中间那个竖线的右侧从地面上看有款明显的锯齿,而左边就没有。包括球的反射出来的三角形和地面也有明显的锯齿。那么抗锯齿究竟本例中是怎么做的呢?
首先在采样时,当场景需要重绘时,我们此时定义场景为第0帧,在第0帧时我们绘制精确的有锯齿的场景,在随后的各帧中对其光线的方向增加一个[0, 1]的随机的扰动(因为光线是每个像素生成的,因此0到1之间的扰动真的很小又合适),生成轻微模糊的图像,然后再与上一帧按照权重进行叠加,就形成了虚化一些的反走样的图片。我们来看实际代码:
RT_PROGRAM void pinhole_camera()
{
//缓存尺寸,也就是屏幕尺寸
size_t2 screen = output_buffer.size();
//rtPrintf("%d-%d-", screen.x, screen.y);
unsigned int seed = tea<16>(screen.x*launch_index.y + launch_index.x, frame);
float2 subpixel_jitter = frame == 0 ? make_float2(0.0f, 0.0f) : make_float2(rnd(seed) - 0.5f, rnd(seed) - 0.5f);
//左右分窗做对比
if (launch_index.x > screen.x / 2)
{
subpixel_jitter = make_float2(0);
}
float2 d = (make_float2(launch_index) + subpixel_jitter)/ make_float2(screen) * 2.f - 1.f;
float3 ray_origin = eye;
float3 ray_direction = normalize(d.x*U + d.y*V + W);
//生成光线
optix::Ray ray(ray_origin, ray_direction, RADIANCE_RAY_TYPE, scene_epsilon);
PerRayData_radiance prd;
prd.importance = 1.f;
prd.depth = 0;
rtTrace(top_object, ray, prd);
float4 acc_val = accum_buffer[launch_index];
if (frame > 0)
{
acc_val = lerp(acc_val, make_float4(prd.result, 0.0f), 1.0f / static_cast<float>(frame + 1));
}
else
{
acc_val = make_float4(prd.result, 0.f);
}
if (launch_index.x == (screen.x / 2))
{
acc_val = make_float4(0);
}
//所有跟踪后,求得结果
output_buffer[launch_index] = make_color(make_float3(acc_val));
accum_buffer[launch_index] = acc_val;
}
首先针对扰动我们使用了生成随机数subpixel_jitter ,可以看到在第0帧时不生成,如何定义第0帧呢,就是当场景需要重绘时就是第0帧。而后生成的图片首先存在一个缓冲区中float4 acc_val = accum_buffer[launch_index];,然后跟据当前渲染的帧数对图片按权重进行叠加,这个权重值是1.0f / static_cast<float>(frame + 1),也就是越往后的权重越低,确保第0帧的图片保真不失。
【反射】
在phongShade中,倘若我们定义了反射操作p_Kr,则需要对场景计算反射效果,反射效果首先在碰撞点处根据入射光线和法线生成反射光线
//求出反射方向
float3 R = optix::reflect(ray.direction, p_normal);
而后再重新以碰撞点为起点,以反射方向为方向,生成新的光线。来求取颜色添加到结果中。值得注意的是随着反射次数的增加何时结束呢,这里有两个变量决定着,一个是硬性的
new_prd.depth <= max_depth
每反射一次,depth就加1,直到达到最大。
第二个是每反射一次权重也会下降,因为反射个百八十次的基本上无关紧要了,因此当权重值降到0.01时,也会自动的取消继续反射。
---------------------