class EnvironmentLight(Light): def __init__(self, material, sampler, cast_shadow): self.material = material self.sampler = sampler self.cast_shadow = cast_shadow self.sampler.map_samples_to_hemisphere(1) self.u, self.v, self.w = Vector(0.0, 0.0, 0.0), Vector(0.0, 0.0, 0.0), Vector(0.0, 0.0, 0.0) self.wi = Vector(0.0, 0.0, 0.0) def get_direction(self, shading_point): self.w = shading_point.normal up = Vector(0.003, 1.0, 0.007) self.v = up.cross(self.w) self.v = self.v.normalize() self.u = self.v.cross(self.w) sp = self.sampler.sample_hemisphere() self.wi = self.u.scalar(sp.x) + self.v.scalar(sp.y) + self.w.scalar(sp.z) return self.wi.scalar(-1.0) def in_shadow(self, ray, shading_point): for shape in shading_point.scene.shapes: if shape.shadow_hit(ray): return True return False def L(self): return self.material.Le() def G(self, shading_point): return 1.0 def pdf(self, shading_point): return shading_point.normal.dot(self.wi) / math.pi
def __init__(self, shape, cast_shadow): self.shape = shape self.cast_shadow = cast_shadow self.sample = Vector(0.0, 0.0, 0.0) self.light_normal = Vector(0.0, 0.0, 0.0) self.wi = Vector(0.0, 0.0, 0.0)
def __init__(self, material, sampler, cast_shadow): self.material = material self.sampler = sampler self.cast_shadow = cast_shadow self.sampler.map_samples_to_hemisphere(1) self.u, self.v, self.w = Vector(0.0, 0.0, 0.0), Vector(0.0, 0.0, 0.0), Vector(0.0, 0.0, 0.0) self.wi = Vector(0.0, 0.0, 0.0)
def get_direction(self, shading_point): self.w = shading_point.normal up = Vector(0.003, 1.0, 0.007) self.v = up.cross(self.w) self.v = self.v.normalize() self.u = self.v.cross(self.w) sp = self.sampler.sample_hemisphere() self.wi = self.u.scalar(sp.x) + self.v.scalar(sp.y) + self.w.scalar(sp.z) return self.wi.scalar(-1.0)
def sample_f(self, shading_point): w = shading_point.normal # jitter the up vector v = Vector(0.0024, 1.0, 0.0081).cross(w) v = v.normalize() u = v.cross(w) sample_point = self.sampler.sample_hemisphere() wi = sample_point.x * u + sample_point.y * v + sample_point.z * w wi = wi.normalize() pdf = shading_point.normal * wi / math.pi color = self.surface.get_color(shading_point) return pdf, wi, (self.kd * color / math.pi)
def _calculate_intersection(self, ray, frustum): # Calculate the positions of the camera and the ray relative to the quadric rCam = ray.origin - self._position rRay = ray.direction # Precalculate these values for our quadratic equation V1 = rRay * rRay V2 = Vector(rRay.x * rRay.y, rRay.y * rRay.z, rRay.z * rRay.x) * 2 V3 = rCam * rRay V4 = Vector(rRay.x * rCam.y + rCam.x * rRay.y, rCam.y * rRay.z + rRay.y * rCam.z, rCam.x * rRay.z + rRay.x * rCam.z) V5 = rRay V6 = rCam * rCam V7 = Vector(rCam.x * rCam.y, rCam.y * rCam.z, rCam.z * rCam.x) * 2 V8 = rCam * 2 # Calculate the quadratic coefficients A = dot(self._ABC, V1) + dot(self._DEF, V2) B = dot(self._ABC, V3) + dot(self._DEF, V4) + dot(self._GHI, V5) C = dot(self._ABC, V6) + dot(self._DEF, V7) + dot( self._GHI, V8) + self._equation[9] # Calculate the squared value for our quadratic formula square = B**2 - A * C # No collision if the root is imaginary if square < 0: return None # Take its squareroot if it's real root = square**0.5 # Calculate both intersections D1 = (-B - root) / A D2 = (-B + root) / A # Return closest intersection thats in the frustum if frustum.near <= D1 <= frustum.far: return D1 elif frustum.near <= D2 <= frustum.far: return D2 return None
class AreaLight(Light): def __init__(self, shape, cast_shadow): self.shape = shape self.cast_shadow = cast_shadow self.sample = Vector(0.0, 0.0, 0.0) self.light_normal = Vector(0.0, 0.0, 0.0) self.wi = Vector(0.0, 0.0, 0.0) def get_direction(self, shading_point): self.sample = self.shape.sample() self.light_normal = self.shape.normal self.wi = self.sample - shading_point.hit_point self.wi = self.wi.normalize() return -1.0 * self.wi def in_shadow(self, ray, shading_point): ts = (self.sample - ray.origin) * ray.direction for shape in shading_point.scene.shapes: if shape.shadow_hit(ray) and shape.shadow_t < ts: return True return False def L(self): ndotd = -1.0 * self.wi * self.light_normal if ndotd > 0.0: return self.shape.material.Le() else: return Color(0.0, 0.0, 0.0) def G(self, shading_point): ndotd = -1.0 * self.light_normal * self.wi d2 = self.sample.distance(shading_point.hit_point) d2 = d2 * d2 return ndotd / d2 def pdf(self, shading_point): return self.shape.pdf()
def _get_normal(self, point): relative = point - self._position # Compute the generic derivative of the equation at given point x = (2 * self._equation.A * relative.x + self._equation.E * relative.z + self._equation.F * relative.y + self._equation.G) y = (2 * self._equation.B * relative.y + self._equation.D * relative.z + self._equation.F * relative.x + self._equation.H) z = (2 * self._equation.C * relative.z + self._equation.D * relative.y + self._equation.E * relative.x + self._equation.I) return Vector(x, y, z).unit()