def ray4(FOVh, FOVv): ''' Parameters: FOVh (float): Horizontal field of view in radians FOVv (float): Vertical field of view in radians Returns: vector3d.vector.Vector: normalised vector ''' ray = Vector(-math.tan(FOVv / 2), math.tan(FOVh / 2), -1) return ray.normalize()
def rotateRays(ray1, ray2, ray3, ray4, roll, pitch, yaw): """Rotates the four ray-vectors around all 3 axes Parameters: ray1 (vector3d.vector.Vector): First ray-vector ray2 (vector3d.vector.Vector): Second ray-vector ray3 (vector3d.vector.Vector): Third ray-vector ray4 (vector3d.vector.Vector): Fourth ray-vector roll float: Roll rotation pitch float: Pitch rotation yaw float: Yaw rotation Returns: Returns new rotated ray-vectors """ sinAlpha = math.sin(yaw) sinBeta = math.sin(pitch) sinGamma = math.sin(roll) cosAlpha = math.cos(yaw) cosBeta = math.cos(pitch) cosGamma = math.cos(roll) m00 = cosAlpha * cosBeta m01 = cosAlpha * sinBeta * sinGamma - sinAlpha * cosGamma m02 = cosAlpha * sinBeta * cosGamma + sinAlpha * sinGamma m10 = sinAlpha * cosBeta m11 = sinAlpha * sinBeta * sinGamma + cosAlpha * cosGamma m12 = sinAlpha * sinBeta * cosGamma - cosAlpha * sinGamma m20 = -sinBeta m21 = cosBeta * sinGamma m22 = cosBeta * cosGamma # Matrix rotationMatrix = new Matrix(new double[][]{{m00, m01, m02}, {m10, m11, m12}, {m20, m21, m22}}) rotationMatrix = np.array([[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]]) # Matrix ray1Matrix = new Matrix(new double[][]{{ray1.x}, {ray1.y}, {ray1.z}}) # Matrix ray2Matrix = new Matrix(new double[][]{{ray2.x}, {ray2.y}, {ray2.z}}) # Matrix ray3Matrix = new Matrix(new double[][]{{ray3.x}, {ray3.y}, {ray3.z}}) # Matrix ray4Matrix = new Matrix(new double[][]{{ray4.x}, {ray4.y}, {ray4.z}}) ray1Matrix = np.array([[ray1.x], [ray1.y], [ray1.z]]) ray2Matrix = np.array([[ray2.x], [ray2.y], [ray2.z]]) ray3Matrix = np.array([[ray3.x], [ray3.y], [ray3.z]]) ray4Matrix = np.array([[ray4.x], [ray4.y], [ray4.z]]) res1 = rotationMatrix.dot(ray1Matrix) res2 = rotationMatrix.dot(ray2Matrix) res3 = rotationMatrix.dot(ray3Matrix) res4 = rotationMatrix.dot(ray4Matrix) rotatedRay1 = Vector(res1[0, 0], res1[1, 0], res1[2, 0]) rotatedRay2 = Vector(res2[0, 0], res2[1, 0], res2[2, 0]) rotatedRay3 = Vector(res3[0, 0], res3[1, 0], res3[2, 0]) rotatedRay4 = Vector(res4[0, 0], res4[1, 0], res4[2, 0]) rayArray = [rotatedRay1, rotatedRay2, rotatedRay3, rotatedRay4] return rayArray
def getBoundingPolygon(FOVh, FOVv, altitude, roll, pitch, heading): '''Get corners of the polygon captured by the camera on the ground. The calculations are performed in the axes origin (0, 0, altitude) and the points are not yet translated to camera's X-Y coordinates. Parameters: FOVh (float): Horizontal field of view in radians FOVv (float): Vertical field of view in radians altitude (float): Altitude of the camera in meters heading (float): Heading of the camera (z axis) in radians roll (float): Roll of the camera (x axis) in radians pitch (float): Pitch of the camera (y axis) in radians Returns: vector3d.vector.Vector: Array with 4 points defining a polygon ''' # import ipdb; ipdb.set_trace() ray11 = CameraCalculator.ray1(FOVh, FOVv) ray22 = CameraCalculator.ray2(FOVh, FOVv) ray33 = CameraCalculator.ray3(FOVh, FOVv) ray44 = CameraCalculator.ray4(FOVh, FOVv) rotatedVectors = CameraCalculator.rotateRays(ray11, ray22, ray33, ray44, roll, pitch, heading) origin = Vector(0, 0, altitude) intersections = CameraCalculator.getRayGroundIntersections( rotatedVectors, origin) return intersections
def render(screen: pygame.Surface, objects: Tuple[Geometry], lights: Tuple[Light]): screen.lock() for j in range(-int(SCREEN[1] / 2), int(SCREEN[1] / 2)): for i in range(-int(SCREEN[0] / 2), int(SCREEN[0] / 2)): x = (2 * (i + 0.5)) / (SCREEN[0] - 1) * math.tan(FOV / 2.0) * int( SCREEN[0]) / SCREEN[1] y = -(2 * (j + 0.5)) / (SCREEN[1] - 1) * math.tan(FOV / 2.0) direction = Vector(x, y, -1).normalize() screen.set_at((i + int(SCREEN[0] / 2), j + int(SCREEN[1] / 2)), cast_ray(Vector(0, 0, 0), direction, tuple(objects), tuple(lights))) pygame.display.flip() screen.unlock()
def cast_ray(orig: Vector, direction: Vector, objects: Tuple[Geometry], lights: Tuple[Light], depth=0): c = None res, hit, N, obj_hit = scene_intersect(orig, direction, objects) if depth > 4 or not res: return (128, 200, 255) refl_dir = reflect(direction, N).normalize() refl_orig = hit - N * 0.001 if refl_dir * N < 0 else hit + N * 0.001 refl_color = cast_ray(refl_orig, refl_dir, objects, lights, depth + 1) obj_to_render = obj_hit if hit: diffuse_light_intens = 0 specular_light_intens = 0 for light in lights: light_dir = (light.pos - hit).normalize() diffuse_light_intens += light.intensity * max(0.0, light_dir * N) specular_light_intens += pow( max(0.0, -reflect(-light_dir, N) * direction), obj_to_render.specular()) * light.intensity c = obj_to_render.diffuse_color( ) * diffuse_light_intens * obj_to_render.albedo().x + Vector( 1.0, 1.0, 1.0) * specular_light_intens * 255 * obj_to_render.albedo( ).y + Vector(*refl_color) * obj_to_render.albedo().z if c.x > 255: c.x = 255 if c.y > 255: c.y = 255 if c.z > 255: c.z = 255 return (int(c.x), int(c.y), int(c.z))
def findRayGroundIntersection(ray, origin): """ Finds a ray-vector's intersection with the ground approximated by a planeç Parameters: ray (vector3d.vector.Vector): Ray-vector origin (vector3d.vector.Vector): Camera's position Returns: vector3d.vector.Vector """ # Parametric form of an equation # P = origin + vector * t x = Vector(origin.x, ray.x) y = Vector(origin.y, ray.y) z = Vector(origin.z, ray.z) # Equation of the horizontal plane (ground) # -z = 0 # Calculate t by substituting z t = -(z.x / z.y) # Substitute t in the original parametric equations to get points of intersection return Vector(x.x + x.y * t, y.x + y.y * t, z.x + z.y * t)
def getBoundingPolygon(FOVh, FOVv, roll, pitch, yaw, camera_pos=(0.0, 0.0, 100.0), units="feet"): '''Get corners of the polygon captured by the camera on the ground. The calculations are performed in the axes origin (0, 0, altitude) and the points are not yet translated to camera's X-Y coordinates. Parameters: FOVh (float): Horizontal field of view in degrees FOVv (float): Vertical field of view in degrees roll (float): Roll of the camera (x axis) in degrees yaw (float): Heading of the camera (z axis) in degrees pitch (float): Pitch of the camera (y axis) in degrees camera_pos (float): Tuple. XYZ coordinate of camera units (str): Units label Returns: vector3d.vector.Vector: Array with 4 points defining a polygon ''' # import ipdb; ipdb.set_trace() # Convert into radians FOVh = np.radians(float(FOVh)) FOVv = np.radians(float(FOVv)) roll = np.radians(float(roll)) pitch = np.radians(float(pitch)) yaw = np.radians(float(yaw)) ray11 = CameraCalculator.ray1(FOVh, FOVv) ray22 = CameraCalculator.ray2(FOVh, FOVv) ray33 = CameraCalculator.ray3(FOVh, FOVv) ray44 = CameraCalculator.ray4(FOVh, FOVv) rotatedVectors = CameraCalculator.rotateRays(ray11, ray22, ray33, ray44, roll, pitch, yaw) origin = Vector(camera_pos[0], camera_pos[1], camera_pos[2]) intersections = CameraCalculator.getRayGroundIntersections( rotatedVectors, origin) return intersections
def main(): objects = [ Sphere(Vector(-3, 0, -16), 4, Material(Vector(0.0, 0.4, 0.9), (Vector(255, 255, 255)), 50)), Sphere(Vector(9, 1, -16), 7, Material(Vector(0.9, 0.1, 0.2), Vector(255, 128, 255), 10)), Sphere(Vector(-8, 5, -16), 2, Material(Vector(0.4, 0.5, 0.4), Vector(0, 128, 0), 100)) ] lights = [ Light(Vector(-20, 20, 20), 1.5), Light(Vector(30, 50, -25), 1.3), Light(Vector(30, 20, 30), 0.7) ] pygame.init() pygame.display.set_caption("SW RT") screen = pygame.display.set_mode((int(SCREEN[0]), int(SCREEN[1]))) while True: st = time.time() render(screen, objects, lights) print(time.time() - st) pygame.display.flip() objects[0].pos.x += 1 for event in pygame.event.get(): if event.type == pygame.QUIT: return