问题描述
代码为立方体创建 3D 坐标,然后将它们显示在 2D 屏幕上,但您仍然可以看到立方体的背面。我只是想告诉代码不要在 3D 坐标中绘制面后面的点。
points = [(-1,-1,-1),(-1,1),1,(1,]#coords for points
faces = [(3,4,7),5,6,2),(2,3),(5,7,6),(3,2,(0,4)]
这些是点的坐标以及哪些点应该连接到哪些
def flattenPoint(point):
(x,y,z) = (point[0],point[1],point[2])
xnew = x#x axis rotation
ynew = y * math.cos(rotatedanglex) - z * math.sin(rotatedanglex)
znew = y * math.sin(rotatedanglex) + z * math.cos(rotatedanglex)
xnew = znew * math.sin(rotatedangley) + xnew * math.cos(rotatedangley)
ynew = ynew #y axis rotation
znew = ynew * math.cos(rotatedangley) - xnew * math.sin(rotatedangley)
projectedY = int(height / 2 + ((ynew * distance) / (znew + distance)) * scale)
projectedX = int(width / 2 + ((xnew * distance) / (znew + distance)) * scale)
return (projectedX,projectedY,znew)
def createOutline(points):
a,b,c,d = points[0],points[1],points[2],points[3]
coords = ((b[0],b[1]),(a[0],a[1]),(d[0],d[1]),(c[0],c[1]))
pygame.draw.polygon(screen,blue,coords,1)
''' FlattenPoint 函数旋转 3D 点,然后将它们转换为显示的 2D 坐标。 '''
def createFace(points):
a,green,coords)
createFace 连接二维坐标。
def render(points,faces):
coords = []
for point in points:
coords.append(flattenPoint(point))
screen.fill(screencolour)
for face in faces:
createFace((coords[face[0]],coords[face[1]],coords[face[2]],coords[face[3]]))
for face in faces:#must draw outline after all the faces have been drawn
createOutline((coords[face[0]],coords[face[3]]))
'''
解决方法
计算一个面的法向量 to 并剔除法向量指向远离视图的面。法向量可以用 Cross product 计算:
def cross(a,b):
return [a[1]*b[2] - a[2]*b[1],a[2]*b[0] - a[0]*b[2],a[0]*b[1] - a[1]*b[0]]
使用叉积并剔除面:
def createFace(points):
a,b,c,d = points[0],points[1],points[2],points[3]
v1 = b[0]-a[0],b[1]-a[1],b[2]-a[2]
v2 = c[0]-a[0],c[1]-a[1],c[2]-a[2]
n = cross(v1,v2)
if n[2] < 0:
return
coords = ((b[0],b[1]),(a[0],a[1]),(d[0],d[1]),(c[0],c[1]))
pygame.draw.polygon(screen,green,coords)
你必须确保所有面的缠绕顺序都是逆时针的。另见Face Culling和Back-face culling
按如下方式更改顶点和索引:
points = [(-1,-1,-1),( 1,(1,1,(-1,1),1)]
faces = [(0,2,3),(5,4,7,6),(4,3,7),5,6,2),0),(3,7)]
但是,我建议实施深度测试。请参阅 Pygame rotating cubes around axis 和 Does PyGame do 3d?。
完整示例:
import pygame
import math
points = [(-1,7)]
def flattenPoint(point):
(x,y,z) = (point[0],point[1],point[2])
xnew = x#x axis rotation
ynew = y * math.cos(rotatedanglex) - z * math.sin(rotatedanglex)
znew = y * math.sin(rotatedanglex) + z * math.cos(rotatedanglex)
xnew = znew * math.sin(rotatedangley) + xnew * math.cos(rotatedangley)
ynew = ynew #y axis rotation
znew = ynew * math.cos(rotatedangley) - xnew * math.sin(rotatedangley)
projectedY = int(height / 2 + ((ynew * distance) / (znew + distance)) * scale)
projectedX = int(width / 2 + ((xnew * distance) / (znew + distance)) * scale)
return (projectedX,projectedY,znew)
def cross(a,a[0]*b[1] - a[1]*b[0]]
def createOutline(points):
a,blue,coords,3)
def createFace(points):
a,coords)
def render(points,faces):
coords = []
for point in points:
coords.append(flattenPoint(point))
screen.fill(screencolour)
for face in faces:
createFace((coords[face[0]],coords[face[1]],coords[face[2]],coords[face[3]]))
for face in faces:#must draw outline after all the faces have been drawn
createOutline((coords[face[0]],coords[face[3]]))
pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
rotatedanglex = 0.0
rotatedangley = 0.0
width,height = screen.get_size()
distance = 200.0
scale = 75.0
green = (0,255,0)
blue = (0,255)
screencolour = (0,0)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill(0)
render(points,faces)
pygame.display.flip()
rotatedanglex += 0.01
rotatedangley += 0.02
pygame.quit()
exit()