简体   繁体   中英

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. I just want to tell the code not to draw the points that are behind the faces in the 3D coordinates.

输出图片

新输出

新输出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. '''

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.

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. 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? .


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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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