def test_vec_normalization(self): values = [ vector.Vec3(1., 3., 10.), vector.Vec3(0., 1., 0.), vector.Vec3(50, -50, 30) ] for v in values: self.assertAlmostEqual(v.normalized().length(), 1.0)
def main(): arglen = len(sys.argv) instancevar = -1 if arglen > 1: arg0 = sys.argv[0] arg1 = sys.argv[1] instancevar = arg1 aspect_ratio = 16.0 / 9.0 image_width = 384 #image_width = 800 image_height = int(image_width / aspect_ratio) samples_per_pixel = 10 max_depth = 50 lookfrom = vector.Vec3(13, 2, 3) lookat = vector.Vec3(0, 0, 0) dist_to_focus = 10.0 aperture = 0.1 vup = vector.Vec3(0, 1, 0) cam = camera.Camera(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus) world = random_scene(-1) random.seed(instancevar) print("P3") print("" + str(image_width) + " " + str(image_height)) print("255") for j in range(image_height - 1, 0, -1): if instancevar == -1: sys.stderr.write("\rScanlines remaining: " + str(j) + " ") for i in range(0, image_width, 1): pixel_color = vector.Vec3(0.0, 0.0, 0.0) for _ in range(samples_per_pixel): u1 = (i + util.random_double()) / (image_width - 1) v1 = (j + util.random_double()) / (image_height - 1) r = cam.get_ray(u1, v1) pixel_color = pixel_color + ray_color(r, world, max_depth) write_color(pixel_color, samples_per_pixel) sys.stderr.write("\nDone (instance: " + str(instancevar) + ")")
def calc_view_matrix(self): eye = vector.Vec3(self.x, self.y, self.z) up = vector.Vec3(0, 1, 0) target = vector.Vec3(eye.x + self.x_tilt, eye.y + self.y_tilt, 0) # view axes forward = (target - eye).normalize() side = forward.cross(up).normalize() upward = side.cross(forward) m = [[side.x, upward.x, -forward.x, 0], [side.y, upward.y, -forward.y, 0], [side.z, upward.z, -forward.z, 0], [-eye.dot(side), -eye.dot(upward), eye.dot(forward), 1]] self.view_matrix = np.array(m, dtype=np.float32) self.look_x, self.look_y, self.look_z = side, upward, forward
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord): attenuation = vector.Vec3(1.0, 1.0, 1.0) etai_over_etat = self.ref_idx if hit_record.front_face: etai_over_etat = 1.0 / self.ref_idx unit_direction = vector.unit_vector(ray_in.direction) cos_theta = min(vector.dot(-unit_direction, hit_record.normal), 1.0) sin_theta = math.sqrt(1.0 - cos_theta*cos_theta) if etai_over_etat * sin_theta > 1.0: reflected = vector.reflect(unit_direction, hit_record.normal) scattered = vector.Ray(hit_record.position, reflected) return True, attenuation, scattered reflect_prob = vector.schlick(cos_theta, etai_over_etat) if util.random_double() < reflect_prob: reflected = vector.reflect(unit_direction, hit_record.normal) scattered = vector.Ray(hit_record.position, reflected) return True, attenuation, scattered refracted = vector.refract(unit_direction, hit_record.normal, etai_over_etat) scattered = vector.Ray(hit_record.position, refracted) return True, attenuation, scattered
def random_scene(seed): random.seed(seed) world = hittable.HittableList() world.add( hittable.Sphere(vector.Vec3(0, -1000, 0), 1000, material.Lambertian(vector.Vec3(0.5, 0.5, 0.5)))) for a in range(-11, 11): for b in range(-11, 11): choose_mat = util.random_double() center = vector.Vec3(a + 0.9 * util.random_double(), 0.2, b + 0.9 * util.random_double()) if (center - vector.Vec3(4, 0.2, 0)).length() > 0.9: if choose_mat < 0.8: # diffuse albedo = vector.random() * vector.random() world.add( hittable.Sphere(center, 0.2, material.Lambertian(albedo))) elif choose_mat < 0.95: # metal albedo = vector.random_in_range(.5, 1) fuzz = util.random_double_range(0, .5) world.add( hittable.Sphere(center, 0.2, material.Metal(albedo, fuzz))) else: # glass world.add( hittable.Sphere(center, 0.2, material.Dielectric(1.5))) world.add( hittable.Sphere(vector.Vec3(0, 1, 0), 1.0, material.Dielectric(1.5))) world.add( hittable.Sphere(vector.Vec3(-4, 1, 0), 1.0, material.Lambertian(vector.Vec3(.4, .2, .1)))) world.add( hittable.Sphere(vector.Vec3(4, 1, 0), 1.0, material.Metal(vector.Vec3(.7, .6, .5), 0.0))) return world
def ray_color(ray: vector.Ray, world: hittable.Hittable, depth): if depth <= 0: return vector.Vec3(0.0, 0.0, 0.0) did_hit, hit_rec = world.hit(ray, 0.001, util.INFINITY) if did_hit: tempmaterial = hit_rec.material didscatter, albedo, scattered = tempmaterial.scatter(ray, hit_rec) if didscatter: return albedo * ray_color(scattered, world, depth - 1) return vector.Vec3(0, 0, 0) unit_dir = vector.unit_vector(ray.direction) t = (unit_dir.y + 1.0) * 0.5 return vector.Vec3(1.0, 1.0, 1.0).times(1.0 - t) + vector.Vec3( 0.5, 0.7, 1.0).times(t)
import vector import cProfile import re import hittable p = vector.Vec3(0.0, 0.0, 0.0) norm = vector.Vec3(0.0, 1.0, 0.0) hit_rec = hittable.HitRecord(p, norm, 0.0, None) sum = 0.0 for i in range(100): target = hit_rec.position + vector.random_in_hemisphere(hit_rec.normal) sum = sum + target.x print("avg x: " + str(sum / 100.0)) r = vector.Ray(vector.Vec3(0.0, 0.0, 0.0), vector.Vec3(1.0, 1.0, 1.0)) r2 = r.at(-0.5) print("" + str(r)) print("" + str(r2))
def test_vec_addition(self): vec1 = vector.Vec3(5., 3., -2.) vec2 = vector.Vec3(-5., 2., 0.) expected = vector.Vec3(0., 5., -2.) self.assertEqual(vec1 + vec2, expected)
def test_vec_printing(self): vec = vector.Vec3(5, 3, 0) self.assertEqual(str(vec), "(5, 3, 0)")
def test_scene(seed): random.seed(seed) world = hittable.HittableList() R = math.cos(util.PI / 4) world.add( hittable.Sphere(vector.Vec3(-R, 0, -1), R, material.Lambertian(vector.Vec3(0, 0, 1)))) world.add( hittable.Sphere(vector.Vec3(R, 0, -1), R, material.Lambertian(vector.Vec3(1, 0, 0)))) world.add( hittable.Sphere(vector.Vec3(0, 0, -1), 0.5, material.Lambertian(vector.Vec3(0.1, 0.2, 0.5)))) world.add( hittable.Sphere(vector.Vec3(0, -100.5, -1), 100, material.Lambertian(vector.Vec3(0.8, 0.8, 0.0)))) world.add( hittable.Sphere(vector.Vec3(1, 0, -1), 0.5, material.Metal(vector.Vec3(.8, .6, .2), 0.0))) world.add( hittable.Sphere(vector.Vec3(-1, 0, -1), 0.5, material.Dielectric(1.5))) world.add( hittable.Sphere(vector.Vec3(-1, 0, -1), -0.45, material.Dielectric(1.5)))