简体   繁体   English

Pygame 不会以正确的顺序绘制四边形

[英]Pygame won't draw quads in the right order

I have been trying to make a 3d engine with python for some time, and I have gotten pretty far, however I have found a problem in when I try and sort items in a list, the sorting flips when you are close enough to the cube.一段时间以来,我一直在尝试使用 python 制作 3d 引擎,而且我已经走了很远,但是当我尝试对列表中的项目进行排序时,我发现了一个问题,当你离立方体足够近时,排序会翻转.

main.py:主要.py:

import os
os.environ["SDL_VIDEO_CENTERED"] = '1'
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = '1'
import pygame
from pygame import gfxdraw
import math
from matrix import matrix_multiplication
import mesh
from random import randint as random
import time

startTime = time.time()

black, white, blue  = (20, 20, 20), (230, 230, 230), (0, 154, 255)
width, height = 700, 700

pygame.init()
pygame.display.set_caption("3D Engine")
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
frames = 60
outline = False

rs, gs, bs = [random(0, 255) for i in range(len(mesh.faces))], [random(0, 255) for i in 
range(len(mesh.faces))], [random(0, 255) for i in range(len(mesh.faces))]

angle_x = 0
angle_y = 0
angle_z = 0
pos_x = 0
pos_y = 0
pos_z = 0
cube_position = [width//2, height//2]
scale = 600
speed = 0.001
points = [[[i] for i in j] for j in mesh.verts]
movSpeed = 0.001

font = pygame.font.SysFont("Corbel", 23)

def avarageX(i):
     return (new_points[mesh.faces[i][0]][0][0] + new_points[mesh.faces[i][1]][0][0] + new_points[mesh.faces[i][2]][0][0] + new_points[mesh.faces[i][3]][0][0]) / 4

def avarageY(i):
     return (new_points[mesh.faces[i][0]][1][0] + new_points[mesh.faces[i][1]][1][0] + new_points[mesh.faces[i][2]][1][0] + new_points[mesh.faces[i][3]][1][0]) / 4

def avarageZ(i):
    return (new_points[mesh.faces[i][0]][2][0] + new_points[mesh.faces[i][1]][2][0] + new_points[mesh.faces[i][2]][2][0] + new_points[mesh.faces[i][3]][2][0]) / 4

def distToCam(i):
    a = [0, 0, 0]
    b = [avarageX(i), avarageY(i), avarageZ(i)]
    return math.dist(a, b)

print("It took: {} seconds".format(time.time() - startTime))

run = True
while run:
    dt = clock.tick(frames)
    fps = clock.get_fps()
    screen.fill(white)
    
    keys = pygame.key.get_pressed()
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    index = 0
    projected_points = [j for j in range(len(points))]

    rotation_x = [[1, 0, 0],
                  [0, math.cos(angle_x), -math.sin(angle_x)],
                  [0, math.sin(angle_x), math.cos(angle_x)]]

    rotation_y = [[math.cos(angle_y), 0, -math.sin(angle_y)],
                  [0, 1, 0],
                  [math.sin(angle_y), 0, math.cos(angle_y)]]

    rotation_z = [[math.cos(angle_z), -math.sin(angle_z), 0],
                  [math.sin(angle_z), math.cos(angle_z), 0],
                  [0, 0, 1]]

    new_points = []
    for point in points:
        rotated_2d = matrix_multiplication(rotation_y, point)
        rotated_2d = matrix_multiplication(rotation_x, rotated_2d)
        rotated_2d = matrix_multiplication(rotation_z, rotated_2d)
        
        new_point = [[rotated_2d[0][0] + pos_x], [rotated_2d[1][0] + pos_y], [rotated_2d[2][0] - pos_z]]
        new_points.append(new_point)
        
        distance = 5
        z = 1 / (distance - new_point[2][0])
        projection_matrix = [[z, 0, 0],
                            [0, z, 0]]
        projected_2d = matrix_multiplication(projection_matrix, new_point)
        
        x = int(projected_2d[0][0] * scale) + cube_position[0]
        y = int(projected_2d[1][0] * scale) + cube_position[1]
        projected_points[index] = [x, y]
        index += 1
 


    zs = [[distToCam(i), i] for i in range(len(mesh.faces))]
    zs.sort(reverse=True)
    faces = [[mesh.faces[zs[i][1]], zs[i][1]] for i in range(len(mesh.faces))]
    
    fi = 0
    for f in faces:
        gfxdraw.filled_polygon(screen, [projected_points[f[0][0]], projected_points[f[0][1]], projected_points[f[0][2]], projected_points[f[0][3]]], (rs[zs[fi][1]], gs[zs[fi][1]], bs[zs[fi][1]]))
        gfxdraw.aapolygon(screen, [projected_points[f[0][0]], projected_points[f[0][1]], projected_points[f[0][2]], projected_points[f[0][3]]], (rs[zs[fi][1]], gs[zs[fi][1]], bs[zs[fi][1]]))
        fi += 1

    angle_x += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * speed * dt
    angle_y += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed * dt
    pos_x += (keys[pygame.K_d] - keys[pygame.K_a]) * movSpeed * dt
    pos_z += (keys[pygame.K_w] - keys[pygame.K_s]) * movSpeed * dt
    
    text = font.render(str(round(fps, 1)), False, black)
    
    screen.blit(text, (0, 0))
    
    pygame.display.update()

pygame.quit()

The matrix multiplication matrix.py:矩阵乘法matrix.py:

def matrix_multiplication(a, b):
    columns_a = len(a[0])
    rows_a = len(a)
    columns_b = len(b[0])
    rows_b = len(b)
    
    result_matrix = [[j for j in range(columns_b)] for i in range(rows_a)]
    if columns_a == rows_b:
        for x in range(rows_a):
            for y in range(columns_b):
                sum = 0
                for k in range(columns_a):
                    sum += a[x][k] * b[k][y]
                result_matrix[x][y] = sum
        return result_matrix
        
    else:
        print("columns of the first matrix must be equal to the rows of the second matrix")
        return None

The mesh data.网格数据。 mesh.py:网格.py:

verts = [
    [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, 4, 6, 2],
    [3, 2, 6, 7],
    [7, 6, 4, 5],
    [5, 1, 3, 7],
    [1, 0, 2, 3],
    [5, 4, 0, 1]
]

WARNING: There might be flashing lights on startup警告:启动时指示灯可能会闪烁

You have to compute the distance of the camera position ( [0, 0, distance] ) to the points in world space ( new_points ), instead of the points in model space ( points ):您必须计算相机 position ( [0, 0, distance] )到世界空间中的点( new_points )的距离,而不是 model 空间中的点( points ):

def distToCam(i):
    a = [0, 0, distance]
    b = [sum(new_points[mesh.faces[i][pi]][j][0] for pi in range(4)) / 4 for j in range(3)]
    return math.dist(a, b)

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

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