python - 当我旋转立方体时,如何隐藏立方体的不朝前的面?
问题描述
该代码为立方体创建 3D 坐标,然后将它们显示在 2D 屏幕上,但您仍然可以看到立方体的背面。我只想告诉代码不要在 3D 坐标中绘制面部后面的点。
points = [(-1,-1,-1),(-1,-1,1),(-1,1,1),(-1,1,-1),
(1,-1,-1),(1,-1,1),(1,1,1),(1,1,-1), ]#coords for points
faces = [(3,0,4,7),(1,5,6,2),(2,1,0,3),(5,4,7,6),(3,2,6,7),(0,1,5,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, 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, green, coords)
createFace 连接了 2D 坐标。
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[1]], coords[face[2]],coords[face[3]]))
'''
解决方案
计算一个面的法线向量 to 并剔除法线向量指向远离视图的面。法线向量可以用叉积计算:
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)
你必须确保所有面的缠绕顺序都是逆时针的。另见面剔除和背面剔除
更改顶点和索引,如下所示:
points = [(-1,-1,-1),( 1,-1,-1), (1, 1,-1),(-1, 1,-1),
(-1,-1, 1),( 1,-1, 1), (1, 1, 1),(-1, 1, 1)]
faces = [(0,1,2,3),(5,4,7,6),(4,0,3,7),(1,5,6,2),(4,5,1,0),(3,2,6,7)]
但是,我建议实施深度测试。请参阅Pygame 围绕轴旋转立方体和PyGame 做 3d 吗?.
完整示例:
import pygame
import math
points = [(-1,-1,-1),( 1,-1,-1), (1, 1,-1),(-1, 1,-1),
(-1,-1, 1),( 1,-1, 1), (1, 1, 1),(-1, 1, 1)]
faces = [(0,1,2,3),(5,4,7,6),(4,0,3,7),(1,5,6,2),(4,5,1,0),(3,2,6,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, 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 createOutline(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, blue, coords, 3)
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)
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[1]], coords[face[2]],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, 0, 255)
screencolour = (0, 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()
推荐阅读
- python - Pygame 矩形不会出现,除非我退出并返回
- windows - `read_csv` 在 Windows 中看不到我的文件
- sql-server - 根据使用 T-SQL 的 xml 字段中的连接值更新表中的 xml 特定节点
- php - PHP不会将用户数据插入SQL?
- python - peewee 一对多作为集合
- algorithm - 有约束的座位算法
- swift - Swift 4 mapkit 在隐藏地图注释后重新加载地图
- c# - 使用 linqToExcel 从 excel 中读取日期
- variables - 存储网站范围的变量
- dart - 你需要在 Dart 中使用“new”关键字吗?