Esempio n. 1
0
 def make_ray(self, i, j):
     # was having difficulty making a good mass-ray-generation routine, settled on on-demand
     # speed is fine and it'll be good for future adaptive sampling stuff
     n1 = np.random.random()
     n2 = np.random.random()
     origin = self.origin + self.dx_dp * (j + n1) + self.dy_dp * (i + n2)
     ray = Ray(origin, unit(self.focal_point - origin))
     ray.i = i
     ray.j = j
     return ray
Esempio n. 2
0
def extend_path(path: Path, root: Box):
    triangle, t = traverse_bvh(root, path.ray)
    if triangle is not None:
        # generate new ray
        new_origin = path.ray.origin + path.ray.direction * t
        new_direction = BRDF_sample(triangle.material, -1 * path.ray.direction, triangle.normal, path.direction)
        new_ray = Ray(new_origin, new_direction)
        new_ray.normal = triangle.normal
        new_ray.material = triangle.material
        new_ray.local_color = triangle.color
        if triangle.emitter:
            path.hit_light = True

        path_push(path, new_ray)
        # if path_health_check(path):
        return True
    else:
        return False
Esempio n. 3
0
def extend_path(path: Path, boxes, triangles):
    triangle, t = traverse_bvh(boxes, triangles, path.ray)
    if triangle is not None:
        # generate new ray
        new_origin = path.ray.origin + path.ray.direction * t
        new_direction = brdf_sample(triangle.material, -1 * path.ray.direction,
                                    triangle.normal, path.direction)
        new_ray = Ray(new_origin, new_direction)
        new_ray.normal = triangle.normal
        new_ray.material = triangle.material
        new_ray.local_color = triangle.color
        if triangle.emitter:
            path.hit_light = True

        path_push(path, new_ray)
        return True
    else:
        return False
Esempio n. 4
0
    def _trace_ray(self, ray, calc_color, tol, tracing_depth):
        """
        :param ray: object of type Ray
        :param calc_color: function, which takes Hit object as parameter and returns color of object in this point
        :return: result of execution calc_color function
        """

        min_dist = 1e8
        min_hit = None

        for obj in self.scene.objects:
            hit = obj.intersect(ray, tol)
            if hit is None:
                continue

            dist = hit.distance()
            if dist < min_dist:
                min_dist = dist
                min_hit = hit

        obj_color = calc_color(min_hit)

        res_shading = np.array([0.0, 0.0, 0.0])

        if min_hit is not None:
            # Tracing shadow rays
            for light in self.scene.lights:
                shadow_ray = Ray(min_hit.point, light.origin - min_hit.point)
                shadow_hit = self._trace_shadow_ray(shadow_ray, tol)

                if shadow_hit is None:
                    res_shading += light.get_intensity(shadow_ray) * obj_color * max(0, np.dot(min_hit.normal, shadow_ray.direction))

            # Tracing reflection ray
            if tracing_depth > 0:

                reflection_ray_dir = ray.direction - 2.0 * (np.dot(ray.direction, min_hit.normal)) * min_hit.normal
                reflection_ray = Ray(min_hit.point, reflection_ray_dir)
                reflection_shading = self._trace_ray(reflection_ray, calc_color, tol, tracing_depth - 1)

                res_shading += REFLECTION_COEF * reflection_shading

        return res_shading
Esempio n. 5
0
    def isValidMove(self, A, B):
        # get the direction of the movement ray
        D = B - A
        dist = LA.norm(D)

        # trace a ray to get the hit record towards scene objects
        ray = Ray(A, D / dist)
        d, hr = self.trace(ray)

        # we can move if we don't hit a wall
        return dist < d
Esempio n. 6
0
def path_push(path: Path, ray: Ray):
    # update stuff appropriately
    if path.direction == Direction.STORAGE.value:
        # don't change anything, this is just a stack. this reduces wasted calculation and preserves first-vertex values
        pass
    elif path.ray is None:
        # this shouldn't come up
        pass
    else:
        G = geometry_term(path.ray, ray)
        path.ray.direction = unit(ray.origin - path.ray.origin)
        if path.ray.prev is None:
            # pushing onto stack of 1, just propagate p and color (?)
            ray.color = path.ray.color * G
            ray.p = path.ray.p * G
        else:
            # pushing onto stack of 2 or more, do some work
            brdf = BRDF_function(path.ray.material, -1 * path.ray.prev.direction, path.ray.normal, path.ray.direction,
                                       path.direction)
            ray.color = path.ray.local_color * path.ray.color * brdf * G
            ray.p = path.ray.p * G * BRDF_pdf(path.ray.material, -1 * path.ray.prev.direction, path.ray.normal, path.ray.direction,
                                          path.direction)
        ray.bounces = path.ray.bounces + 1

    # store new ray
    ray.prev = path.ray
    path.ray = ray
Esempio n. 7
0
    def get_ray(self, point):
        """
        :param point: point of type tuple (x: float, y: float), where -1 <= x, y <= 1
        :return:
        """
        fov_x, fov_y = self.fov_angle
        d = 1 / np.tan(fov_x / 2)
        x, y = point
        u, v, w = self.direction
        aspect = fov_y / fov_x

        dir = x * u + aspect * y * v + d * w
        normalized_direction = dir / np.sqrt(np.dot(dir, dir))

        return Ray(self.origin, normalized_direction)
Esempio n. 8
0
def generate_light_ray(box: Box):
    light_index = np.random.randint(0, len(box.lights))
    light = box.lights[light_index]
    light_origin = light.sample_surface()
    x, y, z = local_orthonormal_system(light.normal)
    light_direction = random_hemisphere_uniform_weighted(x, y, z)
    ray = Ray(light_origin, light_direction)
    ray.color = light.color
    ray.local_color = light.color
    ray.normal = light.normal
    ray.p = 1 / (2 * np.pi * light.surface_area)
    return ray
Esempio n. 9
0
def visibility_test(boxes, triangles, ray_a: Ray, ray_b: Ray):
    delta = ray_b.origin - ray_a.origin
    least_t = np.linalg.norm(delta)
    direction = delta / least_t
    if np.dot(ray_a.normal, direction) <= 0 or np.dot(ray_b.normal, -1 * direction) <= 0:
        return False
    test_ray = Ray(ray_a.origin, direction)
    stack = [boxes[0]]
    while stack:
        box = stack.pop()
        if box.right == 0:
            if bvh_hit_inner(test_ray, box, least_t):
                stack.append(boxes[box.left])
                stack.append(boxes[box.left + 1])
        else:
            if visibility_hit_leaf(test_ray, box, triangles[box.left:box.right], least_t):
                return False
    return True
Esempio n. 10
0
def visibility_test(root: Box, ray_a: Ray, ray_b: Ray):
    delta = ray_b.origin - ray_a.origin
    least_t = np.linalg.norm(delta)
    direction = delta / least_t
    if np.dot(ray_a.normal, direction) <= 0 or np.dot(ray_b.normal, -1 * direction) <= 0:
        return False
    test_ray = Ray(ray_a.origin, direction)
    stack = BoxStack()
    stack.push(root)
    while stack.size:
        box = stack.pop()
        if box.left is not None and box.right is not None:
            if bvh_hit_inner(test_ray, box, least_t):
                stack.push(box.left)
                stack.push(box.right)
        else:
            hit, t = bvh_hit_leaf(test_ray, box, least_t)
            if hit is not None and t < least_t:
                return False
    return True
Esempio n. 11
0
def generate_light_ray(emitters):

    light = emitters[np.random.randint(0, len(emitters))]
    light_origin = light.sample_surface()

    x, y, z = local_orthonormal_system(light.normal)
    light_direction = random_hemisphere_uniform_weighted(x, y, z)
    ray = Ray(light_origin, light_direction)

    ray.color = light.color
    ray.local_color = light.color
    ray.normal = light.normal

    # this seems made up
    ray.p = 1 / (2 * np.pi * light.surface_area)

    return ray
Esempio n. 12
0
def path_push(path: Path, ray: Ray):
    # update stuff appropriately
    G = geometry_term(path.ray, ray)
    path.ray.direction = unit(ray.origin - path.ray.origin)
    if path.ray.prev is None:
        # pushing onto stack of 1, just propagate p and color (?)
        ray.color = path.ray.color * G
        ray.p = path.ray.p * G
    else:
        # pushing onto stack of 2 or more, do some work
        brdf = brdf_function(path.ray.material, -1 * path.ray.prev.direction,
                             path.ray.normal, path.ray.direction,
                             path.direction)
        ray.color = path.ray.local_color * path.ray.color * brdf * G
        ray.p = path.ray.p * G * brdf_pdf(
            path.ray.material, -1 * path.ray.prev.direction, path.ray.normal,
            path.ray.direction, path.direction)
    ray.bounces = path.ray.bounces + 1

    # store new ray
    ray.prev = path.ray
    path.ray = ray
Esempio n. 13
0
def ray_that_misses():
    return Ray(ONES * 5, UNIT_Y)
Esempio n. 14
0
def ray_inside_box():
    return Ray(point(0.5, 0.5, 0.5), UNIT_Z)
Esempio n. 15
0
def ray_that_hits():
    # hits object in center
    return Ray(point(0.2, 0.2, 5), -1 * UNIT_Z)
Esempio n. 16
0
def ray_that_barely_hits():
    # hits object at origin
    return Ray(UNIT_Z * 5, -1 * UNIT_Z)
Esempio n. 17
0
def extend_path(path, root, path_direction):
    for i in range(MAX_BOUNCES):
        ray = path[-1]
        triangle, t = traverse_bvh(root, ray)
        if triangle is not None:
            # generate new ray
            #  new vectors
            origin = ray.origin + ray.direction * t
            direction = BRDF_sample(triangle.material, -1 * ray.direction,
                                    triangle.normal, path_direction)
            new_ray = Ray(origin, direction)

            #  store info from triangle
            new_ray.normal = triangle.normal
            new_ray.material = triangle.material
            new_ray.local_color = triangle.color
            if path_direction == Direction.FROM_CAMERA.value and triangle.emitter:
                new_ray.hit_light = True

            # probability, weight, and color updates
            G = geometry_term(ray, new_ray)

            if i == 0:
                # only need to multiply by G because p of this direction is already stored at creation
                new_ray.p = ray.p * G
                # same deal, "brdf" of source is already in ray.color
                new_ray.color = ray.color * G
                new_ray.G = G
            else:
                # so the idea here is that each vertex has information about everything up to it but not including it,
                # because we can't be sure of anything about the final bounce until we know the joining vertex
                bounce_p = BRDF_pdf(ray.material, -1 * path[-2].direction,
                                    ray.normal, ray.direction, path_direction)
                new_ray.p = ray.p * G * bounce_p
                new_ray.color = ray.color * ray.local_color * G * BRDF_function(
                    ray.material, -1 * path[-2].direction, ray.normal,
                    ray.direction, path_direction)
                new_ray.G = G
                ray.local_p = bounce_p

            path.append(new_ray)
        else:
            break