Файл: Принцип работы и применение технологии трассировки лучей.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. Результат. (Без трассировки лучей и с трассировкой лучей)