pyGame做3d吗?

时间:2011-02-01 17:08:44

标签: python 3d pygame

我似乎无法在任何地方找到这个问题的答案。我意识到你必须使用pyOpenGL或类似的东西做openGL的东西,但我想知道它是否可以做非常基本的3D图形而没有任何其他依赖。

14 个答案:

答案 0 :(得分:16)

不,Pygame是SDL的包装器,它是一个2D api。 Pygame不提供任何3D功能,可能永远不会。

Python的3D库包括Panda3DDirectPython,尽管它们使用起来可能非常复杂,尤其是后者。

答案 1 :(得分:13)

好吧,如果你可以做2d你可以随时做3d。所有的3D都是倾斜的2维表面给人的印象,你正在看深度的东西。真正的问题是它可以做得好,你甚至想要。浏览pyGame文档一段时间后,看起来它只是一个SDL包装器。 SDL不适用于3D编程,因此真正问题的答案是,不,我甚至都不会尝试。

答案 2 :(得分:7)

你可以只用pygame做伪3D游戏(比如" Doom"):

http://code.google.com/p/gh0stenstein/

如果您浏览pygame.org网站,您可能会发现更多" 3d"用python和pygame完成的游戏。

但是,如果你真的想进入3d编程,你应该研究OpenGl,Blender或任何其他真正的3D库。

答案 3 :(得分:3)

Python Soya可以在pygame表面上渲染3d图形。

答案 4 :(得分:1)

如果您想要3D投影功能以及所有这些功能,您将不得不使用3D API,但如果您想要进行基本的3D外观,我建议使用Peter的网站教程:http://www.petercollingridge.co.uk/pygame-3d-graphics-tutorial

答案 5 :(得分:1)

Pygame从来没有打算做3D,但有一种方法可以用任何2D图形库做3d。您只需要以下功能,它可以将3d点转换为2d点,这样您就可以通过在屏幕上绘制线条来制作任何3d形状。

def convert_to_2d(point=[0,0,0]):
    return [point[0]*(point[2]*.3),point[1]*(point[2]*.3)]

这称为伪3d或2.5d。这可以做到,但可能很慢,并且非常难以做到,因此建议您使用适用于3d的库。

答案 6 :(得分:1)

您看到的3D实际上是2D游戏。毕竟,您正在观看屏幕(通常是;))是2D的。将虚拟世界(以3D形式)投影到平面上,然后将其显示在屏幕上。然后我们的大脑将2D图像转换为3D图像(就像对眼睛的图像一样),使其看起来像3D。

因此制作3D游戏相对容易:您只需使用多维矩阵创建一个虚拟世界,然后将其每个环投影到2D平面上即可显示在屏幕上。

this one 是可用于3D程序(使用pygame)的一个教程。

答案 7 :(得分:1)

Pygame 不提供任何用于绘制 3D 形状、网格甚至透视和照明的功能。
如果要使用 Pygame 绘制 3D 场景,则需要使用矢量算法计算顶点并使用多边形将几何体缝合在一起。
然后回答 Pygame rotating cubes around axis 的示例:

这种方法不会给出令人满意的性能,只对学习有价值。 3D 场景是在 GPU 的帮助下生成的。仅使用 CPU 的方法无法实现所需的性能。

在 Python 中使 3D 场景更强大的一种方法是使用基于 OpenGL 的库,如 pygletModernGL

但是,您可以使用 Pygame 窗口来创建 OpenGL Context。您需要在创建显示表面时设置 pygame.OPENGL 标志(请参阅 pygame.display.set_mode):

window = pg.display.set_mode((width, height), pygame.OPENGL | pygame.DOUBLEBUF)

看例子:

import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL.shaders import *
import ctypes
import glm

glsl_vert = """
#version 330 core

layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec4 a_col;

out vec4 v_color;

uniform mat4 u_proj; 
uniform mat4 u_view; 
uniform mat4 u_model; 

void main()
{
    v_color     = a_col;
    gl_Position = u_proj * u_view * u_model * vec4(a_pos.xyz, 1.0);
}
"""

glsl_frag = """
#version 330 core

out vec4 frag_color;
in  vec4 v_color;

void main()
{
    frag_color = v_color;
}
"""

class Cube:
  
    def __init__(self):
        v = [(-1,-1,-1), ( 1,-1,-1), ( 1, 1,-1), (-1, 1,-1), (-1,-1, 1), ( 1,-1, 1), ( 1, 1, 1), (-1, 1, 1)]
        edges = [(0,1), (1,2), (2,3), (3,0), (4,5), (5,6), (6,7), (7,4), (0,4), (1,5), (2,6), (3,7)]
        surfaces = [(0,1,2,3), (5,4,7,6), (4,0,3,7),(1,5,6,2), (4,5,1,0), (3,2,6,7)]
        colors = [(1,0,0), (0,1,0), (0,0,1), (1,1,0), (1,0,1), (1,0.5,0)]
        line_color = [0, 0, 0]

        edge_attributes = []
        for e in edges:
            edge_attributes += v[e[0]]
            edge_attributes += line_color
            edge_attributes += v[e[1]]
            edge_attributes += line_color

        face_attributes = []
        for i, quad in enumerate(surfaces):
            for iv in quad:
                face_attributes += v[iv]
                face_attributes += colors[i]

        self.edge_vbo = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, self.edge_vbo)
        glBufferData(GL_ARRAY_BUFFER, (GLfloat * len(edge_attributes))(*edge_attributes), GL_STATIC_DRAW)
        self.edge_vao = glGenVertexArrays(1)
        glBindVertexArray(self.edge_vao)
        glVertexAttribPointer(0, 3, GL_FLOAT, False, 6*ctypes.sizeof(GLfloat), ctypes.c_void_p(0)) 
        glEnableVertexAttribArray(0) 
        glVertexAttribPointer(1, 3, GL_FLOAT, False, 6*ctypes.sizeof(GLfloat), ctypes.c_void_p(3*ctypes.sizeof(GLfloat))) 
        glEnableVertexAttribArray(1) 

        self.face_vbos = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, self.face_vbos)
        glBufferData(GL_ARRAY_BUFFER, (GLfloat * len(face_attributes))(*face_attributes), GL_STATIC_DRAW)
        self.face_vao = glGenVertexArrays(1)
        glBindVertexArray(self.face_vao)
        glVertexAttribPointer(0, 3, GL_FLOAT, False, 6*ctypes.sizeof(GLfloat), ctypes.c_void_p(0)) 
        glEnableVertexAttribArray(0) 
        glVertexAttribPointer(1, 3, GL_FLOAT, False, 6*ctypes.sizeof(GLfloat), ctypes.c_void_p(3*ctypes.sizeof(GLfloat))) 
        glEnableVertexAttribArray(1) 

    def draw(self):
        glEnable(GL_DEPTH_TEST)

        glLineWidth(5)

        glBindVertexArray(self.edge_vao)
        glDrawArrays(GL_LINES, 0, 12*2)
        glBindVertexArray(0)

        glEnable(GL_POLYGON_OFFSET_FILL)
        glPolygonOffset( 1.0, 1.0 )

        glBindVertexArray(self.face_vao)
        glDrawArrays(GL_QUADS, 0, 6*4)
        glBindVertexArray(0)
        
        glDisable(GL_POLYGON_OFFSET_FILL)

def set_projection(w, h):
    return glm.perspective(glm.radians(45), w / h, 0.1, 50.0)

pygame.init()
window = pygame.display.set_mode((400, 300), pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
clock = pygame.time.Clock()

proj = set_projection(*window.get_size())
view = glm.lookAt(glm.vec3(0, 0, 5), glm.vec3(0, 0, 0), glm.vec3(0, 1, 0))
model = glm.mat4(1)
cube = Cube()
angle_x, angle_y = 0, 0

program = compileProgram( 
    compileShader(glsl_vert, GL_VERTEX_SHADER),
    compileShader(glsl_frag, GL_FRAGMENT_SHADER))
attrib = { a : glGetAttribLocation(program, a) for a in ['a_pos', 'a_col'] }
print(attrib)
uniform = { u : glGetUniformLocation(program, u) for u in ['u_model', 'u_view', 'u_proj'] }
print(uniform)
glUseProgram(program)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == pygame.VIDEORESIZE:
            glViewport(0, 0, event.w, event.h)
            proj = set_projection(event.w, event.h)

    model = glm.mat4(1)
    model = glm.rotate(model, glm.radians(angle_y), glm.vec3(0, 1, 0))
    model = glm.rotate(model, glm.radians(angle_x), glm.vec3(1, 0, 0))
   
    glUniformMatrix4fv(uniform['u_proj'], 1, GL_FALSE, glm.value_ptr(proj))
    glUniformMatrix4fv(uniform['u_view'], 1, GL_FALSE, glm.value_ptr(view))
    glUniformMatrix4fv(uniform['u_model'], 1, GL_FALSE, glm.value_ptr(model))

    angle_x += 1
    angle_y += 0.4

    glClearColor(0.5, 0.5, 0.5, 1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    cube.draw()    
    pygame.display.flip()

pygame.quit()
exit()

答案 8 :(得分:0)

为PyGame制作3D驱动程序很容易。 PyGame有一些3D游戏开发资产。 现在我正在使用PyGame开发Py3D驱动程序。当我结束时,我会告诉你链接下载Py3D。我试图用PyGame制作3D游戏,我只需要为PyGame添加一个小插件。你认为必须使用SDL,PyOpenGL,Op​​enGL,PyQt5,Tkinter是错误的。所有这些都是制作3D游戏的错误。 OpenGL和PyOpenGL或Panda3D很难学习。我对这些驱动程序的所有游戏都非常糟糕。 PyQt5和Tkinter不是制作游戏的驱动程序,但它们已经有了它的插件。不要试图在这些驱动程序上进行任何游戏。我们需要使用模块math.py的所有驱动程序都很难。你可以轻松地为它们制作小插件,我想每个人都可以在1-2周内为PyGame制作驱动程序。

答案 9 :(得分:0)

Pygame只是一个用于更改像素颜色(以及一些其他用于编程游戏的有用内容)的库。您可以通过将图像显示在屏幕上或直接设置像素的颜色来实现此目的。

因此,使用pygame编写2D游戏很容易,因为上述正是您真正需要的。但是3D游戏只是将3D对象“压扁”(渲染)成2D,以便可以在屏幕上显示。因此,要仅使用pygame制作3D游戏,您将自己处理渲染,包括所有必要的复杂矩阵数学。

由于其中涉及巨大的处理能力,这不仅运行缓慢,而且还需要您编写庞大的3D渲染/栅格化引擎。而且由于python被解释,所以速度甚至会更慢。正确的方法是使用(Py)opengl在GPU上运行此过程。

因此,是的,在技术上仅使用pygame可以进行3D,但绝对不建议这样做。我建议您学习Panda3D或一些类似的3D引擎。

答案 10 :(得分:0)

您可以这样:

def convert_2d(x, y, z, horizon):
    d = 1 - (z/horizon)
    return x*d, y*d
def draw_list_of_points(lst):
    '''Assume that lst is a list of 3 dimentionnal points like [(0, 0, 0), (1, 6, 2)...
    Let's take 200 for the horizon, it can give us a pretty clean 3D''' 
    for x, y, z in lst:
        pygame.draw.circle(screen, color, convert_2d(x, y, z, 200), 1)
But it's not very fast. If you want fast try to implement in C++/SDL2 or C.
Pygame is not very good for 3d graphics.

答案 11 :(得分:0)

简单: 只需绘制一堆多边形即可:

import pygame
screen = pygame.display.set_mode((100, 100))
While True:
   screen.fill((0, 0, 0))
   Pos = [(10, 10), (20, 10), (20, 20), (10, 20)]
   # first side (the front) in red
   pygame.draw.polygon(screen, (225, 0, 0), Pos)
   # outline in white
   pygame.draw.lines(screen, (225, 225, 225), Pos)
   # Second side (the back) in blue
   Pos2 = [(Pos[0[0]] + 2.5, Pos[0[1]] + 2.5), (Pos2[0[0]] + 5, Pos2[0[1]]), (Pos2[1[0]], Pos2[1[1]] + 5), (Pos2[0[0]], Pos2[0[1]] + 5)]
   pygame.draw.polygon(screen, (0, 0, 225), Pos2)
   pygame.draw.lines(screen, (225, 225, 225), Pos2)
   # Third side (the left but just 2 lines(not really)) in green 
   Pos3 = [Pos[0], Pos2[0], Pos2[3], Pos[3]]
   pygame.draw.polygon(screen, (0, 225, 0), Pos3)
   pygame.draw.lines(screen, (225, 225, 225), Pos3)
   # Fourth side (the right) in purple
   Pos4 = [Pos[1], Pos2[1], Pos2[2], Pos[2]]
   pygame.draw.polygon(screen, (225, 0, 225), Pos4)
   pygame.draw.lines(screen, (225, 225, 225), Pos4)
   pygame.display.flip()

&有一个简单的多维数据集,我将很快提供完整代码的链接,以便能够旋转多维数据集并调整其大小

这应该为您提供与使用OpenGL等效的功能

答案 12 :(得分:0)

如果您想在制作游戏时坚持使用 Python 式语言,Godot 是一个很好的选择,它同时提供 2D 和 3D 支持、大型社区和大量教程。它的自定义脚本语言 (gdscript) 有一些细微的差异,但总体而言基本相同。它还支持 c# 和 c++,并且在游戏开发方面具有更多功能。

答案 13 :(得分:0)

它不支持,但结合 PyOpenGL 可以利用两者的力量,这里有一个完整的例子

    import pygame
    from pygame.locals import *

    from OpenGL.GL import *
    from OpenGL.GLU import *

    import random

    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))
edges = ((0,1),(0,3),(0,4),(2,1),(2,3),(2,7),(6,3),(6,4),(6,7),(5,1),(5,4),(5,7))
    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))
    colors = ((1,0,0),(0,1,0),(0,0,1),(0,1,0),(1,1,1),(0,1,1),(1,0,0),(0,1,0),(0,0,1),(1,0,0),(1,1,1),(0,1,1),)

   
    def set_vertices(max_distance, min_distance = -20):
        x_value_change = random.randrange(-10,10)
        y_value_change = random.randrange(-10,10)
        z_value_change = random.randrange(-1*max_distance,min_distance)
        new_vertices = []
        for vert in vertices:
            new_vert = []
            new_x = vert[0] + x_value_change
            new_y = vert[1] + y_value_change
            new_z = vert[2] + z_value_change
            new_vert.append(new_x)
            new_vert.append(new_y)
            new_vert.append(new_z)
            new_vertices.append(new_vert)
        return new_vertices
            
        


    def Cube(vertices):
        glBegin(GL_QUADS)
        for surface in surfaces:
            x = 0

            for vertex in surface:
                x+=1
                glColor3fv(colors[x])
                glVertex3fv(vertices[vertex])
        glEnd()
        glBegin(GL_LINES)
        for edge in edges:
            for vertex in edge:
                glVertex3fv(vertices[vertex])
        glEnd()

    def main():
        pygame.init()
        display = (800,600)
        pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
        max_distance = 100
        gluPerspective(45, (display[0]/display[1]), 0.1, max_distance)
        glTranslatef(random.randrange(-5,5),random.randrange(-5,5), -40)
        #object_passed = False
        x_move = 0
        y_move = 0
        cube_dict = {}

        for x in range(50):
            cube_dict[x] =set_vertices(max_distance)

        #glRotatef(25, 2, 1, 0)

        
        x = glGetDoublev(GL_MODELVIEW_MATRIX)
        camera_x = x[3][0]
        camera_y = x[3][1]
        camera_z = x[3][2]
        button_down = False
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
                if event.type == pygame.MOUSEMOTION:
                    if button_down == True:
                        print(pygame.mouse.get_pressed())
                        glRotatef(event.rel[1], 1, 0, 0)
                        glRotatef(event.rel[0], 0, 1, 0)
            
            for event in pygame.mouse.get_pressed():
                # print(pygame.mouse.get_pressed())
                if pygame.mouse.get_pressed()[0] == 1:
                    button_down = True
                elif pygame.mouse.get_pressed()[0] == 0:
                    button_down = False

           

            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)


            for each_cube in cube_dict:
                Cube(cube_dict[each_cube])

            pygame.display.flip()
            pygame.time.wait(10)

    main()
    pygame.quit()
    quit()

enter image description here