opengl - 使用 pyglet 滚动窗口的最佳方式

标签 opengl python-2.7 pyglet

我正在努力创建一个有向图,但它最终比我的窗口大,所以我不想不断地制作一个更大的窗口,而是希望允许滚动。稍后我还将允许用户旋转图形,因为它是 3D 的。

那么,我如何在 pyglet 中滚动?

我发现了这个:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(ClipBox.x1,ClipBox.x2,ClipBox.y1,ClipBox.y2,ClipBox.z1,ClipBox.z2);
glMatrixMode(GL_MODELVIEW);

但我不确定是否有更好的选择。

通过查看 http://www.pyglet.org/doc/programming_guide/mouse_events.html我可以看到我需要使用什么事件,例如鼠标拖动和滚轮,我只需要给用户一个印象,即 View 正在按照他们的预期移动。

最佳答案

您可以变换模型矩阵或投影矩阵来执行此操作。

会有更好的方法,但据我所知,移动几何体的最简单方法是在绘制之前使用 glTranslatef、glRotatef 和 glScalef。

在这个例子中,Camera类只修改GL_PROJECTION来设置 View 模式,然后在绘制几何图形时修改GL_MODELVIEW矩阵来移动相机:

import pyglet
from pyglet.window import key
from pyglet.gl import *

def opengl_init():
    """ Initial OpenGL configuration.
    """
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glDepthFunc(GL_LEQUAL)

def playground():
    """ Draw something here, like a white X.
    """
    glColor4f(1, 1, 1, 1)
    glBegin(GL_LINES)
    glVertex3f(0, 0, 0)
    glVertex3f(640, 480, 0)

    glVertex3f(0, 480, 0)
    glVertex3f(640, 0, 0)
    glEnd()

class camera(object):
    """ A camera.
    """
    mode = 1
    x, y, z = 0, 0, 512
    rx, ry, rz = 30, -45, 0
    w, h = 640, 480
    far = 8192
    fov = 60

    def view(self, width, height):
        """ Adjust window size.
        """
        self.w, self.h = width, height
        glViewport(0, 0, width, height)
        print "Viewport " + str(width) + "x" + str(height)
        if self.mode == 2:
            self.isometric()
        elif self.mode == 3:
            self.perspective()
        else:
            self.default()

    def default(self):
        """ Default pyglet projection.
        """
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(0, self.w, 0, self.h, -1, 1)
        glMatrixMode(GL_MODELVIEW)

    def isometric(self):
        """ Isometric projection.
        """
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(-self.w/2., self.w/2., -self.h/2., self.h/2., 0, self.far)
        glMatrixMode(GL_MODELVIEW)

    def perspective(self):
        """ Perspective projection.
        """
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(self.fov, float(self.w)/self.h, 0.1, self.far)
        glMatrixMode(GL_MODELVIEW)

    def key(self, symbol, modifiers):
        """ Key pressed event handler.
        """
        if symbol == key.F1:
            self.mode = 1
            self.default()
            print "Projection: Pyglet default"
        elif symbol == key.F2:
            print "Projection: 3D Isometric"
            self.mode = 2
            self.isometric()
        elif symbol == key.F3:
            print "Projection: 3D Perspective"
            self.mode = 3
            self.perspective()
        elif self.mode == 3 and symbol == key.NUM_SUBTRACT:
            self.fov -= 1
            self.perspective()
        elif self.mode == 3 and symbol == key.NUM_ADD:
            self.fov += 1
            self.perspective()
        else: print "KEY " + key.symbol_string(symbol)

    def drag(self, x, y, dx, dy, button, modifiers):
        """ Mouse drag event handler.
        """
        if button == 1:
            self.x -= dx*2
            self.y -= dy*2
        elif button == 2:
            self.x -= dx*2
            self.z -= dy*2
        elif button == 4:
            self.ry += dx/4.
            self.rx -= dy/4.

    def apply(self):
        """ Apply camera transformation.
        """
        glLoadIdentity()
        if self.mode == 1: return
        glTranslatef(-self.x, -self.y, -self.z)
        glRotatef(self.rx, 1, 0, 0)
        glRotatef(self.ry, 0, 1, 0)
        glRotatef(self.rz, 0, 0, 1)


def x_array(list):
    """ Converts a list to GLFloat list.
    """
    return (GLfloat * len(list))(*list)

def axis(d=200):
    """ Define vertices and colors for 3 planes
    """
    vertices , colors = [], []   
    #XZ RED 
    vertices.extend([-d, 0, -d, d, 0, -d, d, 0, d, -d, 0, d])
    for i in range (0, 4):
        colors.extend([1, 0, 0, 0.5])
    #YZ GREEN 
    vertices.extend([0, -d, -d, 0, -d, d, 0, d, d, 0, d, -d])
    for i in range (0, 4):
        colors.extend([0, 1, 0, 0.5])
    #XY BLUE 
    vertices.extend([-d, -d, 0, d, -d, 0, d, d, 0, -d, d, 0])
    for i in range (0, 4):
        colors.extend([0, 0, 1, 0.5])
    return x_array(vertices), x_array(colors)

AXIS_VERTICES, AXIS_COLORS = axis()

def draw_vertex_array(vertices, colors, mode=GL_LINES):
    """ Draw a vertex array.
    """
    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_COLOR_ARRAY)
    glColorPointer(4, GL_FLOAT, 0, colors)
    glVertexPointer(3, GL_FLOAT, 0, vertices)
    glDrawArrays(GL_QUADS, 0, len(vertices)/3)
    glDisableClientState(GL_VERTEX_ARRAY)
    glDisableClientState(GL_COLOR_ARRAY)

def draw_axis():
    """ Draw the 3 planes
    """
    glEnable(GL_DEPTH_TEST)
    draw_vertex_array(AXIS_VERTICES, AXIS_COLORS, GL_QUADS)
    glDisable(GL_DEPTH_TEST)



class CameraWindow(pyglet.window.Window):
    def __init__(self):
        super(CameraWindow, self).__init__(resizable=True)
        opengl_init()
        self.cam = camera()
        self.on_resize = self.cam.view
        self.on_key_press = self.cam.key
        self.on_mouse_drag = self.cam.drag

    def on_draw(self):
        self.clear()
        self.cam.apply()
        draw_axis()
        playground()


if __name__ == '__main__':
    print "OpenGL Projections"
    print "---------------------------------"
    print "Projection matrix -> F1, F2, F3"
    print "Camera -> Drag LMB, CMB, RMB"
    print ""
    window = CameraWindow()
    pyglet.app.run()

关于opengl - 使用 pyglet 滚动窗口的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16969094/

相关文章:

python - 使用两个或多个列表进行聚类

audio - 播放文件时如何用pyglet停止音频?

c++ - 失去焦点时全屏 GLFW 窗口消失

c++ - 如何使这个 Open GL 程序在不终止的情况下旋转

c++ - 从 gl_triangles 存储矩阵

google-app-engine - 获取用户对象的应用引擎端点方法

shell - 逐行读取 python 的 shell 输出

python-2.7 - 在 pyglet 中保存图像或动画

python - Pyglet图像渲染

c++ - 第三人称相机翻转循环