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
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
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