def hit(self, ray: Ray): c = self.origin e = ray.origin d = ray.dir r = self.radius # check discriminant disc = (d.dot(e - c))**2 - (d.dot(d)) * ((e - c).dot(e - c) - r**2) if disc < 0: return (False, None) elif disc > 0: # two solutions t1 = ((d.scale(-1)).dot(e - c) - math.sqrt(disc))/d.dot(d) t2 = ((d.scale(-1)).dot(e - c) + math.sqrt(disc))/d.dot(d) n1 = self.normal(ray.getPoint(t1)) n2 = self.normal(ray.getPoint(t2)) # print(str(t1) + ', ' + str(t2)) if t2 < 10**(-8): return (False, None) elif t1 < 10**(-8) and t2 >= 10**(-8): return (True, HitRec([t2], [n2])) elif t1 >= 10**(-8): return (True, HitRec([t1, t2], [n1, n2])) else: # one solution t1 = ((d.scale(-1)).dot(e - c))/d.dot(d) n1 = self.normal(ray.getPoint(t1)) return (True, HitRec([t1], [n1]))
def rayColor(ray: Ray, objects: list, depth: int, obj_ignore: Surface): if depth == 5: return (0, 0, 0) obj_hit, t, n = hit(ray, objects, obj_ignore) if (obj_hit): lightsource = Vec3(-50, 20, 50) lightsource_dir = (lightsource - ray.getPoint(t)).normalize() shadow_ray = Ray(ray.getPoint(t), lightsource_dir) SHADOWED = False # hex_fill = None for o in objects: res = o.hit(shadow_ray) if (res[0]): SHADOWED = True break if (not SHADOWED): h = ((ray.dir.scale(-1)) + lightsource_dir).normalize() reflection_dir = ray.dir - n.scale(2*ray.dir.dot(n)) reflection = Ray(ray.getPoint(t), reflection_dir) rec_ref = rayColor(reflection, objects, depth+1, obj_hit) Lr = min(int((0.1 * 4.5 * max(0, n.dot(lightsource_dir)) + 0.5 * 4.5 * max(0, n.dot(h)**8) + 2*rec_ref[0]/255) * 255), 255) Lg = min(int((0.3 * 3 * max(0, n.dot(lightsource_dir)) + 0.5 * 3 * max(0, n.dot(h)**8) + 2*rec_ref[1]/255) * 255), 255) Lb = min(int((0.6 * 0.3 * max(0, n.dot(lightsource_dir)) + 0.5 * 0.3 * max(0, n.dot(h)**8) + 2*rec_ref[2]/255) * 255), 255) return (Lr, Lg, Lb) else: h = ((ray.dir.scale(-1)) + lightsource_dir).normalize() # print(ray.getPoint(t)) Lr = min(int(0.1 * 4.5 * max(0, n.dot(lightsource_dir)) * 255), 255) Lg = min(int(0.3 * 3 * max(0, n.dot(lightsource_dir)) * 255) , 255) Lb = min(int(0.3 * 0.3 * max(0, n.dot(lightsource_dir)) * 255) , 255) return (Lr, Lg, Lb) return (0 , 0, 0)
def hit(self, ray: Ray): xa = self.a.x ya = self.a.y za = self.a.z xb = self.b.x yb = self.b.y zb = self.b.z xc = self.c.x yc = self.c.y zc = self.c.z xd = ray.dir.x yd = ray.dir.y zd = ray.dir.z xe = ray.origin.x ye = ray.origin.y ze = ray.origin.z a = xa - xb b = ya - yb c = za - zb d = xa - xc e = ya - yc f = za - zc g = xd h = yd i = zd j = xa - xe k = ya - ye l = za - ze M = a*(e*i - h*f) + b*(g*f - d*i) + c*(d*h - e*g) if (-10**(-8) <= M <= 10**(-8)): return (False, None) t = -1* (f*(a*k - j*b) + e*(j*c - a*l) + d*(b*l - k*c))/M if (t <= 10**(-8)): return (False, None) gamma = (i*(a*k - j*b) + h*(j*c - a*l) + g*(b*l - k*c))/M if (gamma < 0 or gamma > 1): return (False, None) beta = (j*(e*i - h*f) + k*(g*f - d*i) + l*(d*h - e*g))/M if (beta < 0 or (beta + gamma) > 1 ): return (False, None) n = self.normal(ray.getPoint(t)) return (True, HitRec([t], [n]))