def __init__(self, color=color(255, 255, 255), position=V3(0, 0, 0), intensity=1): self.color = color self.position = position self.intensity = intensity
def getColor(self, tx, ty, intensity=1): if tx >= 0 and tx <= 1 and ty >= 0 and ty <= 1: x = round(tx * self.width - 1) y = round(ty * self.height - 1) return self.pixels[y][x] else: return color(0, 0, 0)
def read(self): image = open(self.path, "rb") image.seek(2 + 4 + 4) header_size = struct.unpack("=l", image.read(4))[0] image.seek(2 + 4 + 4 + 4 + 4) self.width = struct.unpack("=l", image.read(4))[0] self.height = struct.unpack("=l", image.read(4))[0] image.seek(header_size) self.pixels = [] for y in range(self.height): self.pixels.append([]) for x in range(self.width): b = ord(image.read(1)) g = ord(image.read(1)) r = ord(image.read(1)) self.pixels[y].append(color(r, g, b)) image.close()
for y in range(self.height): self.pixels.append([]) for x in range(self.width): b = ord(image.read(1)) g = ord(image.read(1)) r = ord(image.read(1)) self.pixels[y].append(color(r, g, b)) image.close() def getColor(self, tx, ty, intensity=1): if tx >= 0 and tx <= 1 and ty >= 0 and ty <= 1: x = round(tx * self.width - 1) y = round(ty * self.height - 1) return self.pixels[y][x] else: return color(0, 0, 0) # ivory = Material(diffuse=color(100, 100, 80), albedo=(0.6, 0.3, 0.1, 0), specular=50) # rubber = Material(diffuse=color(80, 0, 0), albedo=(0.9, 0.1, 0, 0, 0), specular=10) # glass = Material(diffuse=color(150, 180, 200), albedo=(0, 0.5, 0.1, 0.8), specular=125, refractive_index=1.5) # mirror = Material(diffuse=color(255, 255, 255), albedo=(0, 10, 0.8, 0), specular=1425) stone = Material(diffuse=color(184, 176, 155), albedo=(1, 0, 0, 0)) water = Material(diffuse=color(135, 206, 235), albedo=(0, 5, 0.6, 0), specular=1000, refractive_index=1.33) grass = Material(diffuse=color(132, 192, 17), albedo=(0.9, 0.1, 0, 0)) cloud = Material(diffuse=color(255, 255, 255), albedo=(0.6, 0.3, 0, 0)) snow = Material(diffuse=(255, 255, 255), albedo=(0.9, 0.2, 0, 0), specular=75)
from ray import RayTracer from ray import White from sphere import Sphere from usefullFunctions import V3 from light import Light from mats import Texture, water, grass, stone, cloud, snow from usefullFunctions import color from cube import Cube from plane import Plane r = RayTracer(2048, 2048) r.light = Light(position=V3(0, 20, -2), intensity=1.5) r.backgroundColor = color(50, 50, 200) r.scene = [ #Sky Cube(V3(-1, 4.9, -15), cloud, Texture('textures/cloud.bmp')), Cube(V3(0, 4.9, -15), cloud, Texture('textures/cloud.bmp')), Cube(V3(1, 4.9, -15), cloud, Texture('textures/cloud.bmp')), Cube(V3(2, 4.9, -15), cloud, Texture('textures/cloud.bmp')), Cube(V3(3, 4.9, -15), cloud, Texture('textures/cloud.bmp')), Cube(V3(4, 4.9, -15), cloud, Texture('textures/cloud.bmp')), Cube(V3(0, 5.9, -14), cloud, Texture('textures/cloud.bmp')), Cube(V3(1, 5.9, -14), cloud, Texture('textures/cloud.bmp')), Cube(V3(2, 5.9, -14), cloud, Texture('textures/cloud.bmp')), Cube(V3(3, 5.9, -14), cloud, Texture('textures/cloud.bmp')), Cube(V3(4, 5.9, -14), cloud, Texture('textures/cloud.bmp')), Cube(V3(5, 5.9, -14), cloud, Texture('textures/cloud.bmp')), Cube(V3(1, 6.9, -13), cloud, Texture('textures/cloud.bmp')),
def glColor(self, r, g, b): self.drawColor = color(r, g, b)
def glClearColor(self, r, g, b): self.clearColor = color(r, g, b)
def cast_ray(self, origin, direction, recursion=0): material_detected, impact = self.collisionDetected(origin, direction) if material_detected is None or recursion >= MAX_RECURSION_DEPTH: return self.backgroundColor light_direction = norm(sub(self.light.position, impact.point)) light_distance = length(sub(self.light.position, impact.point)) offset_normal = mul(impact.normal, 1.1) shadow_origin = sub( impact.point, offset_normal) if dot(light_direction, impact.normal) < 0 else sum( impact.point, offset_normal) shadow_material, shadow_intersect = self.collisionDetected( shadow_origin, light_direction) shadow_intensity = 0 if shadow_material and length( sub(shadow_intersect.point, shadow_origin)) < light_distance: shadow_intensity = 0.9 intensity = self.light.intensity * max( 0, dot(light_direction, impact.normal)) * (1 - shadow_intensity) reflection = reflect(light_direction, impact.normal) specular_intensity = self.light.intensity * (max( 0, -dot(reflection, direction))**material_detected.specular) if material_detected.albedo[2] > 0: reflect_dir = reflect(direction, impact.normal) reflect_orig = sub( impact.point, offset_normal) if dot(reflect_dir, impact.normal) < 0 else sum( impact.point, offset_normal) reflected_color = self.cast_ray(reflect_orig, reflect_dir, recursion + 1) else: reflected_color = Black if material_detected.albedo[3] > 0: refract_dir = refract(direction, impact.normal, material_detected.refractive_index) refract_orig = sub( impact.point, offset_normal) if dot(refract_dir, impact.normal) < 0 else sum( impact.point, offset_normal) refract_color = self.cast_ray(refract_orig, refract_dir, recursion + 1) else: refract_color = Black if impact.texture_color is not None: diffuse = impact.texture_color * intensity * material_detected.albedo[ 0] else: diffuse = material_detected.diffuse * intensity * material_detected.albedo[ 0] specular = color( 255, 255, 255) * specular_intensity * material_detected.albedo[1] reflected = reflected_color * material_detected.albedo[2] refraction = refract_color * material_detected.albedo[3] return diffuse + specular + reflected + refraction
from usefullFunctions import V3, color, char, dword, word, norm, sub, length, mul, reflect, refract, dot, sum from math import sin, cos, tan, pi from sphere import Sphere from light import Light White = color(255, 255, 255) Black = color(0, 0, 0) MAX_RECURSION_DEPTH = 3 class RayTracer(object): def __init__(self, width, height, fileName='test.bmp', clearColor=Black): self.width = width self.height = height self.fileName = fileName self.clearColor = clearColor self.pixels = [] self.scene = [] self.viewport = None self.drawColor = White self.backgroundColor = Black self.light = Light(V3(0, 0, 0), 1) self.glCreateWindow(self.width, self.height) def glInit(self): return ('TODO') def glCreateWindow(self, width, height): self.pixels = [[self.clearColor for x in range(width)] for y in range(height)]