Файл: Принцип работы и применение технологии трассировки лучей.docx
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 03.02.2024
Просмотров: 13
Скачиваний: 0
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
def render(window, t, camera_pos, sphere_pos, radius, box_pos, box_size, camera_rot):
light = vec3(math.sin(t*0.25), math.cos(t*0.25), -1).normalize()
for y in range(int(p_height)):
for x in range(int(p_width)):
cam_pos = camera_pos
uv = vec2((x/p_width*2-1)* aspect, y/p_height*2-1)
ray_vel = vec3(1, uv.x, uv.y).rotateZ(camera_rot.z).normalize()
diff = 1
for k in range(max_reflections):
minIt = 99999
intersection = sphere(cam_pos - sphere_pos, ray_vel, radius)
n = vec3(0, 0, 0)
albedo = 1
if intersection.x > 0:
itPoint = cam_pos - sphere_pos + ray_vel * intersection.x
minIt = intersection.x
n = vec3.normalize(itPoint)
boxN = vec3(0, 1, 0)
intersection = box(cam_pos - box_pos, ray_vel, box_size, boxN)
if intersection.x > 0 and intersection.x < minIt:
minIt = intersection.x
n = boxN
intersection = plane(cam_pos, ray_vel, vec3(0, 0, -1), -10)
if intersection > 0 and intersection < minIt:
minIt = intersection
n = vec3(0, 0, -1)
albedo = 0.5
if minIt < 99999:
diff *= float(vec3.dot(n, light) * 0.5 + 0.5) * albedo
cam_pos += ray_vel * (minIt - 0.01)
ray_vel = vec3.reflect(ray_vel, n)
else:
break
pygame.draw.rect(window, (diff*255, diff*255, diff*255), (x*s_width, y*s_height, s_width, s_height))
2.4 Дополнение главного файла
После я добавил в класс приложения рендеринг и остальные файлы. Сразу после импортирования модулей я добавил импорт наших файлов:
from settings import *
from render import *
from vector import *
А после
#Input
keys = pygame.key.get_pressed()
нужно добавить следующий фрагмент кода для обработки нажатий клавиш
if keys[pygame.K_ESCAPE]:
self.execute = False
if keys[pygame.K_w]:
camera_pos.x += speed
if keys[pygame.K_s]:
camera_pos.x -= speed
if keys[pygame.K_d]:
camera_pos.y += speed
if keys[pygame.K_a]:
camera_pos.y -= speed
if keys[pygame.K_q]:
camera_rot.y += camera_speed
if keys[pygame.K_e]:
camera_rot.y -= camera_speed
Теперь передвижение камеры вперёд-назад, влево-вправо используются клавиши: [W][S][A][D]
А перед “pygame.display.flip()” нужно добавить:
render(self.screen, self.font, self.t, 1, camera_pos, sphere_pos, radius, box_pos, box_size, self.camera_rot)
Теперь можно проверять
(Приложение 4 Изображение 4)
Вывод: Результат выглядит неплохо, но частота кадров при этом низкая. Это потому что всю графику просчитывает процессор на одном ядре, а не видеокарта. В дальнейшей перспективе можно будет перенести всю работу с графикой в OpenGL. Это в несколько раз увеличит скорость и эффективность кода, но потребует значимых его изменений. Так как 3D графика в OpenGL состоит из двух основных шейдеров: вершинного и пиксельного.
Список литературы
1. Трассировка лучей(Wikipedia) https://ru.wikipedia.org/wiki/Трассировка_Лучей
2. История трассировки лучей(Shazoo) https://clck.ru/eByf9
3. Иллюстрации работы технологии https://clck.ru/eC2Pa и https://clck.ru/eC3Vi
4. Пример трассировки путей https://www.youtube.com/watch?v=R-CHTQAezWw
5. Официальный сайт Python https://www.python.org/
6. Мой исходный код https://github.com/wowlikon/Python-Console-Ray-tracing
7. Код, на основе которого было написано https://github.com/ArtemOnigiri/Console3D
8. SDL (Wikipedia) https://ru.wikipedia.org/wiki/SDL
9. Формулы пересечения луча https://clck.ru/eMpHz
10. OpenGL (Wikipedia) https://ru.wikipedia.org/wiki/OpenGL
Приложение 1
Изображение 1. Прямая трассировка лучей
Изображение 2. Обратная трассировка лучей
Изображение 3. Формулы пересечения с плоскостью, сферой и кубом
Приложение 2
Код 1:
class App:
def __init__(self):
#inicialization
pygame.init()
self.screen = pygame.display.set_mode(size, pygame.SCALED)
self.clock = pygame.time.Clock
self.execute = True
self.t = 0
self.camera_rot = vec3(0, 0, 0)/360 * 3.1415926535
def run(self):
#Set image
logo = pygame.image.load("logo.png")
pygame.display.set_icon(logo)
#Loop
while self.execute:
self.t += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.execute = False
#Input
keys = pygame.key.get_pressed()
#Drawing
self.screen.fill('black')
camera_rot = vec3(self.camera_rot.x%math.pi, self.camera_rot.y%math.pi,
self.camera_rot.z%math.pi)
pygame.display.flip()
self.clock.tick()
pygame.display.set_caption(f' GAME FPS: {self.clock.get_fps() :.2f}')
pygame.display.update()
#Run
if __name__ == '__main__':
app = App()
app.run()
pygame.quit()
Приложение 3
Код 2:
def step(a, b):
return b > a
def sign(v):
return (0 < v) - (v < 0)
def lerp(v1, v2, t) :
return (1 - t) * v1 + t * v2
class vec2:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __add__(self, other):
if is instance(other, self.__class__):
return vec2(self.x + other.x, self.y + other.y)
return vec2(self.x + other, self.y + other)
def __sub__(self, other):
if is instance(other, self.__class__):
return vec2(self.x - other.x, self.y - other.y)
return vec2(self.x - other, self.y - other)
def __mul__(self, other):
if is instance(other, self.__class__):
return vec2(self.x * other.x, self.y * other.y)
return vec2(self.x * other, self.y * other)
def __rmul__(self, other):
return self.__mul__(other)
def __truediv__(self, other):
if is instance(other, self.__class__):
return vec2(self.x / other.x, self.y / other.y)
return vec2(self.x / other, self.y / other)
def __eq__(self, other):
if is instance(other, self.__class__):
return self.x == other.x and self.y == other.y
return self.x == other and self.y == other
def __neg__(self):
return vec2(-self.x, -self.y)
def make_int_turple(self):
return int(self.x), int(self.y)
def set(self, vect):
self.x = vect.x
self.y = vect.y
def dot(vect1, vect2):
return vect1.x * vect2.x + vect1.y * vect2.y
def angle_between(vect1, vect2):
return math.acos(vec2.dot(vect1, vect2))
def angle(self):
return math.acos(self.dot(vec2(1, 0)))
def lenght(vect):
return math.sqrt(vect.x**2 + vect.y**2)
def dist(vect1, vect2):
vect = vect1 - vect2
return vect.lenght()
def normalize(vect):
vect_len = lenght(vect)
if vect_len < 0.00001:
return vec2(0, 1)
return vec2(vect.x/vect_len, vect.y/vect_len)
def reflect(incident, normal):
return incident - dot(normal, incident) * 2 * normal
def random_vector():
return vec2(random.random()*2-1, random.random()*2-1)
def random_direction():
return normalize(random_vector())
def copy(vect):
return vec2(vect.x, vect.y)
def rotate(self, a: float):
a = float(a.x)
new_x = ( self.x * math.cos(a)) - (-self.y * math.sin(a))
new_y = (-self.y * math.cos(a)) + ( self.x * math.sin(a))
return vec2(new_x, new_y)
def lerp(a, b, v: float):
return vec2(lerp(a.x, b.x, v), lerp(a.y, b.y, v))
class vec3:
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
if is instance(other, self.__class__):
return vec3(self.x + other.x, self.y + other.y, self.z + other.z)
return vec3(self.x + other, self.y + other, self.z + other)
def __sub__(self, other):
if is instance(other, self.__class__):
return vec3(self.x - other.x, self.y - other.y, self.z - other.z)
return vec3(self.x - other, self.y - other, self.z - other)
def __mul__(self, other):
if is instance(other, self.__class__):
return vec3(self.x * other.x, self.y * other.y, self.z * other.z)
return vec3(self.x * other, self.y * other, self.z * other)
def __rmul__(self, other):
return self.__mul__(other)
def __truediv__(self, other):
if is instance(other, self.__class__):
if other.x != 0 and other.y != 0 and other.z != 0:
return vec3(self.x / other.x, self.y / other.y, self.z / other.z)
else:
return vec3(99999, 99999, 99999)
else:
if other != 0:
return vec3(self.x / other, self.y / other, self.z / other)
else:
return vec3(0, 0, 0)
def __eq__(self, other):
if is instance(other, self.__class__):
return self.x == other.x and self.y == other.y and self.z == other.z
return self.x == other and self.y == other and self.z == other
def __neg__(self):
return vec3(-self.x, -self.y, -self.z)
def set(self, vect):
self.x = vect.x
self.y = vect.y
self.z = vect.z
def dot(vect1, vect2):
return vect1.x * vect2.x + vect1.y * vect2.y + vect1.z * vect2.z
def angle_between(vect1, vect2):
return math.acos(vec3.dot(vect1, vect2))
def lenght(vect):
return (vect.x**2 + vect.y**2 + vect.z**2)**(1/2)
def dist(vect1, vect2):
vect = vect1 - vect2
return vect.lenght()
def normalize(vect):
vect_len = vect.lenght()
if vect_len < 0.00001:
return vec3(0, 1, 0)
return vec3(vect.x/vect_len, vect.y/vect_len, vect.z/vect_len)
def reflect(incident, normal):
return incident - normal * (2*vec3.dot(normal, incident))
def random_vector():
return vec3(random.random()*2-1, random.random()*2-1, random.random()*2-1)
def random_direction():
return normalize(random_vector())
def copy(vect):
return vec3(vect.x, vect.y, vect.z)
def rotateX(self, angle):
return vec3(self.x, self.x*math.cos(angle)-self.y*math.sin(angle), self.x*math.sin(angle)+self.y*math.cos(angle))
def rotateY(self, angle):
return vec3(self.x*math.cos(angle)-self.y*math.sin(angle), self.y, self.x*math.sin(angle)+self.y*math.cos(angle))
def rotateZ(self, angle):
return vec3(self.x*math.cos(angle)-self.y*math.sin(angle), self.x*math.sin(angle)+self.y*math.cos(angle), self.z)
def rotate(self, angles):
vector = self
vector = vector.rotateX(angles.x)
vector = vector.rotateY(angles.y)
vector = vector.rotateZ(angles.z)
return vector
def sign(self):
return vec3(sign(self.x), sign(self.y), sign(self.z))
def step(self, edge):
return vec3(step(edge.x, self.x), step(edge.y, self.y), step(edge.z, self.z))
def lerp(a, b, v: float):
return vec3(lerp(a.x, b.x, v), lerp(a.y, b.y, v), lerp(a.z, b.z, v))
Приложение 4
Изображение 4. Результат. (Без трассировки лучей и с трассировкой лучей)