如何解决靠近相机时 3D 对象出现故障
问题
我正在使用 Python 模块 Turtle 制作 3D 引擎。它现在可以“正常”工作,但存在一些错误(没有相机旋转,面部未按正确顺序渲染,投影看起来不正确)。 主要错误是,当我越过相机 y 的某个点(朝向和远离物体)时,我位于物体之间,它会导致一切在视觉上破裂,直到我经过它并且即使我仍在 y 轴上向前移动,物体也开始移动(它们也被翻转了)。 我不知道这是我的编码还是我没有实现一些数学,但这里有一个 gif 显示了什么是正在发生:
代码
demo.py
import Engine3D as e3d
import time
camera = e3d.Camera(0,0)
screen = camera.screen
cursor = camera.cursor
screen.title("Demo")
screen.screensize(400,400)
screen.bgcolor("grey")
cursor.pensize(5)
if __name__ == "__main__":
size = 100
cube0_center = e3d.Point3D(100,220,100)
cube0 = e3d.Cube(cube0_center,size,"None")
cube1_center = e3d.Point3D(-100,100)
cube1 = e3d.Cube(cube1_center,"Red")
cube2_center = e3d.Point3D(100,-100)
cube2 = e3d.Cube(cube2_center,["Red","Green","Yellow","Blue","White","Purple"])
pyramid0_center = e3d.Point3D(-100,-100)
pyramid0 = e3d.Pyramid(pyramid0_center,["None","None","Green"])
objects = [cube0,cube1,cube2,pyramid0]
keys = []
screen.getcanvas().winfo_toplevel().bind("<KeyPress>",lambda x: (keys.append(str(x.keysym).lower()) if not str(x.keysym).lower() in keys else print("",end="")))
screen.getcanvas().winfo_toplevel().bind("<keyrelease>",lambda x: (keys.remove(str(x.keysym).lower()) if str(x.keysym).lower() in keys else print("",end="")))
while True:
e3d.render(objects,camera)
cube0.rotate(-0.01,0.01)
cube1.rotate(-0.01,-0.01)
cube2.rotate(0.01,0.01)
pyramid0.rotate(0.01,-0.01)
if "w" in keys: camera.move(0,2.5)
if "s" in keys: camera.move(0,-2.5)
if "d" in keys: camera.move(2.5,0)
if "a" in keys: camera.move(-2.5,0)
if "shift_l" in keys: camera.move(0,2.5,0)
if "control_l" in keys: camera.move(0,-2.5,0)
time.sleep(1 / 60)
Engine3D.py
import turtle
import math
class Point3D:
def __init__(self,x,y,z):
self.x = float(x)
self.y = float(y)
self.z = float(z)
def combine(self,z):
self.x += x
self.y += y
self.z += z
return self
class Point2D:
def __init__(self,y):
self.x = float(x)
self.y = float(y)
def combine(self,y):
self.x += x
self.y += y
return self
class Shape():
def __init__(self,center,side,color=None):
self.d = side/2
self.center = center
self.side = side
self.vertices = [
]
self.faces = [
]
if (type(color) == list or type(color) == tuple) and len(color) == len(self.faces): self.colors = color
elif (type(color) == list or type(color) == tuple) and len(color) != len(self.faces): self.colors = [color[0] for i in range(len(self.faces))]
elif (type(color) == str): self.colors = [color for i in range(len(self.faces))]
else: self.colors = ["None" for i in range(len(self.faces))]
def rotate(self,theta,phi) :
for point in self.vertices:
ct = math.cos(theta);
st = math.sin(theta);
cp = math.cos(phi);
sp = math.sin(phi);
x = point.x - self.center.x;
y = point.y - self.center.y;
z = point.z - self.center.z;
point.x = ct * x - st * cp * y + st * sp * z + self.center.x;
point.y = st * x + ct * cp * y - ct * sp * z + self.center.y;
point.z = sp * y + cp * z + self.center.z;
def move(self,z):
for point in self.vertices:
point.x += x; self.center.x += x
point.y += y; self.center.y += y
point.z += z; self.center.z += z
class Cube(Shape):
def __init__(self,color=None):
self.d = side/2
self.center = center
self.side = side
self.vertices = [
Point3D(center.x - self.d,center.y - self.d,center.z + self.d),Point3D(center.x - self.d,center.z - self.d),Point3D(center.x + self.d,center.y + self.d,center.z + self.d)
]
self.faces = [
[self.vertices[0],self.vertices[1],self.vertices[2],self.vertices[3]],[self.vertices[3],self.vertices[5],self.vertices[4]],[self.vertices[4],self.vertices[6],self.vertices[7]],[self.vertices[7],self.vertices[0]],self.vertices[0],self.vertices[3],[self.vertices[1],self.vertices[2]]
]
if (type(color) == list or type(color) == tuple) and len(color) == len(self.faces): self.colors = color
elif (type(color) == list or type(color) == tuple) and len(color) != len(self.faces): self.colors = [color[0] for i in range(len(self.faces))]
elif (type(color) == str): self.colors = [color for i in range(len(self.faces))]
else: self.colors = ["None" for i in range(len(self.faces))]
class Pyramid(Shape):
def __init__(self,color=None):
self.d = side/2
self.center = center
self.side = side
self.vertices = [
Point3D(center.x,center.z),]
self.faces = [
[self.vertices[0],self.vertices[2]],[self.vertices[0],self.vertices[4]]
]
if (type(color) == list or type(color) == tuple) and len(color) == len(self.faces): self.colors = color
elif (type(color) == list or type(color) == tuple) and len(color) != len(self.faces): self.colors = [color[0] for i in range(len(self.faces))]
elif (type(color) == str): self.colors = [color for i in range(len(self.faces))]
else: self.colors = ["None" for i in range(len(self.faces))]
class Camera:
def __init__(self,x=0,y=0,z=0):
self.position = Point3D(x,z)
self.screen = turtle.Screen()
self.screen.delay(0)
self.screen.tracer(0)
self.cursor = turtle.Turtle()
self.cursor.ht()
self.cursor.pu()
self.cursor.speed(0)
def move(self,z):
self.position.combine(-x,-y,z)
def teleport(self,z):
self.position = Point3D(-x,z)
def rotate(self,z):
pass
def snap(self,z):
pass
class Fill:
def __init__(self,color,cursor):
self.cursor = cursor
self.color = color
def __enter__(self):
if not self.color.lower() == "none":
self.cursor.fillcolor(self.color)
self.cursor.begin_fill()
def __exit__(self,type,value,traceback):
if not self.color.lower() == "none":
self.cursor.end_fill()
def project(M,camera):
d = 100
r = d / M.y
return Point2D(r * M.x,r * M.z)
def mean(numbers):
return sum(numbers)/len(numbers)
def midpoint3D(points):
x = [x.x for x in points]
y = [y.y for y in points]
z = [z.z for z in points]
return (mean(x),mean(y),mean(z))
def midpoint2D(points):
x = [x.x for x in points]
y = [y.y for y in points]
return (mean(x),mean(y))
def shape(points,cursor):
with Fill(color,cursor):
cursor.pu()
cursor.goto(points[0].x,points[0].y)
cursor.pd()
for point in points[1:]:
cursor.goto(point.x,point.y)
cursor.goto(points[0].x,points[0].y)
cursor.pu()
def distance(x0,y0,z0,x1,y1,z1):
return math.sqrt(math.pow(x1 - x0,2) + math.pow(y1 - y0,2) + math.pow(z1 - z0,2)* 1.0)
def render(objects,camera):
camera.cursor.clear()
for _object in objects:
color = dict([(str(b),_object.colors[a]) for a,b in enumerate(_object.faces)])
for index,face in enumerate(sorted(_object.faces,key=lambda o: min(list(map(lambda v: distance(camera.position.x,camera.position.y,camera.position.z,v.y,0),o))),reverse=True)):
points2D = []
points3D = []
for point in face:
cameraPoint = Point3D(point.x+camera.position.x,point.y+camera.position.y,point.z+camera.position.z)
P = project(cameraPoint,camera)
points2D.append(Point2D(P.x,-P.y))
points3D.append(cameraPoint)
shape(points2D,color[str(face)],camera.cursor)
#midpoint = midpoint3D(points3D)
#point = Point3D(midpoint[0],midpoint[1],midpoint[2])
#P = project(point)
#cursor.goto(P.x,-P.y)
#cursor.dot(5,"black")
camera.screen.update()
结束语
如果您知道如何修复此错误、其他错误、我的代码格式、变量名称和 ETC,请告诉我,以便我(希望)在未来的项目中对其进行更改。谢谢!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。