def hit(self, ray: vector.Ray, t_min: float, t_max: float): oc = ray.origin - self.center a = ray.direction.length_squared() half_b = vector.dot(oc, ray.direction) c = oc.length_squared() - self.radius * self.radius discriminant = half_b * half_b - a * c if discriminant > 0: root = math.sqrt(discriminant) temp = (-half_b - root) / a if t_min < temp < t_max: hit_rec = HitRecord(None, None, None, None) hit_rec.t = temp hit_rec.position = ray.at(hit_rec.t) hit_rec.material = self.m outward_normal = (hit_rec.position - self.center).divide( self.radius) hit_rec.set_face_normal(ray, outward_normal) return True, hit_rec temp = (-half_b + root) / a if t_min < temp < t_max: hit_rec = HitRecord(None, None, None, None) hit_rec.t = temp hit_rec.position = ray.at(hit_rec.t) hit_rec.material = self.m outward_normal = (hit_rec.position - self.center).divide( self.radius) hit_rec.set_face_normal(ray, outward_normal) return True, hit_rec return False, None
def test_intersect5(self): r = Ray(point(0, 0, 5), vector(0, 0, 1)) s = Sphere() i = s.intersect(r) self.assertEqual(2, len(i)) self.assertEqual(-6.0, i[0].t) self.assertEqual(-4.0, i[1].t)
def scatter(self, ray_in: Ray, collision: HitRecord) -> MaterialRecord: color = Color(1, 1, 1) if collision.resultant_outward: incoming_index, outgoing_index = 1.0, self.index_of_refraction else: incoming_index, outgoing_index = self.index_of_refraction, 1.0 index_ratio = incoming_index / outgoing_index direction = ray_in.direction.unit() normal = collision.resultant.direction cos_theta = -direction @ normal sin_theta = sqrt(max(1 - cos_theta**2, 0)) # Use the Schlick approximation to calculate reflectance r_0 = ((1 - index_ratio) / (1 + index_ratio))**2 reflectance = r_0 + (1 - r_0) * (1 - cos_theta)**5 snell_solvable = sin_theta * index_ratio <= 1.0 schlick_within_range = reflectance <= random() can_refract = snell_solvable and schlick_within_range if can_refract: outgoing_direction = refract_across(direction, normal, index_ratio) else: outgoing_direction = reflect_across(direction, normal) outgoing_ray = Ray(collision.resultant.base, outgoing_direction) return MaterialRecord(color=color, outgoing_ray=outgoing_ray)
def loop_simulation(dt): global slave_error if (run_auto): if (slave_device_pos_tween.done() and slave_device_rot_tween.done()): scene_vectormanager.clear() update_slave_sensor() slave_device.pos = slave_device_pos_tween.step(dt * 10) slave_device.rot = slave_device_rot_tween.step(dt * 10) scene_vectormanager.clear(15) for r in view_rays: scene_vectormanager.addRay(r, color=(0, 0, 1, 1), group=15) if print_timer.tick(): scene_vectormanager.clear(10) target_rays = lighthouse.getRays(target_device) delta_vecs = [] for ray, sp in zip(target_rays, [ slave_device.pos + rsp.rotate(slave_device.rot) for rsp in slave_device.sensorpos ]): np = ray.nearest(sp) if np: delta_vecs.append(np - sp) scene_vectormanager.addRay(Ray(sp, np - sp), color=(1, 1, 1, 1), group=10) slave_error = sum([vec.magnitude() for vec in delta_vecs]) print "E:", slave_error, "FS:", face_sums
def test_intersect_sphere1(self): s = Sphere() r = Ray(point(0, 0, -5), vector(0, 0, 1)) s.set_transform(xf_scale(2, 2, 2)) i = s.intersect(r) self.assertEqual(2, len(i)) self.assertEqual(i[0].t, 3.0) self.assertEqual(i[1].t, 7.0)
def get_ray(self, horizontal_component, vertical_component): offset = self._get_offset() base = self.look_from + offset direction = self.lower_left +\ (horizontal_component * self.horizontal) +\ (vertical_component * self.vertical) -\ base return Ray(base, direction)
def scatter(self, ray_in: Ray, collision: HitRecord) -> MaterialRecord: base = collision.resultant.base direction = collision.resultant.direction.unit() reflected_direction = direction + random_in_hemisphere(direction) if reflected_direction.near_zero(): reflected_direction = direction reflected_ray = Ray(base, reflected_direction) color = self.albedo return MaterialRecord(outgoing_ray=reflected_ray, color=color)
def scatter(self, ray_in: Ray, collision: HitRecord) -> MaterialRecord: base = collision.resultant.base incoming_direction = ray_in.direction.unit() normal = collision.resultant.direction.unit() fuzz = random_in_sphere() * self.fuzziness reflected_direction = reflect_across(incoming_direction, normal) + fuzz if reflected_direction.near_zero(): reflected_direction = direction reflected_ray = Ray(base, reflected_direction) color = self.albedo absorbed = (reflected_direction @ normal) < 0 return MaterialRecord(outgoing_ray=reflected_ray, color=color, absorbed=absorbed)
def hit(self, ray: Ray, t_min=0, t_max=INF) -> HitRecord: base_to_center = ray.base - self.center a = ray.direction @ ray.direction b = ray.direction @ base_to_center c = base_to_center @ base_to_center - self.radsquared discriminant = b**2 - a * c # Not hit if discriminant <= 0: return HitRecord() sqrt_discriminant = np.sqrt(discriminant) def roots(): yield from [(-b - sqrt_discriminant) / a, (-b + sqrt_discriminant) / a] for sphere_hit_coordinate in roots(): in_bounds = t_min < sphere_hit_coordinate < t_max if not in_bounds: continue sphere_boundary = ray(sphere_hit_coordinate) outward_normal = (sphere_boundary - self.center) / self.radius normal = Ray(sphere_boundary, outward_normal) record = HitRecord(resultant=normal, t=sphere_hit_coordinate, material=self.material) record.orient(ray, outward_normal) return record return HitRecord()
def test_translate_ray2(self): r = Ray(point(1, 2, 3), vector(0, 1, 0)) m = xf_scale(2, 3, 4) r2 = r.transform(m) self.assertEqual(r2.origin, point(2, 6, 12)) self.assertEqual(r2.direction, vector(0, 3, 0))
def test_translate_ray1(self): r = Ray(point(1, 2, 3), vector(0, 1, 0)) m = xf_translate(3, 4, 5) r2 = r.transform(m) self.assertEqual(r2.origin, point(4, 6, 8)) self.assertEqual(r2.direction, vector(0, 1, 0))
def test_intersect3(self): r = Ray(point(0, 2, -5), vector(0, 0, 1)) s = Sphere() i = s.intersect(r) self.assertEqual(0, len(i))
def test_ray_postion1(self): r = Ray(point(2, 3, 4), vector(1, 0, 0)) self.assertEqual(r.position(0), point(2, 3, 4)) self.assertEqual(r.position(1), point(3, 3, 4)) self.assertEqual(r.position(-1), point(1, 3, 4)) self.assertEqual(r.position(2.5), point(4.5, 3, 4))
def update_slave_sensor(): global slave_state global slave_rays global slave_pos_delta global slave_rot_delta global slave_device_pos_tween global slave_device_rot_tween global target_index global slave_error global face_sums slave_device.pos = slave_device_pos_tween.finish() slave_device.rot = slave_device_rot_tween.finish() _slave_rays = lighthouse.getRays(slave_device) scene_vectormanager.clear(4) for ray in _slave_rays: scene_vectormanager.addRay(ray, color=(1, 0.5, 0.5, 1), group=4) if slave_state == SS_CAST_RAYS: slave_rays = lighthouse.getRays(target_device) for ray in slave_rays: scene_vectormanager.addRay(ray, color=(1, 1, 0, 1), group=1) slave_state = SS_COMPUTE_POS_DELTA elif slave_state == SS_COMPUTE_POS_DELTA: translation_rays = [] face_sums = [] slave_sensorpos = slave_device.getWorldSensorPos() target_sensorpos = [] for ray, sp, rsp in zip( slave_rays, slave_sensorpos, [sp.rotate(slave_device.rot) for sp in slave_device.sensorpos]): np = ray.nearest(sp) if np: target_sensorpos.append(np) translation_ray = Ray(sp, np - sp) translation_rays.append(translation_ray) scene_vectormanager.addRay(translation_ray, color=(1, 0, 0, 1), group=2) face_sums.append(math.copysign(1.0, (np - sp).dot(rsp))) slave_aabb = Vector3.enclosingAABB(slave_sensorpos) target_aabb = Vector3.enclosingAABB(target_sensorpos) target_pos = Vector3.average(target_sensorpos) lighthouse_vector = target_pos - lighthouse.pos target_aabb_size = (target_aabb[0] - target_aabb[1]).magnitude() if (target_aabb_size > 0): lighthouse_vector = (lighthouse_vector * ((slave_aabb[0] - slave_aabb[1]).magnitude() / target_aabb_size - 1.0)) else: lighthouse_vector = Vector3.zero average_vec = Vector3.average([tr.vec for tr in translation_rays]) #if(face_sum < 0): # average_vec *= abs(face_sum) scene_vectormanager.addVector(slave_device.pos, average_vec, color=(1, 1, 1, 1), group=2) scene_vectormanager.addVector(slave_device.pos + average_vec, lighthouse_vector, color=(1, 1, 1, 1), group=2) slave_pos_delta = average_vec + lighthouse_vector slave_state = SS_APPLY_POS_DELTA elif slave_state == SS_APPLY_POS_DELTA: scene_vectormanager.clear(2) slave_device_pos_tween.__init__(slave_device.pos, slave_device.pos + slave_pos_delta, 10.0) slave_state = SS_COMPUTE_ROT_DELTA elif slave_state == SS_COMPUTE_ROT_DELTA: rotation_rays = [] rotation_quats = [] options = zip( slave_rays, slave_device.getWorldSensorPos(), [sp.rotate(slave_device.rot) for sp in slave_device.sensorpos]) for ray, sp, rsp in options: np = ray.nearest(sp) if np: rotation_ray = Ray(sp, np - sp) rnp = np - slave_device.pos rotation_rays.append(rotation_ray) scene_vectormanager.addRay(rotation_ray, color=(0, 1, 0, 1), group=3) rotation_quats.append(Quaternion.rotationBetween(rsp, rnp)) average_rot = Quaternion.average(rotation_quats) average_rotation = average_rot scene_vectormanager.addVector(slave_device.pos, average_rotation.toAxisAngle()[0], color=(1, 1, 1, 1), group=3) slave_rot_delta = average_rotation slave_state = SS_APPLY_ROT_DELTA elif slave_state == SS_APPLY_ROT_DELTA: scene_vectormanager.clear(3) slave_device_rot_tween.__init__(slave_device.rot, slave_rot_delta * slave_device.rot, 10.0) slave_state = SS_COMPUTE_POS_DELTA