现在,我们学习最后一个特性,散焦模糊。摄影方面一般称呼其为景深。
我们在真实相机中散焦模糊的原因是因为他们需要一个大洞(而不是针孔)才能收集光线。这会使一切都散焦,但如果我们在镜头孔中贴上镜头,那么在一切焦点处都会有一定的距离。到物体聚焦的那个平面的距离由镜头和胶片/传感器之间的距离控制。这就是为什么当你改变焦点时(这可能发生在你的手机相机中,传感器会移动),你会看到镜头相对于相机移动。真正的相机有一个复杂的复合镜头。 对于我们的代码,我们可以模拟顺序:传感器,然后是镜头,然后是光圈,然后计算出发送光线的位置,然后翻转一次计算的图像(图像在电影上上下颠倒投影)。图形人通常使用薄的近似镜头。
我们也不需要模拟相机内部的任何部分。 为了在相机外部渲染图像,这将是不必要的复杂性。 相反,我通常从镜头表面开始发射光线,并通过在焦点平面(在 focus_dist)上找到胶片的投影,将它们发送到虚拟胶片平面。
为此,我们只需要将射线源放在外观上的磁盘上,而不是从某个角度来看:
def random_in_unit_disk(): p=vec3(0,0,0) while True: p=2.0*vec3(random(),random(),0)-vec3(1,1,0) if p.dot(p) >= 1.0: break return p class camera: def __init__(self,lookfrom,lookat,vup,vfov,aspect,aperture,focus_dist): self.lens_radius=aperture/2 theta=vfov*pi/180 half_height=tan(theta/2) half_width=aspect*half_height self.origin=lookfrom self.w=(lookfrom-lookat).unit_vector() self.u=vup.cross(self.w).unit_vector() self.v=self.w.cross(self.u) self.lower_left_corner=self.origin-half_width*focus_dist*self.u-half_height*focus_dist*self.v-focus_dist*self.w self.horizontal=2*half_width*focus_dist*self.u self.vertical=2*half_height*focus_dist*self.v def get_ray(self,s,t): rd=self.lens_radius*random_in_unit_disk() offset=self.u*rd.x()+self.v*rd.y() return ray(self.origin+offset,self.lower_left_corner+s*self.horizontal+t*self.vertical-self.origin-offset)