Untitled
unknown
python
2 years ago
5.6 kB
6
Indexable
from PIL import Image import numpy as np import math import colorsys #Define a vector class class Vector: def __init__(self, x, y, z): self.x = x self.y = y self.z = z def __mul__(self, a): return Vector(a*self.x, a*self.y, a*self.z) def __truediv__(self, a): return Vector(self.x/a, self.y/a, self.z/a) def __add__(self, other): return Vector(self.x + other.x, self.y + other.y, self.z + other.z) def __sub__(self, other): return Vector(self.x - other.x, self.y - other.y, self.z - other.z) def dot_product(self, other): return (self.x*other.x + self.y*other.y + self.z*other.z)*1.0 def abs(self): return math.sqrt(self.dot_product(self)) def normalize(self): return self / self.abs() def cos_angle(self, other): return self.dot_product(other)/(self.abs() * other.abs()) def sin_square_angle(self, other): cos = self.cos_angle(other) return 1 - cos**2 def print(self): print((self.x, self.y, self.z)) #Define a sphere class class Sphere: def __init__(self, radio, x = 0, y = 0, z = 0): self.center = Vector(x, y, z) self.radio = radio def normal_vector(self, point): v = point - self.center return v.normalize() def ray_casting(self, pixel): v = (pixel - camera).normalize() position = camera - self.center delta_over4 = (v.dot_product(position) ** 2) - (position.dot_product(position) - (self.radio ** 2)) #delta_over4 = self.radio**2 - position.dot_product(position)*v.sin_square_angle(position) if delta_over4 < 0: #print("Negative") return False elif delta_over4 == 0: #print("Zero") t = - v.dot_product(position) if t >= 0: return camera + v*t else: return False else: #print("Positive") t1 = - (v.dot_product(position) + math.sqrt(delta_over4)) t2 = math.sqrt(delta_over4) - v.dot_product(position) maximal = max(t1, t2) minimal = min(t1, t2) if minimal >= 0: return camera + v*minimal elif maximal >= 0: return camera + v*maximal else: return False class Color: def __init__(self, r, g, b): self.r, self.g, self.b = r, g, b def __add__(self, other): return Color(self.r + other.r, self.g + other.g, self.b + other.b) def to_tuple(self): return (int(self.r), int(self.g), int(self.b)) def intensity(self, k): hls_color = colorsys.rgb_to_hls(self.r, self.g, self.g) (r, g, b) = colorsys.hls_to_rgb(hls_color[0], k*hls_color[1], hls_color[2]) return Color(r, g, b) def intensity_dif(self, kr, kg, kb): hls_color = [0, 0, 0] hls_color[0] = colorsys.rgb_to_hls(self.r, 0, 0) hls_color[1] = colorsys.rgb_to_hls(0, self.g, 0) hls_color[2] = colorsys.rgb_to_hls(0, 0, self.b) color = [0, 0, 0] color[0] = colorsys.hls_to_rgb(hls_color[0][0], kr*hls_color[0][1], hls_color[0][2]) color[1] = colorsys.hls_to_rgb(hls_color[1][0], kg*hls_color[1][1], hls_color[1][2]) color[2] = colorsys.hls_to_rgb(hls_color[2][0], kb*hls_color[2][1], hls_color[2][2]) return Color(color[0][0], color[0][1], color[0][2]) + Color(color[1][0], color[1][1], color[1][2]) + Color(color[2][0], color[2][1], color[2][2]) #Image start width = 400 height = 400 image = Image.new(mode="RGB", size=(width, height), color=(0,0,0)) #Setup parameters camera = Vector(0, 0, -500) plan = Vector(-width/2, -height/2, -200) light_source = Vector(1000, 0, 0) #Color parametes light_color = Color(255, 255, 255) light_intensity = 1 env_color = Color(255, 255, 255) env_intensity = 0.1 #Constant terms n = 20 kd = (1, 1, 1) ks = 1 #Enviroment env = env_color.intensity(env_intensity) env = env.intensity_dif(kd[0], kd[1], kd[2]) sphere = Sphere(200) for i in range(width): for j in range(height): pixel = plan + Vector(i, j, 0) spectral = (0, 0, 0) point = sphere.ray_casting(pixel) if point != False: #Calculate parameters normal = sphere.normal_vector(point) light = (light_source - point).normalize() reflection = normal*(2*light.dot_product(normal)) - light visual = (camera - point).normalize() #Calculate dot products N_L = normal.dot_product(light) V_R = visual.dot_product(reflection) #Phong components difuse = (kd[0]*N_L, kd[1]*N_L, kd[2]*N_L) specular = ks*(visual.dot_product(reflection) ** n) if (N_L >= 0): if (V_R >= 0): spectral = (difuse[0] + specular, difuse[1] + specular, difuse[2] + specular) else: spectral = difuse spectral = (light_color.intensity_dif(spectral[0], spectral[1], spectral[2]) + env).to_tuple() image.putpixel([i, j], spectral) image.show()
Editor is loading...