python - 为什么 2d 光线追踪 + 镜子做(有时)半透明镜子(光线穿过并反射)
问题描述
使用 pygame(仅限 python)
描述:我正在学习光线追踪,我想做镜子(无光力,0%透明镜子)经典的直接光源是黄色的,反射是橙色的,反射的反射是红色的,有时当光源碰到镜子时,它产生一个反射(基本),然后另一个反射出现(总是红色,(它可能有帮助))以与光源相同的角度穿过镜子(直接穿过(但它变成红色(反射的反射)) )
有我的墙/镜子的代码
class Boundary:
def __init__(self, screen: pg.display, start: tuple, end: tuple,state: str):
self.start = pg.Vector2(start)
self.end = pg.Vector2(end)
self.image = None
self.state=state
self.color=(255,255,255)
self.tagged_rays="" # None
if self.state=="mirror":
self.color = (0,255,255)
self.tagged_rays=[]
def update(self, screen: pg.display):
if self.state=="mirror":
## writes the len of the tagged rays list var
screen.blit(pg.font.SysFont("helvetica", 10).render("{}".format(len(self.tagged_rays)), 10, (0,255,0)), (int(self.start.x+10), int(self.start.y)))
self.tagged_rays=[]
#print(len(self.tagged_rays))
## draw the wall / the mirror
self.image = pg.draw.line(screen, (self.color), self.start, self.end, 2)
错误的屏幕
有我的射线的代码
class Ray:
def __init__(self, p: Particle, heading: float = 0):
self.start = p.pos
self.heading = heading
self.end: pg.math.Vector2 = pg.math.Vector2()
self.image = None
#self.color = (randint(215,225),randint(175,200),0)
self.color =(255,255,0)
self.isrefleted=False
self.reflect_angle=0
def update(self, screen: pg.display, p: Particle, boundaries: list, rays:list, reflections:list):
self.isrefleted=False
self.start = p.pos
self.end.from_polar((sys.maxsize, self.heading))
closest = float("inf")
new_end = pg.Vector2()
x3 = self.start.x
x4 = self.end.x
y3 = self.start.y
y4 = self.end.y
for b in boundaries:
if b.state == "mirror" and self in b.tagged_rays:
continue
x1 = b.start.x
x2 = b.end.x
y1 = b.start.y
y2 = b.end.y
den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
if den == 0:
return
t_num = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)
t = t_num / den
u_num = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3))
u = u_num / den
if u >= 0 and 0 <= t <= 1:
x = x1 + t * (x2 - x1)
y = y1 + t * (y2 - y1)
dist = self.start.distance_to((x, y))
if dist < closest:
closest = dist
new_end.xy = x, y
if b.state=="mirror":
#print("REFLET")
#print(self.start.x-new_end.x,",",b.start.x-b.start.y)
radius1, self.reflect_angle1 = (self.start - self.end).as_polar()
radius2, self.reflect_angle2 = (b.start - b.end).as_polar()
#radius2, self.reflect_angle3 = (self.reflect_angle1 - self.reflect_angle2).as_polar()
if self.start.x < self.end.x:
#print(self.reflect_angle2,"pos")
self.reflect_angle2-=90
elif self.start.x > self.end.x:
#print(self.reflect_angle2,"neg")
self.reflect_angle2+=90
else:
pass
#print()
## 90* from the miror ( to understand the mechanics )
_90_reflet= False
if _90_reflet:
reflect2= Reflect(new_end, self.reflect_angle2,(0,255,0))
b.tagged_rays.append(reflect2)
reflections.append(reflect2)
reflect= Reflect(new_end, -self.reflect_angle1,(255,100,0))
b.tagged_rays.append(reflect)
reflections.append(reflect)
self.isrefleted=True
if closest == float("inf"):
self.end = self.start
self.image = None
else:
self.end = new_end
self.image = pg.draw.line(screen, self.color, (self.start.x,self.start.y), (self.end), 1)
anglepos=pg.math.Vector2()
anglepos.x = int(self.end.x)
anglepos.y= int(self.end.y)
w, h = pg.display.get_surface().get_size()
xoffset=10
yoffset=-3
if anglepos.x+len(str(self.heading)) >w:
anglepos.x -=50
if anglepos.y+10 >h:
anglepos.y -=20
if 0> anglepos.y:
anglepos.y=+10
screen.blit(pg.font.SysFont("helvetica", 11).render("{}".format(self.heading), 10, (0,255,255)), (int(anglepos.x+xoffset), int(anglepos.y+yoffset)))
#pg.draw.circle(screen,(255,0,0), (int(self.end.x),int(self.end.y)),5)
还有我反射光线的代码
from particle import Particle
import pygame as pg
from random import randint
import math,sys
class Reflect:
def __init__(self, r_End, heading: float = 0,color: tuple=(255,0,0)):
self.start= r_End
self.heading=heading
self.end: pg.math.Vector2 = pg.math.Vector2()
self.color =color
self.isrefleted=False
def update(self, screen: pg.display, p: Particle, boundaries: list,rays:list,reflections:list):
self.isrefleted=False
self.end.from_polar((sys.maxsize, self.heading))
closest = float("inf")
new_end = pg.Vector2()
x3 = self.start.x+3
x4 = self.end.x
y3 = self.start.y
y4 = self.end.y
for b in boundaries:
if b.state == "mirror" and self in b.tagged_rays:
continue
x1 = b.start.x
x2 = b.end.x
y1 = b.start.y
y2 = b.end.y
den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
if den == 0:
return
t_num = (x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)
t = t_num / den
u_num = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3))
u = u_num / den
if u >= 0 and 0 <= t <= 1:
x = x1 + t * (x2 - x1)
y = y1 + t * (y2 - y1)
dist = self.start.distance_to((x, y))
if dist < closest:
closest = dist
new_end.xy = x, y
if b.state=="mirror" and 1:
#print("REFLET")
#print(self.start.x-new_end.x,",",b.start.x-b.start.y)
radius1, self.reflect_angle1 = (self.start - self.end).as_polar()
radius2, self.reflect_angle2 = (b.start - b.end).as_polar()
#radius2, self.reflect_angle3 = (self.reflect_angle1 - self.reflect_angle2).as_polar()
if self.start.x < self.end.x:
#print(self.reflect_angle2,"pos")
self.reflect_angle2-=90
elif self.start.x > self.end.x:
#print(self.reflect_angle2,"neg")
self.reflect_angle2+=90
else:
pass
#print()
## 90* from the miror ( to understand the mechanics )
_90_reflet= False
if _90_reflet:
reflect2= Reflect(new_end, self.reflect_angle2,(0,255,0))
b.tagged_rays.append(reflect2)
reflections.append(reflect2)
if not -1<abs(self.heading) <1:
if not 179<abs(self.heading) <181:
#print(self.heading)
reflect=None
reflect= Reflect(new_end, -self.reflect_angle1,(255,0,0))
b.tagged_rays.append(reflect)
reflections.append(reflect)
self.isrefleted=True
if closest == float("inf"):
self.end = self.start
self.image = None
else:
self.end = new_end
#print(self.end)
self.image = pg.draw.line(screen, self.color, self.start, self.end,2)
anglepos=pg.math.Vector2()
anglepos.x = int(self.end.x)
anglepos.y= int(self.end.y)
w, h = pg.display.get_surface().get_size()
xoffset=10
yoffset=-3
if anglepos.x+len(str(self.heading)) >w:
anglepos.x -=50
if anglepos.y+10 >h:
anglepos.y -=20
if 0> anglepos.y:
anglepos.y=+10
screen.blit(pg.font.SysFont("helvetica", 11).render("{}".format(self.heading), 10, (0,255,255)), (int(anglepos.x+xoffset), int(anglepos.y+yoffset)))
#pg.draw.circle(screen,(255,0,0), (int(self.end.x),int(self.end.y)),5)
编辑,有粒子的代码
import pygame as pg
from random import randint
class Particle:
def __init__(self):
info = pg.display.Info()
self.image = None
pg.math.Vector2()
self.pos = pg.Vector2(randint(0, info.current_w), randint(0, info.current_h))
self.heading = 0
self.vel = pg.math.Vector2((0, 0))
def update(self, screen: pg.display,mouseX=int(),mouseY=int()):
#self.move_random()
self.move_on_mouse(mouseX,mouseY)
self.image = pg.draw.circle(screen, pg.Color('white'), (int(self.pos[0]), int(self.pos[1])), 4, 2) #basic (random)
def move_random(self):
info = pg.display.Info()
self.pos += self.vel
if self.pos.x < 0:
self.pos.x = 0
self.vel.x += 5
elif self.pos.x > info.current_w:
self.pos.x = info.current_w - 1
self.vel.x -= 5
if self.pos.y < 0:
self.pos.y = 0
self.vel.y += 5
elif self.pos.y > info.current_h:
self.pos.y = info.current_h - 1
self.vel.y -= 5
self.vel.x += randint(-5, 5)
self.vel.y += randint(-5, 5)
def move_on_mouse(self,mouseX=int(),mouseY=int()):
self.pos = pg.Vector2(mouseX, mouseY)
解决方案
推荐阅读
- ruby-on-rails - Ruby on Rails - 通过连接在 has_many 中使用了错误的外键
- c# - C# 错误 CS0029 无法将类型“int”隐式转换为 UnityEngine.UI.Text
- php - 如何使用 PHP 在字符串中使用 OR 运算符
- mongodb - 在 Mongodb Compass 中使用过滤器时没有结果
- java - VAO 绘制错误索引
- angular - autoprefixer 如何以角度与单个文件组件一起工作?
- bash - 在 Bash 中获取配置文件的最佳实践
- shell - 如何从 bash 中的 Json 文件中获取单个值?
- mysql - 如何为 COALESCE 定义 null 或零?
- neo4j - 如何在 Neo4j 中找到关键节点?