简体   繁体   English

当我旋转立方体时,如何隐藏立方体的不朝前的面?

[英]How do I hide the faces of the cube that aren't facing forwards when I rotate the cube?

The code creates 3D coordinates for the cube and then displays them on the 2D screen but you can still see the back faces of the cube.该代码为立方体创建 3D 坐标,然后将它们显示在 2D 屏幕上,但您仍然可以看到立方体的背面。 I just want to tell the code not to draw the points that are behind the faces in the 3D coordinates.我只想告诉代码不要在 3D 坐标中绘制面后面的点。

输出图片

新输出

新输出2

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)]

These are the coordinates of the points and which points should be joined to which这些是点的坐标,哪些点应该连接到哪些点

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)

''' The FlattenPoint function rotates the 3D points and then turns them into 2D coordinates that are displayed. ''' FlattenPoint function 旋转 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 joins up the 2D coordinates. 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]]))

''' '''

Compute the normal vector to of a face and cull the faces where the normal vector points away from the view.计算一个面的法线向量 to 并剔除法线向量指向远离视图的面。 The normal vector can be computed with the 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]]

Use the cross product and cull the faces:使用叉积并剔除面:

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)

You have to ensure that the winding order of all the faces in counter clockwise.你必须确保所有面的缠绕顺序都是逆时针的。 See also Face Culling and Back-face culling见面剔除和背面剔除

Change the vertices and indices as follows:更改顶点和索引,如下所示:

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)]

However, I recommend to implement a depth test.但是,我建议实施深度测试。 See Pygame rotating cubes around axis and Does PyGame do 3d?请参阅Pygame 围绕轴旋转立方体PyGame 是否执行 3d? . .


Complete example:完整示例:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM