首页 > 解决方案 > 如何在 pyglet 中制作 3D?

问题描述

我试图使用 OpenGL、Python 和 pyglet 创建一个 3D 空间中的平面三角形,我在互联网上看到了一些教程,在 YouTube 上看到了一些视频,最后我把这段代码写在那里,问题是它没有按我的预期工作,我想如果我尝试旋转,我会看到三角形变平,当我走开时​​,三角形不必缩小?

import pyglet
from pyglet.gl import *

config = Config(sample_buffers=1, samples=8)
tela = pyglet.window.Window(height=500, width=500, config=config)

glViewport(0,0,500,500)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(35,1,0.1,1000)
glMatrixMode(GL_MODELVIEW)

@tela.event
def on_draw():
    glBegin(GL_POLYGON)
    glVertex3f(10,10,0)
    glVertex3f(100,10,0)
    glVertex3f(50,100,0)
    glEnd()
    glFlush()

@tela.event
def on_key_press(s,m):
    tela.clear()
    if s == pyglet.window.key.W:
        glTranslatef(0,0,1)
    if s == pyglet.window.key.S:
        glTranslatef(0,0,-1)
    if s == pyglet.window.key.A:
        glRotatef(1,0,1,0)
    if s == pyglet.window.key.D:
        glRotatef(-1,0,1,0)

pyglet.app.run()

当我运行代码时,会出现:

在此处输入图像描述

当我尝试旋转场景时,它会发生:

在此处输入图像描述

有谁知道我要去哪里错了?

标签: pythonpython-3.xopengl3dpyglet

解决方案


视口的初始化和投影和模型视图矩阵的刺痛是无用的

glViewport(0,0,500,500)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(35,1,0.1,1000)
glMatrixMode(GL_MODELVIEW) 

因为在启动应用程序时设置了视口和正交投影。

请参阅pyglet - OpenGL 接口

[...] pyglet 自动在每个窗口上设置视口和正交投影。

如果你会使用透视投影

gluPerspective(35,1,0.1,1000)

然后三角形会消失,因为它会被透视投影的近平面剪裁(0.1)。


为了解决这个问题,将透视投影的设置放到draw事件中:

@tela.event
def on_draw():

    tela.clear()

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(90, 1, 0.1, 100)

我想如果我尝试旋转,我会看到三角形变平,当我走开时​​,三角形不必缩小吗?

在视图空间中,x 轴从左到右,y 轴从下到上。要在 XY 平面中旋转,您必须绕 Z 轴旋转。

定义三角形的位置和 Y 角。Z 坐标必须为负,并且到对象的距离必须在近平面和远平面之间。如果 near 是 0.1 而 far 是 100,那么:

0.1 <= -z <= 100

例如

pos = [0, 0, -20]
rot_y = 0

操作事件中的位置和角度:

@tela.event
def on_key_press(s,m):

    global pos_z, rot_y

    if s == pyglet.window.key.W:
        pos[2] -= 1
    if s == pyglet.window.key.S:
        pos[2] += 1
    if s == pyglet.window.key.A:
        rot_y += 5
    if s == pyglet.window.key.D:
        rot_y -= 5

将平移和旋转应用于模型视图矩阵堆栈draw

@tela.event
def on_draw():

    global pos_z, rot_y

    # [...]

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    glTranslatef(*pos)
    glRotatef(rot_y, 0, 1, 0)

绘制一个围绕 (0, 0, 0) 排列的对象。请注意,对象的位置由透视投影设置,pos并且在透视投影中,原点 (0, 0, 0) 位于窗口的中心:

glBegin(GL_POLYGON)
glVertex3f(-5,-5,0)
glVertex3f(5,-5,0)
glVertex3f(0,5,0)
glEnd()

应用了建议更改的完整代码:

import pyglet
from pyglet.gl import *

pos = [0, 0, -20]
rot_y = 0

config = Config(sample_buffers=1, samples=8)
tela = pyglet.window.Window(height=500, width=500, config=config)

@tela.event
def on_draw():

    global pos_z, rot_y

    tela.clear()

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(90, 1, 0.1, 100)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    glTranslatef(*pos)
    glRotatef(rot_y, 0, 1, 0)

    glBegin(GL_POLYGON)
    glVertex3f(-5,-5,0)
    glVertex3f(5,-5,0)
    glVertex3f(0,5,0)
    glEnd()

    glFlush()

@tela.event
def on_key_press(s,m):

    global pos_z, rot_y

    if s == pyglet.window.key.W:
        pos[2] -= 1
    if s == pyglet.window.key.S:
        pos[2] += 1
    if s == pyglet.window.key.A:
        rot_y += 5
    if s == pyglet.window.key.D:
        rot_y -= 5

pyglet.app.run()

推荐阅读