光线追踪相机观察问题:旋转范围有限?

问题描述 投票:0回答:1

我正在开发光线追踪器,并且我面临着相机的 Look_at 功能的意外行为。看起来相机的旋转被限制在一定的范围内,当我将look_at设置为vec3(100., 0.25, -3.)时,它的行为与vec3(1000., 0.25, -3.)类似。我希望相机能够围绕场景平滑地旋转 360 度。

代码:

from PIL import Image, ImageFilter
import numpy as np

class Scene():
    def __init__(self, ambient_color = vec3(0.01, 0.01, 0.01), n = vec3(1.0,1.0,1.0)) :
        self.scene_primitives = []
        self.collider_list = []
        self.shadowed_collider_list = []
        self.Light_list = []
        self.importance_sampled_list = []
        self.ambient_color = ambient_color
        self.n = n
        self.importance_sampled_list = []
        self.bvh_root = None
    def add(self, collider):
        self.collider_list.append(collider)

    def build_bvh(self):
        # Build BVH for the scene
        self.bvh_root = build_bvh(self.collider_list)

    def get_raycolor(self, ray):
        distances, hit_orientation = zip(*[s.intersect(ray.origin, ray.dir) for s in self.collider_list])

        nearest = np.minimum.reduce(distances)
        color = vec3(0., 0., 0.)

        for (coll, dis, orient) in zip(self.collider_list, distances, hit_orientation):
            hit_check = (nearest != FARAWAY) & (dis == nearest)
            if np.any(hit_check):
                color += coll.assigned_primitive.material.get_color(
                    self, ray.extract(hit_check),
                    Hit(extract(hit_check, dis), extract(hit_check, orient), coll.assigned_primitive.material, coll,
                        coll.assigned_primitive)).place(hit_check)

        return color
    def add_Camera(self, look_from, look_at, **kwargs):
        self.camera = Camera(look_from, look_at, **kwargs)
    def add_PointLight(self, pos, color):
        self.Light_list += [PointLight(pos, color)]
    def add_DirectionalLight(self, Ldir, color):
        self.Light_list += [DirectionalLight(Ldir.normalize() , color)]
    def add(self,primitive, importance_sampled = False):
        self.scene_primitives += [primitive]
        self.collider_list += primitive.collider_list
        if importance_sampled == True:
            self.importance_sampled_list += [primitive]
        if primitive.shadow == True:
            self.shadowed_collider_list += primitive.collider_list
    def add_Background(self, img, light_intensity = 0.0, blur =0.0 , spherical = False):
        primitive = None
        if spherical == False:
            primitive = SkyBox(img, light_intensity = light_intensity, blur = blur)
        else:
            primitive = Panorama(img, light_intensity = light_intensity, blur = blur)
        self.scene_primitives += [primitive]
        self.collider_list += primitive.collider_list
    def render(self, samples_per_pixel, progress_bar = False):
        if self.bvh_root is None:
            self.build_bvh()
        color_RGBlinear = vec3(0.,0.,0.)
        if progress_bar:
            for i in range(samples_per_pixel):
                color_RGBlinear += get_raycolor(self.camera.get_ray(self.n), scene = self)
                print(i)
        else:
            for i in range(samples_per_pixel):
                color_RGBlinear += get_raycolor(self.camera.get_ray(self.n), scene = self)
        color_RGBlinear = color_RGBlinear/samples_per_pixel
        rgb_linear = color_RGBlinear.to_array()
        rgb = np.where( rgb_linear <= 0.00304,  12.92 * rgb_linear,  1.055 * np.power(rgb_linear, 1.0/2.4) - 0.055)
        rgb_max =  np.amax(rgb, axis=0)  + 0.00001
        intensity_cutoff = 1.0
        color = np.where(rgb_max > intensity_cutoff, rgb * intensity_cutoff / (rgb_max), rgb)
        img_RGB = []
        for c in color:
            img_RGB += [Image.fromarray((255 * np.clip(c, 0, 1).reshape((self.camera.screen_height, self.camera.screen_width))).astype(np.uint8), "L") ]
        return Image.merge("RGB", img_RGB)
class Camera():
    def __init__(self, look_from, look_at, screen_width = 400 ,screen_height = 300,  field_of_view = 90., aperture = 0., focal_distance = 1.):
        self.screen_width = screen_width
        self.screen_height = screen_height
        self.aspect_ratio = float(screen_width) / screen_height
        self.look_from = look_from
        self.look_at = look_at
        self.camera_width = np.tan(field_of_view * np.pi / 180 / 2.) * 2.
        self.camera_height = self.camera_width / self.aspect_ratio
        self.cameraFwd = (look_at - look_from).normalize()
        self.cameraRight = (self.cameraFwd.cross(vec3(0., 1., 0.))).normalize()
        self.cameraUp = self.cameraRight.cross(self.cameraFwd)
        self.lens_radius = aperture / 2.
        self.focal_distance = focal_distance
        self.near = .1
        self.far = 100.
        self.x = np.linspace(-self.camera_width / 2., self.camera_width / 2., self.screen_width)
        self.y = np.linspace(self.camera_height / 2., -self.camera_height / 2., self.screen_height)
        xx, yy = np.meshgrid(self.x, self.y)
        self.x = xx.flatten()
        self.y = yy.flatten()
    def get_ray(self,n):
        x = self.x + (np.random.rand(len(self.x)) - 0.5) * self.camera_width / (self.screen_width)
        y = self.y + (np.random.rand(len(self.y)) - 0.5) * self.camera_height / (self.screen_height)
        ray_origin = self.look_from + self.cameraRight * x * self.near + self.cameraUp * y * self.near
        return Ray(origin=ray_origin, dir=(self.look_from + self.cameraUp * y * self.focal_distance +self.cameraRight * x * self.focal_distance +self.cameraFwd * self.focal_distance - ray_origin).normalize(), depth=0, n=n, reflections=0, transmissions=0, diffuse_reflections=0)

用途:

camera_position = vec3(2.5 * np.sin(angle), 0.25, 2.5 * np.cos(angle) - 1.5)
look_at = vec3(0., 0.25, -3.) # in this case 0. (it's not the same when you put 10 which is correct but 100 is the same with 1000 or 200 which is incorrect)
Sc.add_Camera(look_from=camera_position, look_at=look_at, screen_width=width, screen_height=height)
Sc.build_bvh()
Sc.render(samples_per_pixel=1).show()
python raytracing
1个回答
0
投票

您可能没有更改所有

look_at
值(x、y、z)。

© www.soinside.com 2019 - 2024. All rights reserved.