def scatter(self, ray, hit_record): reflected = reflect(ray.direction, hit_record.normal) # If the ray is inside the sphere set values accordingly if np.dot(ray.direction, hit_record.normal) > 0.: outward_normal = -hit_record.normal ni_over_nt = self.refraction_index cosine = self.refraction_index * np.dot( ray.direction, hit_record.normal) / length(ray.direction) else: outward_normal = hit_record.normal ni_over_nt = 1. / self.refraction_index cosine = -np.dot(ray.direction, hit_record.normal) / length( ray.direction) is_refracted, refracted = refract(ray.direction, outward_normal, ni_over_nt) # get probability of reflection over refraction with schlick approximation reflect_prob = self._schlick(cosine) if is_refracted else 1 # set the scattered ray as either the reflection or refraction according to reflect_prob if random.random() < reflect_prob: self.scattered = Ray(hit_record.point, reflected, ray.time) else: self.scattered = Ray(hit_record.point, refracted, ray.time) return True
def is_shadowed(self, light_position, hit_point): vec = subtract(light_position, hit_point) distance = magnitude(vec) direction = normalize(vec) ray = Ray(hit_point, direction) intersections = self.intersect(ray) hit_intersection = shadow_hit(intersections) return hit_intersection is not None and hit_intersection.t < distance
def reflected_color(self, hit, remaining=5): if remaining <= 0: return color(0, 0, 0) if hit.object.material.reflective == 0.0: return color(0, 0, 0) reflect_ray = Ray(hit.over_point, hit.reflectv) reflect_color = self.color_at(reflect_ray, remaining - 1) return multiply(reflect_color, hit.object.material.reflective)
def main(): canvas_pixels = 500 canvas = Canvas(canvas_pixels, canvas_pixels) shape = Sphere() # assign material shape.material = Material() shape.material.color = color(1, 0.2, 1) light_position = point(-10, 10, -10) light_color = color(1, 1, 1) light = PointLight(light_position, light_color) ray_origin = point(0, 0, -5) wall_z = 10 wall_size = 7.0 pixel_size = wall_size / canvas_pixels half = wall_size / 2 for y in range(canvas_pixels): world_y = half - pixel_size * y for x in range(canvas_pixels): world_x = -half + pixel_size * x pos = point(world_x, world_y, wall_z) r = Ray(ray_origin, normalize(subtract(pos, ray_origin))) xs = shape.intersect(r) shape_hit = hit(xs) if shape_hit is not None: hit_point = r.position_at(shape_hit.t) normal = shape_hit.object.normal_at(hit_point) eye = negate(r.direction) px_color = lighting(shape_hit.object.material, shape_hit.object, light, hit_point, eye, normal) canvas.set_pixel(x, y, px_color) with open('render_phong_sphere.ppm', 'w') as out_file: out_file.write(canvas.to_ppm())
def ray_for_pixel(self, pixel_x, pixel_y): xoffset = (pixel_x + 0.5) * self.pixel_size yoffset = (pixel_y + 0.5) * self.pixel_size world_x = self.half_width - xoffset world_y = self.half_height - yoffset pixel = multiply_tuple(self.__inverse_transform, point(world_x, world_y, -1)) origin = multiply_tuple(self.__inverse_transform, point(0, 0, 0)) direction = normalize(subtract(pixel, origin)) return Ray(origin, direction)
def main(): canvas_pixels = 400 canvas = Canvas(canvas_pixels, canvas_pixels) red = color(1, 0, 0) shape = Sphere() # shrink it along the y axis #shape.set_transform(scaling(1, 0.5, 1)) # shrink it along the x axis #shape.set_transform(scaling(0.5, 1, 1)) # shrink it, and rotate it! # shape.set_transform(multiply_matrix(rotation_z(pi / 4), scaling(0.5, 1, # 1))) # shrink it, and skew it! # shape.set_transform( # multiply_matrix(shearing(1, 0, 0, 0, 0, 0), scaling(0.5, 1, 1))) ray_origin = point(0, 0, -5) wall_z = 10 wall_size = 7.0 pixel_size = wall_size / canvas_pixels half = wall_size / 2 for y in range(canvas_pixels): world_y = half - pixel_size * y for x in range(canvas_pixels): world_x = -half + pixel_size * x pos = point(world_x, world_y, wall_z) r = Ray(ray_origin, normalize(subtract(pos, ray_origin))) xs = shape.intersect(r) if hit(xs) is not None: canvas.set_pixel(x, y, red) with open('render_sphere.ppm', 'w') as out_file: out_file.write(canvas.to_ppm())
def refracted_color(self, hit, remaining=5): if remaining <= 0: return color(0, 0, 0) if hit.object.material.transparency == 0.0: return color(0, 0, 0) n_ratio = hit.n1 / hit.n2 cos_i = dot(hit.eyev, hit.normalv) sin2_t = n_ratio**2 * (1 - cos_i**2) if sin2_t > 1.0: return color(0, 0, 0) cos_t = sqrt(1.0 - sin2_t) direction = subtract(multiply(hit.normalv, (n_ratio * cos_i - cos_t)), multiply(hit.eyev, n_ratio)) refract_ray = Ray(hit.under_point, direction) return multiply(self.color_at(refract_ray, remaining - 1), hit.object.material.transparency)
def step_impl(context): context.r = Ray(context.origin, context.direction)
def step_create_ray_with_specific_point_and_direction(context, dx, dy, dz): context.r = Ray(point(0, 0, sqrt(2) / 2), vector(dx, dy, dz))
def step_create_ray_with_point_and_specific_direction(context, ox, oy, oz): context.r = Ray(point(ox, oy, oz), vector(0, -sqrt(2) / 2, sqrt(2) / 2))
def step_create_ray_with_point_and_direction(context, ox, oy, oz, dx, dy, dz): context.r = Ray(point(ox, oy, oz), vector(dx, dy, dz))
#import the necessary modules from core import Ray, Boundary, intersection, prop import numpy as np import math #establish the ray, boundary with desired info #for now, the start points must be <= the endpoints, directionality of the code is an unsolved issue #horizontal lines are not yet supported for boundary! #to see results, pick ray/boundary so that they will intersect ray = Ray([0,0], np.pi/6, 10) boundary = Boundary([-10, -10], [10, 10], .75, 2) #find out where the ray and boundary intersect x_int, y_int = intersection(ray, boundary) #split the ray after collision with the boundary reflected_ray, refracted_ray = ray.split(boundary, [x_int, y_int]) print(reflected_ray.brightness) #this will give you the corresponding ray info for the reflected & refracted rays after interaction with the first boundary #required info can be accessed through the ray class, ex: reflected_ray.brightness() #this is an unfinished build of core.py #the finished version would ideally require the definition of parameters for ray/boundary, #and the rest would be automated through prop(ray)