gpt4 book ai didi

python - Pygame 绕轴旋转立方体

转载 作者:行者123 更新时间:2023-12-01 07:50:00 26 4
gpt4 key购买 nike

我一直在研究旋转立方体的例子 here 。我生成了 2 个应该绕 Y 轴旋转的立方体。但是,它似乎没有按预期工作,我无法弄清楚它的问题是什么。

这是一个有效的代码示例:

import sys
import math
import pygame

from pygame.math import Vector3
from enum import Enum


class Color(Enum):
BLACK = (0, 0, 0)
SILVER = (192,192,192)


class Cube():

def __init__(self, vectors, screen_width, screen_height, initial_angle=25):
self._vectors = vectors
self._angle = initial_angle
self._screen_width = screen_width
self._screen_height = screen_height

# Define the vectors that compose each of the 6 faces
self._faces = [(0,1,2,3),
(1,5,6,2),
(5,4,7,6),
(4,0,3,7),
(0,4,5,1),
(3,2,6,7)]

self._setup_initial_positions(initial_angle)

def _setup_initial_positions(self, angle):
tmp = []
for vector in self._vectors:
rotated_vector = vector.rotate_x(angle).rotate_y(angle)#.rotateZ(self.angle)
tmp.append(rotated_vector)

self._vectors = tmp

def transform_vectors(self, new_angle):
# It will hold transformed vectors.
transformed_vectors = []

for vector in self._vectors:
# Rotate the point around X axis, then around Y axis, and finally around Z axis.
mod_vector = vector.rotate_y(new_angle)
# Transform the point from 3D to 2D
mod_vector = self._project(mod_vector, self._screen_width, self._screen_height, 256, 4)
# Put the point in the list of transformed vectors
transformed_vectors.append(mod_vector)

return transformed_vectors

def _project(self, vector, win_width, win_height, fov, viewer_distance):
factor = fov / (viewer_distance + vector.z)
x = vector.x * factor + win_width / 2
y = -vector.y * factor + win_height / 2
return Vector3(x, y, vector.z)

def calculate_average_z(self, vectors):
avg_z = []
for i, face in enumerate(self._faces):
# for each point of a face calculate the average z value
z = (vectors[face[0]].z +
vectors[face[1]].z +
vectors[face[2]].z +
vectors[face[3]].z) / 4.0
avg_z.append([i, z])

return avg_z

def get_face(self, index):
return self._faces[index]

def create_polygon(self, face, transformed_vectors):
return [(transformed_vectors[face[0]].x, transformed_vectors[face[0]].y),
(transformed_vectors[face[1]].x, transformed_vectors[face[1]].y),
(transformed_vectors[face[2]].x, transformed_vectors[face[2]].y),
(transformed_vectors[face[3]].x, transformed_vectors[face[3]].y),
(transformed_vectors[face[0]].x, transformed_vectors[face[0]].y)]


class Simulation:
def __init__(self, win_width=640, win_height=480):
pygame.init()

self.screen = pygame.display.set_mode((win_width, win_height))

self.clock = pygame.time.Clock()

cube = Cube([
Vector3(0, 0.5, -0.5),
Vector3(0.5, 0.5, -0.5),
Vector3(0.5, 0, -0.5),
Vector3(0, 0, -0.5),
Vector3(0, 0.5, 0),
Vector3(0.5, 0.5, 0),
Vector3(0.5, 0, 0),
Vector3(0, 0, 0)
], win_width, win_height)

cube2 = Cube([
Vector3(0.5, 0.5, -0.5),
Vector3(1, 0.5, -0.5),
Vector3(1, 0, -0.5),
Vector3(0.5, 0, -0.5),
Vector3(0.5, 0.5, 0),
Vector3(1, 0.5, 0),
Vector3(1, 0, 0),
Vector3(0.5, 0, 0)
], win_width, win_height)

self._angle = 30

self._cubes = [cube, cube2]

def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

self.clock.tick(50)
self.screen.fill(Color.BLACK.value)

for cube in self._cubes:
transformed_vectors = cube.transform_vectors(self._angle)
avg_z = cube.calculate_average_z(transformed_vectors)

# Draw the faces using the Painter's algorithm:
# Distant faces are drawn before the closer ones.
for avg_z in sorted(avg_z, key=lambda x: x[1], reverse=True):
face_index = avg_z[0]
face = cube._faces[face_index]
pointlist = cube.create_polygon(face, transformed_vectors)

pygame.draw.polygon(self.screen, Color.SILVER.value,pointlist)
pygame.draw.polygon(self.screen, Color.BLACK.value, pointlist, 3)
# break

self._angle += 1

pygame.display.flip()

if __name__ == "__main__":
Simulation().run()

在此示例中,两个立方体都应绕 Y 轴旋转。对于 future ,我希望有一个解决方案,以便它们可以绕任何轴旋转。

最佳答案

仅按深度对每个立方体的面进行排序是不够的。您必须按深度对整个场景的所有对象的面进行排序。

创建一个元组列表,其中包含面部的投影(变换)点和平均深度(z 值):

polygons = []
for cube in self._cubes:
transformed_vectors = cube.transform_vectors(self._angle)
avg_z = cube.calculate_average_z(transformed_vectors)
for z in avg_z:
face_index = z[0]
face = cube._faces[face_index]
pointlist = cube.create_polygon(face, transformed_vectors)
polygons.append((pointlist, z[1]))

按(反向)排序顺序绘制所有对象的面:

for poly in sorted(polygons, key=lambda x: x[1], reverse=True):
pygame.draw.polygon(self.screen, Color.SILVER.value,poly[0])
pygame.draw.polygon(self.screen, Color.BLACK.value, poly[0], 3)

<小时/>

最小示例: repl.it/@Rabbid76/PyGame-3D

import math
import pygame

def project(vector, w, h, fov, distance):
factor = math.atan(fov / 2 * math.pi / 180) / (distance + vector.z)
x = vector.x * factor * w + w / 2
y = -vector.y * factor * w + h / 2
return pygame.math.Vector3(x, y, vector.z)

def rotate_vertices(vertices, angle, axis):
return [v.rotate(angle, axis) for v in vertices]
def scale_vertices(vertices, s):
return [pygame.math.Vector3(v[0]*s[0], v[1]*s[1], v[2]*s[2]) for v in vertices]
def translate_vertices(vertices, t):
return [v + pygame.math.Vector3(t) for v in vertices]
def project_vertices(vertices, w, h, fov, distance):
return [project(v, w, h, fov, distance) for v in vertices]

class Mesh():

def __init__(self, vertices, faces):
self.__vertices = [pygame.math.Vector3(v) for v in vertices]
self.__faces = faces

def rotate(self, angle, axis):
self.__vertices = rotate_vertices(self.__vertices, angle, axis)
def scale(self, s):
self.__vertices = scale_vertices(self.__vertices, s)
def translate(self, t):
self.__vertices = translate_vertices(self.__vertices, t)

def calculate_average_z(self, vertices):
return [(i, sum([vertices[j].z for j in f]) / len(f)) for i, f in enumerate(self.__faces)]

def get_face(self, index):
return self.__faces[index]
def get_vertices(self):
return self.__vertices

def create_polygon(self, face, vertices):
return [(vertices[i].x, vertices[i].y) for i in [*face, face[0]]]

class Scene:
def __init__(self, mehses, fov, distance):
self.meshes = mehses
self.fov = fov
self.distance = distance
self.euler_angles = [0, 0, 0]

def transform_vertices(self, vertices, width, height):
transformed_vertices = vertices
axis_list = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
for angle, axis in reversed(list(zip(list(self.euler_angles), axis_list))):
transformed_vertices = rotate_vertices(transformed_vertices, angle, axis)
transformed_vertices = project_vertices(transformed_vertices, width, height, self.fov, self.distance)
return transformed_vertices

def draw(self, surface):

polygons = []
for mesh in self.meshes:
transformed_vertices = self.transform_vertices(mesh.get_vertices(), *surface.get_size())
avg_z = mesh.calculate_average_z(transformed_vertices)
for z in avg_z:
#for z in sorted(avg_z, key=lambda x: x[1], reverse=True):
pointlist = mesh.create_polygon(mesh.get_face(z[0]), transformed_vertices)
polygons.append((pointlist, z[1]))
#pygame.draw.polygon(surface, (128, 128, 192), pointlist)
#pygame.draw.polygon(surface, (0, 0, 0), pointlist, 3)

for poly in sorted(polygons, key=lambda x: x[1], reverse=True):
pygame.draw.polygon(surface, (128, 128, 192), poly[0])
pygame.draw.polygon(surface, (0, 0, 0), poly[0], 3)


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

cube_origins = [(-1, -1, 0), (0, -1, 0), (1, -1, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0), (-1, 1, 0), (-1, 0, 0)]
meshes = []
for origin in cube_origins:
cube = Mesh(vertices, faces)
cube.scale((0.5, 0.5, 0.5))
cube.translate(origin)
meshes.append(cube)

scene = Scene(meshes, 90, 5)

pygame.init()
window = pygame.display.set_mode((400, 300))
clock = pygame.time.Clock()

run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False

window.fill((255, 255, 255))
scene.draw(window)
scene.euler_angles[1] += 1
pygame.display.flip()

pygame.quit()

关于python - Pygame 绕轴旋转立方体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56285017/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com