Правильно, поэтому у меня было быстрое воспроизведение на этом уроке по PyGame + OpenGL: https://stackabuse.com/advanced-opengl-in-python-with-pygame-and-pyopengl/
Этот код работает не очень хорошо, но он конвертирует спрайт-лист в воксели и выводит их в окно PyGame. Это действительно очень медленно 1009 *. По крайней мере для меня, я предполагаю, что это вообще не использует аппаратное 3D. Но она позволяет визуализировать модель под любым углом.
Большая проблема в том, что она составляет 32 * 32 * 19 = 19456 вокселей (минус прозрачные). Оптимизация кода таким образом, чтобы соседние воксели одного и того же цвета были объединены в один прямоугольный angular воксель, очень помогли бы.
В любом случае, возможно, это подтолкнет вас к тому, чтобы ваше собственное решение заработало.
import pygame
import random
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 800
DISPLAY_SURFACE = DOUBLEBUF|OPENGL
# A Unit Cube from (0,0,0) -> (1,1,1)
cube_vertices = ( (1,1,1),
(1,1,0),
(1,0,0),
(1,0,1),
(0,1,1),
(0,1,0),
(0,0,0),
(0,0,1) )
# The Surfaces making up each face-square
cube_surfaces = ( (0,1,2,3),
(3,2,7,6),
(6,7,5,4),
(4,5,1,0),
(1,5,7,2),
(4,0,3,6) )
### Class to hold a cube's worth of verticies
class Cube():
def __init__( self, xmove, ymove, zmove, colour ):
global cube_vertices
self.colour = colour
self.vertices = []
for vert in cube_vertices:
new_x = vert[0] + xmove
new_y = vert[1] + ymove
new_z = vert[2] + zmove
self.vertices.append( [new_x, new_y, new_z] )
def drawCube( self ):
""" Call the openGL function to render the cube """
global cube_surfaces
glBegin(GL_QUADS)
for surface in cube_surfaces:
glColor3fv( self.colour )
for vertex in surface:
glVertex3fv( self.vertices[ vertex ])
glEnd()
### Class to convert a 2D sprite sheet into a (huge) set of
### voxels-per-pixels
class SpriteSheet3D():
def __init__( self, sheet_filename, sheet_count, sprite_width, sprite_height ):
self.cube_list = []
self.image = pygame.image.load( sheet_filename ).convert_alpha()
# TODO: sanity check sprite image matches supplied dimensions
# Iterate through each sheet's pixels creating cubes/voxels
# TODO: optimise voxels to combine pixels of the same colour into a single, bigger prism
for z in range( 0, sheet_count ):
for y in range( 0, sprite_height ):
for x in range( 0, sprite_width ):
offset_x = x + ( z * sprite_width )
pixel_colour = self.image.get_at( ( offset_x, y ) )
# Only create opaque pixels (Pixels are RGBA)
if ( pixel_colour[3] > 128 ): # TODO: handle translucent pixels
self.createVoxel( x, y, z, pixel_colour )
def createVoxel( self, x, y, z, pixel_colour ):
""" Create a 3D Unit-Cube at (x,y,z) """
# Pygame maps colours 0-255 for RGBA
# OpenGL maps colour 0-1 for RGB
gl_colour = ( pixel_colour[0]/255, pixel_colour[1]/255, pixel_colour[2]/255 )
self.cube_list.append( Cube( x, y, z, gl_colour ) )
def drawCubes( self ):
""" Paint all the cubes """
for cube in self.cube_list:
cube.drawCube()
### Main
pygame.init()
pygame.display.set_mode( ( DISPLAY_WIDTH, DISPLAY_HEIGHT ), DISPLAY_SURFACE )
glEnable( GL_DEPTH_TEST )
gluPerspective( 45, DISPLAY_WIDTH/DISPLAY_HEIGHT, 0.1, 200.0 )
glTranslatef( -16, -16, -150 ) # move camera here
sprite_3d = SpriteSheet3D( 'sprite_stack.png', 19, 32, 32 )
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glRotatef( 3.6, 0,1,1 ) # rotate 3.6 degrees about Y and Z-axiz
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT )
sprite_3d.drawCubes()
pygame.display.flip()
pygame.time.wait(1)
pygame.quit()
quit()