КомпГр_ЛР6_Заболотников_Петрова_Романова_9373
.pdfself.label_number_sphere_2 = ctk.CTkLabel(master=self.frame_right, text="Вторая сфера")
self.label_number_sphere_2.grid(row=6, column=0,columnspan=4, pady=0, padx=20, sticky="e")
self.entry000 = ctk.CTkEntry(master=self.frame_right, width=80,
textvariable=self.x3) self.entry000.grid(row=7, column=0, columnspan=2, pady=0, padx=20,
sticky="nw")
self.entry111 = ctk.CTkEntry(master=self.frame_right, width=50,
textvariable=self.y3) self.entry111.grid(row=7, column=0, columnspan=2, pady=0, padx=145,
sticky="nwe")
self.entry222 = ctk.CTkEntry(master=self.frame_right, width=80,
textvariable=self.z3) self.entry222.grid(row=7, column=0, columnspan=2, pady=0, padx=20,
sticky="ne")
self.label_number_sphere_3 = ctk.CTkLabel(master=self.frame_right, text="Третья сфера")
self.label_number_sphere_3.grid(row=7, column=0,columnspan=4, pady=0, padx=20, sticky="ne")
self.entry0c = ctk.CTkEntry(master=self.frame_right, width=80,
textvariable=self.r1) self.entry0c.grid(row=9, column=0, columnspan=2, pady=5, padx=20,
sticky="nw")
self.entry1c = ctk.CTkEntry(master=self.frame_right, width=50, textvariable=self.g1)
self.entry1c.grid(row=9, column=0, columnspan=2, pady=5, padx=145, sticky="nwe")
self.entry2c = ctk.CTkEntry(master=self.frame_right, width=80, textvariable=self.b1)
11
self.entry2c.grid(row=9, column=0, columnspan=2, pady=5, padx=20, sticky="ne")
self.label_number_sphere_color_1 = ctk.CTkLabel(master=self.frame_right, text="Первая сфера")
self.label_number_sphere_color_1.grid(row=9, column=0,columnspan=4, pady=0, padx=20, sticky="ne")
self.entry00c = ctk.CTkEntry(master=self.frame_right, width=80, textvariable=self.r2)
self.entry00c.grid(row=10, column=0, columnspan=2, pady=5, padx=20, sticky="nw")
self.entry11c = ctk.CTkEntry(master=self.frame_right, width=50, textvariable=self.g2)
self.entry11c.grid(row=10, column=0, columnspan=2, pady=5, padx=145, sticky="nwe")
self.entry22c = ctk.CTkEntry(master=self.frame_right, width=80, textvariable=self.b2)
self.entry22c.grid(row=10, column=0, columnspan=2, pady=5, padx=20, sticky="ne")
self.label_number_sphere_color_2 = ctk.CTkLabel(master=self.frame_right, text="Вторая сфера")
self.label_number_sphere_color_2.grid(row=10, column=0,columnspan=4, pady=0, padx=20, sticky="ne")
self.entry000c = ctk.CTkEntry(master=self.frame_right, width=80, textvariable=self.r3)
self.entry000c.grid(row=11, column=0, columnspan=2, pady=5, padx=20, sticky="nw")
self.entry111c = ctk.CTkEntry(master=self.frame_right, width=50, textvariable=self.g3)
12
self.entry111c.grid(row=11, column=0, columnspan=2, pady=5, padx=145, sticky="nwe")
self.entry222c = ctk.CTkEntry(master=self.frame_right, width=80, textvariable=self.b3)
self.entry222c.grid(row=11, column=0, columnspan=2, pady=5, padx=20, sticky="ne")
self.label_number_sphere_color_3 = ctk.CTkLabel(master=self.frame_right, text="Третья сфера")
self.label_number_sphere_color_3.grid(row=11, column=0,columnspan=4, pady=0, padx=20, sticky="ne")
self.entry_width = ctk.CTkEntry(master=self.frame_right, width=80, textvariable=self.width_im)
self.entry_width.grid(row=13, column=0, columnspan=2, pady=5, padx=20, sticky="w")
self.button_5 = ctk.CTkButton(master=self.frame_right, text="Нарисовать сцену", border_width=2, # <- custom
border_width
fg_color=None, # <- no fg_color command= self.write_to_image)
self.update()
self.button_5.grid(row=8, column=2, columnspan=1, pady=20, padx=20, sticky="we")
def apply(self): centers = []
for i in self.sph_c: t = []
for j in i: t.append(float(j.get()))
centers.append(t) t = []
colors = []
for i in self.sph_col: t = []
for j in i: t.append(float(j.get()))
13
colors.append(t) t = []
self.height = int(self.width_im.get()) self.width = int(self.height * 16.0 / 9.0) for i in range(len(centers[0])):
self.spheres[i + 1] = Sphere(vect3(centers[i][0], centers[i][1],centers[i][2]),
vect3(colors[i][0], colors[i][1],
colors[i][2]), abs(centers[i][1]))
def reset(self):
self.spheres = [Sphere(vect3(0, -1000, 0), vect3(1, 1, 1), 1000), Sphere(vect3(-3,1,1), vect3(2,2,2), 1), Sphere(vect3(0,1,1), vect3(1,1,1), 0.8), Sphere(vect3(2,1,1), vect3(1,2,2), 0.6),
# Sphere(vect3(0, 1004, 0), vect3(1, 1, 1), 1000),
]
# light sources
self.lights = [Sphere(vect3(0, 100, 0), vect3(0.0, 0.1, 0.2), 0), Sphere(vect3(100, 100, 200), vect3(0.3, 0.1, 0), 0), Sphere(vect3(-100, 100, 200), vect3(0.1, 0.3, 0.0),
0)]
c = |
[[0.0,0.0,0.0], |
|
[0.0,0.0,0.0], |
|
[0.0,0.0,0.0]] |
col |
= [[0.0,0.0,0.0], |
[0.0,0.0,0.0,],
[0.0,0.0,0.0]] w = 100
for i in range(len(c)):
for j in range(len(c[0])): self.sph_c[i][j].set(c[i][j])
for i in range(len(col)):
for j in range(len(col[0])): self.sph_col[i][j].set(col[i][j])
self.width_im.set(w) self.update()
def write_to_image(self):
14
maxval = 255
ppm_header = f'P6\n{self.width} {self.height}\n{maxval}\n' my_file = 'C:/USERS/Admin/blue_red_example1.ppm'
with open(my_file, 'wb') as f: f.write(bytearray(ppm_header, 'ascii'))
for y in range(self.height): for x in range(self.width):
c = trace(len(self.spheres) - 1, vect3(0, 1, 5), unit_vector(vect3(x - self.width / 2,
self.height / 2.0 - y, -self.height)), self.lights, self.spheres) pixel_col = vect3(int(min(1.0, c.x()) * 255.999),
int(min(1.0, c.y()) * 255.999),
int(min(1.0, c.z()) * 255.999)) write_color(my_file, pixel_col)
self.progressbar.set((self.width * y) / (self.width * self.height))
self.update()
window = tkinter.Tk()
window.geometry(f"{self.width + 100}x{self.height + 100}+500+500") canvas = tkinter.Canvas(window, width=self.width, height=self.height,
bg="#111111")
canvas.pack()
img = tkinter.PhotoImage(master=canvas, file=my_file, width=self.width, height=self.height)
canvas.create_image((0, 0), image=img, state="normal", anchor="nw") window.mainloop()
def change_appearance_mode(self, new_appearance_mode): ctk.set_appearance_mode(new_appearance_mode)
def on_closing(self, event=0): self.destroy()
if __name__ == "__main__": app = App() app.mainloop()
Файл «Vector.py»
class vec3:
import numpy as np class vec3:
15
def __new__(cls, *args, **kwargs): return super().__new__(cls)
def __init__(self, e0=0.0, e1=0.0, e2=0.0): self.e = [e0, e1, e2]
def x(self):
return self.e[0] def y(self):
return self.e[1] def z(self):
return self.e[2] def normalize(self):
n = self.__len__() if n > 0:
nn = 1 / n self.e[0] *= nn self.e[1] *= nn self.e[2] *= nn
return self def __neg__(self):
return vec3(-self.e[0], -self.e[1], -self.e[2]) def __getitem__(self, item):
return self.e[item]
def __iadd__(self, other): self.e[0] += other.e[0] self.e[1] += other.e[1] self.e[2] += other.e[2] return self
def __imul__(self, t: float): self.e[0] *= t
self.e[1] *= t self.e[2] *= t return self
def __idiv__(self, t: float): return self.__imul__(1 / t)
def __len__(self):
return np.sqrt(self.length_squared()) def length_squared(self):
return self.e[0] ** 2 + self.e[1] ** 2 + self.e[2] ** 2 def __repr__(self):
return f'vec3({self.e[0]}, {self.e[1]}, {self.e[2]})'
16
def __str__(self):
return f'{self.e[0]} {self.e[1]} {self.e[2]}' def __add__(self, other):
if isinstance(other, self.__class__): x = self.e[0] + other.e[0]
y = self.e[1] + other.e[1] z = self.e[2] + other.e[2] return vec3(x, y, z)
elif isinstance(other, int): x = self.e[0] + other
y = self.e[1] + other z = self.e[2] + other return vec3(x, y, z)
elif isinstance(other, float): x = self.e[0] + other
y = self.e[1] + other z = self.e[2] + other return vec3(x, y, z)
def __sub__(self, other):
if isinstance(other, self.__class__): x = self.e[0] - other.e[0]
y = self.e[1] - other.e[1] z = self.e[2] - other.e[2] return vec3(x, y, z)
elif isinstance(other, int): x = self.e[0] - other
y = self.e[1] - other z = self.e[2] - other return vec3(x, y, z)
elif isinstance(other, float): x = self.e[0] - other
y = self.e[1] - other z = self.e[2] - other return vec3(x, y, z)
def __mul__(self, other):
if isinstance(other, self.__class__): x = self.e[0] * other.e[0]
y = self.e[1] * other.e[1] z = self.e[2] * other.e[2] return vec3(x, y, z)
elif isinstance(other, int):
17
x = self.e[0] * other y = self.e[1] * other z = self.e[2] * other return vec3(x, y, z)
elif isinstance(other, float): x = self.e[0] * other
y = self.e[1] * other z = self.e[2] * other return vec3(x, y, z)
def __rmul__(self, t: float): return self * t
def __truediv__(self, t: float): return self * (1 / t)
def cross(self, other):
return vec3(self.e[1] * other.e[2] - self.e[2] * other.e[1], self.e[2] * other.e[0] - self.e[0] * other.e[2], self.e[0] * other.e[1] - self.e[1] * other.e[0])
def dot(self, other):
return self.e[0] * other.e[0] + self.e[1] * other.e[1] + self.e[2] * other.e[2]
def unit_vector(v: vec3):
return v.__truediv__(v.__len__().real)
point3 = vec3 color = vec3 vect3 = vec3
Файл «Color.py»
from struct import pack
def write_color(file_name, pixel_color):
x= int(pixel_color[0])
y= int(pixel_color[1])
z= int(pixel_color[2])
with open(file_name, 'ab') as file: file.write(pack('=BBB', x, y, z)) file.close()
Файл «Start.py»
from vector import * #from ray import * import ray
from math import pi, sqrt, inf
18
from color import *
from tkinter import Canvas, Tk, PhotoImage
class Sphere:
def __init__(self, p, ce, r): self.p = p
self.radius = r self.center = ce
def intersect(sphere: Sphere, start: vect3, direction: vect3, intersec: float):
P = start - sphere.p
a = dot(direction, direction) b = dot(P, direction) * 2
c1 = dot(P, P) - sphere.radius * sphere.radius d = b * b - 4 * a * c1
if d < 0: return 0
dsc = 2.0 * a sqd = sqrt(d)
intersec = (-b - sqd) / dsc
if intersec > 0.1: return intersec
intersec = (-b + sqd) / dsc if intersec > 0.1:
return intersec return 0
def trace(spheres_count, O, distance, lights, spheres): h = -1
T: float = 101118152822811797749760.0 t = 10.0 ** 10
for i in range(NS):
if intersect(spheres[i], O, distance, T):
T = intersect(spheres[i], O, distance, T) if t > T:
t = T h = i
if h > -1:
p = O + distance * T
n = unit_vector(p - spheres[h].p)
19
r = distance - n * dot(distance, n) * 2 c2 = spheres[h].center * 0.1
if not h:
spheres[h].center = vect3(1, 1, 1) if (int(p.x() + 10.0 ** 2) + int(p.z() + 10.0 ** 2)) & 1 else vect3(0, 0, 0)
for j in range(NL):
l1 = unit_vector(lights[j].p - p) sh = 0
for i in range(NS):
if intersect(spheres[i], p, l1, t): sh = 1
if not sh:
df = max(0, dot(l1, n)) * 0.7
sp = (max(0, dot(l1, n)) ** 50) * 0.3
c2 = c2 + spheres[h].center * lights[j].center * df + vect3(sp, sp, sp)
spheres_count = spheres_count - 1 if spheres_count:
c2 = c2 + trace(spheres_count, p, r, lights, spheres) * 0.51 return c2
return vect3(1 - distance.y(), 1 - distance.y(), 0.5 + distance.y())
spheres = [Sphere(vect3(0, -1000, 0), vect3(1, 1, 1), 1000), Sphere(vect3(-2.0, 1.0, 0.0), vect3(1, 0.0, 0.0), 1), Sphere(vect3(0.0, 0.8, 0.0), vect3(0.0, 1.0, 0.0), 0.8), Sphere(vect3(2.0, 10, -10.0), vect3(0.0, 0.0, 1.0), 0.6),
# Sphere(vect3(0, 1004, 0), vect3(1, 1, 1), 1000),
]
# light sources
lights = [Sphere(vect3(0, 100, 0), vect3(0.0, 0.1, 0.2), 0), Sphere(vect3(100, 100, 200), vect3(0.3, 0.1, 0), 0), Sphere(vect3(-100, 100, 200), vect3(0.1, 0.3, 0.0), 0)]
NS = 4
NL = 3
if __name__ == '__main__':
20