def find_intersection(self, ray):
        result = [0, False]
        #Ray to sphere direction
        oc = self.center - ray.origin
        #Ray to sphere length squared
        oc2 = dot_product(oc, oc)
        #Distance to the sphere along the ray
        #In other words, the point on the ray closest to the center
        tca = float(dot_product(oc, ray.direction))
     
        #Is the ray origin outside the sphere?
        outside = oc2 > (self.radius ** 2)
    
        if tca < 0.0 and outside:
            return result
        d2 = oc2 - tca * tca
        thc = (self.radius * self.radius) - d2
        if thc < 0.0:
            return result
        else:
            if outside:
                temp = tca - sqrt(thc)
            else:
                temp = tca + sqrt(thc)

            if temp < 0.0:
                return result
            
            result[1] = True
            result[0] = temp
            return result
def phong_light(point, normal, eye, material):
    #A variable to store the final color
    point_color = [0, 0, 0]
    #The ambient, diffuse and specular color of the material
    a_color = material.diffuse_color
    color = material.diffuse_color
    s_color = material.specular_color
    #Ensure that the normal is normalised
    normal.normalise()
    #The ambient coefficient ka
    ambient_coefficient = 0.2
    #Diffuse coefficient Kd 
    k_d = 1
    #Specular coefficient Ks
    k_s = 1
    #Perform ambient lighting
    i =0 
    while i < 3:
        point_color[i] = ambient_coefficient * a_color[i]
        i += 1
    #For each light, compute the contribution to color
    for light in lights:
        #Calculate the light vector
        light_vector = light.position - point
        #Calculate the distance to the light
        dist = light_vector.magnitude
        #Then normalise it
        light_vector.normalise()

        #Calculate the view vector
        view_vector = eye - point
        view_vector.normalise()
        
        #Compute the shadow ray
        shadow_ray = Ray(point + light_vector * 0.001, light_vector)
        #Check if there is an object in the way of the shadow ray
        obj = get_first_intersection(shadow_ray, dist)
        #If there is an object, this lights contribution isn't added
        if obj[0] is not None:
            continue;

        #Else, light it up!
        #Calculate the diffuse lighting
        diffuse = max(dot_product(normal, light_vector), 0.0)
        #Calculate the reflected ray
        reflect= normal * 2.0 * diffuse - light_vector
        reflect.normalise()
        #Calculate the specular lighting
        dp = max(dot_product(view_vector, light_vector), 0.0)
        specular = pow(dp, material.specular_power)
        #Add this lights contribution to each component of the color
        i = 0 
        while i < 3:
            point_color[i] += k_d * color[i] * diffuse\
                    + k_s * s_color[i] * specular
            i += 1
    return point_color
Ejemplo n.º 3
0
    def update(self, delta_time):
        """Animates the missile."""
        # Moves missile based on its direction (the forward vector)
        velocity = self.forward() * self.missile_speed
        self.position += velocity * delta_time

        # Rotate missile towards the player - Figure out where it is pointing and
        # where do we want to point it
        current_dir = self.forward()
        desired_dir = (Vector3(0, 0, 0) - self.position).normalized()
        # Find the angle between these two directions
        dp = max(-1, min(1, dot_product(current_dir, desired_dir)))
        angle = math.acos(dp)

        # If the angle is larger than the ammount we can rotate a single frame,
        # given by the time elapsed and the missile rotation speed, we need to
        # clamp the value of the angle
        if abs(angle) > self.missile_rotation_speed * delta_time:
            angle = self.missile_rotation_speed * delta_time * math.copysign(
                1, angle)

        # Figure out the rotation axis to point the missile towards the desired direction
        axis = cross_product(current_dir, desired_dir)
        axis.normalize()

        if (angle > 0.01):
            # Rotate the missile towards the player
            q = Quaternion.AngleAxis(axis, angle)
            self.rotation = q * self.rotation
    def find_intersection(self, ray):
        result = [0.0, False]
        rayD = dot_product(self.normal, ray.direction)
        #Check if the ray is parallel to the plane
        if fabs(rayD) < 0.0001:
            return result
        originD = -(dot_product(self.normal, ray.origin) + self.distance)
        intersectDist = originD / rayD

        #Check if the intersection is in front of the camera
        if intersectDist < 0.0001:
            return result

        result[1] = True
        result[0] = intersectDist
        return result
def get_reflected_ray(original_ray, point, normal):
    #Calculate the reflected ray
    normal.normalise()
    reflect_direction = original_ray.direction - normal * 2.0 * \
    dot_product(original_ray.direction, normal)
    reflect_direction.normalise()
    reflected_ray = Ray(point + reflect_direction * 0.0001, reflect_direction)
    return reflected_ray
def get_refracted_ray(ray, point, normal, obj):
    #Refractive indices :: Hard coded for now
    nc = 1.0
    nt = 1.5
    #Name changes - to keep track of things...
    in_dir = ray.direction
    #temp is used to decide if the ray is entering or exiting the medium
    temp = dot_product(in_dir, normal)
    if temp < 0.0:
        into = True
        nl = normal
    else:
        into = False
        nl = - normal
    #into tells you if the ray is entering or exiting!
    
    #Determine n1 / n2 
    if into:
        nnt = nc / nt
    else:
        nnt = nt / nc
    
    #Next compute cos theta
    ddn = dot_product(in_dir, nl)
    
    #Now compute the other cosine
    cos2t =  1 - (nnt * nnt) * (1 - ddn * ddn)
    #Deal with total internal reflection
    if cos2t < 0.0:
        print "error"
        refract_direction = None
    else: 
        if into:
            temp2 = normal * (ddn * nnt + sqrt(cos2t))
            temp2.normalise()
            refract_direction = in_dir * nnt - temp2 
        else:
            temp2 = normal * (ddn * nnt + sqrt(cos2t))
            temp2.normalise()
            refract_direction = in_dir * nnt + temp2
    refracted_ray = Ray(point + refract_direction * 0.001, refract_direction)
    return refracted_ray    
def lambert_light(point, normal, material):
    diffuse_coefficient = 1 
    point_color = [0, 0, 0]
    color = material.diffuse_color
    normal.normalise()
    for light in lights:
        light_vector = light.position - point
        light_vector.normalise()
        shade = dot_product(light_vector, normal)
        if shade < 0:
            shade = 0
        for i in range(len(point_color)):
            point_color[i] += light.color[i] * color[i] * diffuse_coefficient *\
                    shade
    return point_color
Ejemplo n.º 8
0
def create_terrain():
    """Creates a terrain, composed of different meshes (one per each type of material)
    It support snow, water, grassland and cliffsize, based on hard-coded parameters"""

    # Size of the terrain
    size_x = 4
    size_z = 4
    # Number of divisions of the terrain. Vertex count scales with the square of this
    div = 40
    # Paramters for water and snow height/depth
    water_depth = -0.1
    snow_height = 0.15

    px = size_x / div
    pz = size_z / div

    # For centering the terrain on the object center
    origin = Vector3(-size_x * 0.5, 0, -size_z * 0.5)

    # Create the meshes for each type of terrain
    grass_mesh = Mesh("Terrain_Grass")
    snow_mesh = Mesh("Terrain_Snow")
    cliff_mesh = Mesh("Terrain_Cliff")
    water_mesh = Mesh("Terrain_Water")

    for dz in range(0, div):
        for dx in range(0, div):
            p1 = Vector3(dx * px, 0, dz * pz) + origin
            p2 = Vector3((dx + 1) * px, 0, dz * pz) + origin
            p3 = Vector3((dx + 1) * px, 0, (dz + 1) * pz) + origin
            p4 = Vector3(dx * px, 0, (dz + 1) * pz) + origin

            p1.y = sample_height(p1.x, p1.z)
            p2.y = sample_height(p2.x, p2.z)
            p3.y = sample_height(p3.x, p3.z)
            p4.y = sample_height(p4.x, p4.z)

            # Check if any of the points is underwater
            water = clamp_to_water(p1, water_depth)
            water |= clamp_to_water(p2, water_depth)
            water |= clamp_to_water(p3, water_depth)
            water |= clamp_to_water(p4, water_depth)

            # Create the polygons
            poly = []
            poly.append(p1)
            poly.append(p2)
            poly.append(p3)
            poly.append(p4)

            if water:
                # Polygon was under water, add it to that mesh
                water_mesh.polygons.append(poly)
            else:
                # Check for snow height
                avg_y = (p1.y + p2.y + p3.y + p4.y) * 0.25
                if avg_y > snow_height:
                    # The polygon was above a certain point
                    snow_mesh.polygons.append(poly)
                else:
                    # Check for cliff face, check the normal
                    normal = cross_product((p3 - p1).normalized(),
                                           (p2 - p1).normalized())
                    if dot_product(normal, Vector3(0, 1, 0)) < 0.5:
                        cliff_mesh.polygons.append(poly)
                    else:
                        grass_mesh.polygons.append(poly)

    # Create materials for the terrain
    grass_material = Material(Color(0.1, 0.6, 0.1, 1), "GrassMaterial")
    snow_material = Material(Color(0.8, 0.8, 0.8, 1), "SnowMaterial")
    cliff_material = Material(Color(0.4, 0.4, 0.4, 1), "CliffMaterial")
    water_material = Material(Color(0, 0.5, 0.7, 1), "WaterMaterial")

    # Return meshes and materials
    meshes = [grass_mesh, snow_mesh, cliff_mesh, water_mesh]
    materials = [grass_material, snow_material, cliff_material, water_material]

    return meshes, materials