예제 #1
0
 def reflected_colour(self, comps, depth=5):
     if depth <= 0:
         return Tuple4.Colour(0, 0, 0)
     elif comps.object.material.reflective == 0:
         return Tuple4.Colour(0, 0, 0)
     else:
         reflect_ray = Ray.Ray(comps.over_point, comps.reflectv)
         colour = self.colour_at(reflect_ray, depth - 1)
         return colour * comps.object.material.reflective
예제 #2
0
 def ray_for_pixel(self, px, py):
     # the offset from the edge of the canvas to the pixel's center
     xoffset = (px + 0.5) * self.pixel_size
     yoffset = (py + 0.5) * self.pixel_size
     # the untransformed coordinates of the pixel in world space.
     # (remember that the camera looks toward -z, so +x is to the *left*.)
     world_x = self.half_width - xoffset
     world_y = self.half_height - yoffset
     # using the camera matrix, transform the canvas point and the origin,
     # and then compute the ray's direction vector.
     # (remember that the canvas is at z=-1)
     pixel = self.transform.inverse() * Tuple4.Point(world_x, world_y, -1)
     origin = self.transform.inverse() * Tuple4.Point(0, 0, 0)
     direction = (pixel - origin).normalize()
     return Ray.Ray(origin, direction)
예제 #3
0
def DefaultWorld():
    w = World()
    w.lights.append(
        Light.PointLight(Tuple4.Point(-10, 10, -10), Tuple4.Colour(1, 1, 1)))

    s1 = Sphere.Sphere()
    s1.material.colour = Tuple4.Colour(0.8, 1.0, 0.6)
    s1.material.diffuse = 0.7
    s1.material.specular = 0.2
    w.objects.append(s1)

    s2 = Sphere.Sphere()
    s2.transform = Transformation.Scaling(0.5, 0.5, 0.5)
    w.objects.append(s2)

    return w
예제 #4
0
 def colour_at(self, ray, depth=5):
     i = self.intersections(ray)
     hit = i.hit()
     if hit:
         comps = hit.prepare_computations(ray)
         return self.shade_hit(comps, depth)
     else:
         return Tuple4.Colour(0, 0, 0)
예제 #5
0
 def shade_hit(self, comp, depth=5):
     # Start with black
     c = Tuple4.Colour(0, 0, 0)
     # Then add the contribution from each light source
     for l in self.lights:
         s = self.is_shadowed(comp.over_point, l)
         c += comp.object.material.lighting(comp.object, l, comp.over_point,
                                            comp.eyev, comp.normalv, s)
     r = self.reflected_colour(comp, depth)
     return c + r
예제 #6
0
 def __init__(self,
              colour=Tuple4.Colour(1, 1, 1),
              ambient=0.1,
              diffuse=0.9,
              specular=0.9,
              shininess=200,
              reflective=0.0):
     self.colour = colour
     self.ambient = ambient
     self.diffuse = diffuse
     self.specular = specular
     self.shininess = shininess
     self.reflective = reflective
예제 #7
0
    def lighting(self, object, light, pos, eye, norm, shadow=False):
        black = Tuple4.Colour(0, 0, 0)

        # Get the point in object space
        opos = object.inverse_transform * pos
        # Check if we have a pattern, otherwise use the inherent colour
        if hasattr(self, "pattern"):
            colour = self.pattern.pattern_at(opos)
        else:
            colour = self.colour
        # combine the surface color with the light's color/intensity
        effective_colour = colour * light.intensity

        # find the direction to the light source
        lightv = (light.position - pos).normalize()

        # compute the ambient contribution
        ambient = effective_colour * self.ambient

        # If we are in shadow, diffuse and specular are both black
        # Test here to avoid an extra calculation below
        if shadow:
            diffuse = black
            specular = black
        else:
            # light_dot_normal represents the cosine of the angle between the
            # light vector and the normal vector. A negative number means the
            # light is on the other side of the surface.
            light_dot_normal = lightv.dot(norm)
            if light_dot_normal < 0:
                diffuse = black
                specular = black
            else:
                # compute the diffuse contribution
                diffuse = effective_colour * self.diffuse * light_dot_normal

                # reflect_dot_eye represents the cosine of the angle between
                # the reflection vector and the eye vector. A negative number
                # means the light reflects away from the eye.
                reflectv = (-lightv).reflect(norm)
                reflect_dot_eye = reflectv.dot(eye)
                if reflect_dot_eye <= 0:
                    specular = black
                else:
                    # compute the specular contribution
                    factor = math.pow(reflect_dot_eye, self.shininess)
                    specular = light.intensity * self.specular * factor

        # Add the three contributions together to get the final shading
        return ambient + diffuse + specular
예제 #8
0
 def local_intersects(self, ray):
     # Incoming ray is now in object space already
     # the vector from the sphere's center, to the ray origin
     # remember: the sphere is centered at the world origin
     sphere_to_ray = ray.origin - Tuple4.Point(0, 0, 0)
     a = ray.direction.dot(ray.direction)
     b = 2 * ray.direction.dot(sphere_to_ray)
     c = sphere_to_ray.dot(sphere_to_ray) - 1
     discriminant = math.pow(b, 2) - 4 * a * c
     if discriminant < 0:
         return Intersections()
     t1 = (-b - math.sqrt(discriminant)) / (2 * a)
     t2 = (-b + math.sqrt(discriminant)) / (2 * a)
     # Intersections are a scalar and an object, so we don't need to
     # transform them back to world space
     return Intersections(Intersection(t1, self), Intersection(t2, self))
예제 #9
0
 def __mul__(self, other):
     if isinstance(other, Matrix):
         if self.cols != other.rows:
             raise MatrixError('A.columns must equal B.rows to '
                               'multiply matrices.')
         data = []
         for r in range(0, self.rows):
             data.append([])
             for c in range(0, other.cols):
                 total = 0
                 for m in range(0, self.cols):
                     total += (self[r][m] * other[m][c])
                 data[r].append(total)
         return Matrix(data)
     elif isinstance(other, Tuple4.Tuple4):
         m1 = Matrix([[other.x], [other.y], [other.z], [other.w]])
         m2 = self * m1
         return Tuple4.Tuple4(m2[0][0], m2[1][0], m2[2][0], m2[3][0])
     else:
         raise MatrixError('Cannot mutiply a matrix by a ' +
                           type(other).__name__)
예제 #10
0
 def pattern(self, point):
     return Tuple4.Colour(point.x, point.y, point.z)
예제 #11
0
 def local_normal_at(self, point):
     # For test purposes, return the point as a vector
     return Tuple4.Vector(point.x, point.y, point.z)
예제 #12
0
 def local_normal_at(self, object_p):
     # This works entirely in object space
     object_n = object_p - Tuple4.Point(0, 0, 0)
     return object_n
예제 #13
0
 def local_normal_at(self, object_p):
     # This works entirely in object space
     # The normal for a plane is fixed
     object_n = Tuple4.Vector(0, 1, 0)
     return object_n