Python 如何在2D中正确平移和缩放?

Python 如何在2D中正确平移和缩放?,python,opengl,graphics,python-3.x,pyglet,Python,Opengl,Graphics,Python 3.x,Pyglet,我只想通过pyglet在OpenGL中创建一个真正简单的二维平移和缩放功能。正如您所看到的,在第一次跳转之后,缩放效果非常好:(然后,拖动(平移)也起作用,但它也会跳转(它跳转了一个相当大的镜头) 以下是我的简化代码和一段视频(),显示了它的行为: import pyglet from pyglet.gl import * # Zooming constants ZOOM_IN_FACTOR = 1.2 ZOOM_OUT_FACTOR = 1/ZOOM_IN_FACTOR class A

我只想通过pyglet在OpenGL中创建一个真正简单的二维平移和缩放功能。正如您所看到的,在第一次跳转之后,缩放效果非常好:(然后,拖动(平移)也起作用,但它也会跳转(它跳转了一个相当大的镜头)

以下是我的简化代码和一段视频(),显示了它的行为:

import pyglet
from pyglet.gl import *

# Zooming constants
ZOOM_IN_FACTOR = 1.2
ZOOM_OUT_FACTOR = 1/ZOOM_IN_FACTOR



class App(pyglet.window.Window):

    def __init__(self, width, height, *args, **kwargs):
        # Create GL configuration
        conf = Config(  sample_buffers=1,
                        samples=4,
                        depth_size=16,
                        double_buffer=True )
        # Initialize parent
        super().__init__( width, height, config=conf, *args, **kwargs )

        # Create Group
        self.group = group = pyglet.graphics.Group()
        # Create Batch
        self.batch = batch = pyglet.graphics.Batch()

        # Create QUAD for testing and add it to batch
        batch.add(
            4, GL_QUADS, group,

            ('v2i', ( -50, -50,
                       50, -50,
                       50,  50,
                      -50,  50 )),

            ('c3B', ( 255,   0,   0,
                      255, 255,   0,
                        0, 255,   0,
                        0,   0, 255 ))
        )

        # Initialize OpenGL
        self.init_gl()

        # Initialize camera values
        self.camera_x = 0
        self.camera_y = 0
        self.camera_zoom = 1

    def init_gl(self):
        # Set clear color
        glClearColor(0/255, 0/255, 0/255, 0/255)

        # Set antialiasing
        glEnable( GL_LINE_SMOOTH )
        glEnable( GL_POLYGON_SMOOTH )
        glHint( GL_LINE_SMOOTH_HINT, GL_NICEST )

        # Set alpha blending
        glEnable( GL_BLEND )
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )

        # Set viewport
        glViewport( 0, 0, self.width, self.height )

        # Initialize Projection matrix
        glMatrixMode( GL_PROJECTION )
        glLoadIdentity()

        # Set orthographic projection matrix
        glOrtho( 0, self.width, 0, self.height, 1, -1 )

        # Initialize Modelview matrix
        glMatrixMode( GL_MODELVIEW )
        glLoadIdentity()

        # Save the default modelview matrix
        glPushMatrix()

    def on_resize(self, width, height):
        # Initialize OpenGL for new dimensions
        self.width  = width
        self.height = height
        self.init_gl()

    def camera_matrix(transformations):

        # Create camera setter function
        def set_camera(self):
            # Take saved matrix off the stack and reset it
            glMatrixMode( GL_MODELVIEW )
            glPopMatrix()
            glLoadIdentity()
            # Call wrapped function
            transformations(self)
            # Save default matrix again with camera translation
            glPushMatrix()

        # Return wrapper function
        return set_camera

    @camera_matrix
    def move_camera(self):
        # Move to camera position
        glTranslatef( self.camera_x, self.camera_y, 0 )
        # Scale camera
        glScalef( self.camera_zoom, self.camera_zoom, 1 )

    @camera_matrix
    def zoom_camera(self):
        # Move to camera position
        glTranslatef( self.camera_x, self.camera_y, 0 )
        # Scale camera
        glScalef( self.camera_zoom, self.camera_zoom, 1 )
        # Move back from camera position
        glTranslatef( -self.camera_x, -self.camera_y, 0 )

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        # Move camera
        self.camera_x += dx
        self.camera_y += dy
        self.move_camera()

    def on_mouse_scroll(self, x, y, dx, dy):
        # Get scale factor
        f = ZOOM_IN_FACTOR if dy < 0 else ZOOM_OUT_FACTOR if dy > 0 else 1
        # If zoom_level is in the proper range
        if .2 < self.camera_zoom*f < 5:
            # Zoom camera
            self.camera_x = x
            self.camera_y = y
            self.camera_zoom *= f
            self.zoom_camera()

    def on_draw(self):
        # Clear window with ClearColor
        glClear( GL_COLOR_BUFFER_BIT )

        # Pop default matrix onto current matrix
        glMatrixMode( GL_MODELVIEW )
        glPopMatrix()

        # Save default matrix again
        glPushMatrix()

        # Move to center of the screen
        glTranslatef( self.width/2, self.height/2, 0 )

        # Draw objects
        self.batch.draw()

    def run(self):
        pyglet.app.run()

# Create instance of app and run it
App(500, 500).run()
导入pyglet 从pyglet.gl导入* #缩放常数 放大系数=1.2 缩小系数=1/放大系数 类应用程序(pyglet.window.window): 定义初始值(自身、宽度、高度、*args、**kwargs): #创建总账配置 conf=Config(示例缓冲区=1, 样本=4, 深度×尺寸=16, 双缓冲区=真) #初始化父级 super() #创建组 self.group=group=pyglet.graphics.group() #创建批处理 self.batch=batch=pyglet.graphics.batch() #创建用于测试的四元组并将其添加到批处理 batch.add( 4,德国四大学组, (‘v2i’,(-50,-50, 50, -50, 50, 50, -50, 50 )), ('c3B',(255,0,0, 255, 255, 0, 0, 255, 0, 0, 0, 255 )) ) #初始化OpenGL self.init_gl() #初始化相机值 self.camera_x=0 self.camera_y=0 self.camera_zoom=1 def初始gl(自身): #设置清晰的颜色 glClearColor(0/255、0/255、0/255、0/255) #设置抗锯齿 glEnable(GL_线_光滑) glEnable(GL_多边形_平滑) glHint(GL\u线\u平滑\u提示,GL\u最好) #设置alpha混合 glEnable(GL_混合) glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去GL_SRC_ALPHA) #设置视口 glViewport(0,0,self.width,self.height) #初始化投影矩阵 glMatrixMode(GL_投影) glLoadIdentity() #集合正交投影矩阵 格洛托(0,自宽,0,自高,1,-1) #初始化模型视图矩阵 glMatrixMode(GLU模型视图) glLoadIdentity() #保存默认的modelview矩阵 glPushMatrix() def on_调整大小(自身、宽度、高度): #为新尺寸初始化OpenGL self.width=宽度 自我高度=高度 self.init_gl() def摄像机矩阵(变换): #创建相机设置器功能 def设置_摄像头(自身): #将保存的矩阵从堆栈中取出并重置它 glMatrixMode(GLU模型视图) GLPOP矩阵() glLoadIdentity() #调用包装函数 转换(自我) #使用摄影机平移再次保存默认矩阵 glPushMatrix() #返回包装函数 回程照相机 @摄像机矩阵 def移动摄像头(自身): #移动到摄像机位置 glTranslatef(self.camera\u x,self.camera\u y,0) #比例尺照相机 glScalef(self.camera\u缩放,self.camera\u缩放,1) @摄像机矩阵 def zoom_摄像头(自身): #移动到摄像机位置 glTranslatef(self.camera\u x,self.camera\u y,0) #比例尺照相机 glScalef(self.camera\u缩放,self.camera\u缩放,1) #从摄像机位置向后移动 glTranslatef(-self.camera_x,-self.camera_y,0) 鼠标拖动时的def(自身、x、y、dx、dy、按钮、修改器): #移动摄像机 self.camera_x+=dx self.camera_y+=dy self.move_摄像头() 鼠标上的def滚动(自身、x、y、dx、dy): #获取比例因子 f=放大系数,如果dy<0,则放大系数;如果dy>0,则缩小系数,否则放大系数为1 #如果缩放级别在正确的范围内 如果.2
glTranslatef
这样的函数并不是绝对有效的。相反,它们会按指定的数量移动“世界”。因此,如果你说
glTranslatef(100100)
你会从现在的位置上下移动100个单位,而不是
100100

他们在后台所做的是修改当前视图矩阵。要使其正常工作,您需要编写如下代码:

glPushMatrix() # save the current matrix somewhere; gives you a new copy to modify

glTranslatef(100,100) # modify your copy; 
                      # you need to do this *every time* before you draw anything
... draw ...

glPopMatrix() # undo all and any change you made to the matrix

在又一天的痛苦之后,我终于找到了一个解决方案:在2D中,最简单的方法是使用
glOrtho()
函数更改投影矩阵,这种方法基于鼠标坐标(轴心点)进行缩放和右键单击并拖动平移,而无需跳跃

这是我的原始代码的一个简化版本——如果你使用PygLeLe的数据量,你应该考虑使用组和批处理,但是为了更容易理解,我使用了<代码> GLASHEN()/<代码> <代码> GLCOLLY()/<代码>,<代码> GLVTEXTER()/<代码> <代码> GLDEND()>代码>函数在这里绘制。

import pyglet
from pyglet.gl import *

# Zooming constants
ZOOM_IN_FACTOR = 1.2
ZOOM_OUT_FACTOR = 1/ZOOM_IN_FACTOR

class App(pyglet.window.Window):

    def __init__(self, width, height, *args, **kwargs):
        conf = Config(sample_buffers=1,
                      samples=4,
                      depth_size=16,
                      double_buffer=True)
        super().__init__(width, height, config=conf, *args, **kwargs)

        #Initialize camera values
        self.left   = 0
        self.right  = width
        self.bottom = 0
        self.top    = height
        self.zoom_level = 1
        self.zoomed_width  = width
        self.zoomed_height = height

    def init_gl(self, width, height):
        # Set clear color
        glClearColor(0/255, 0/255, 0/255, 0/255)

        # Set antialiasing
        glEnable( GL_LINE_SMOOTH )
        glEnable( GL_POLYGON_SMOOTH )
        glHint( GL_LINE_SMOOTH_HINT, GL_NICEST )

        # Set alpha blending
        glEnable( GL_BLEND )
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )

        # Set viewport
        glViewport( 0, 0, width, height )

    def on_resize(self, width, height):
        # Set window values
        self.width  = width
        self.height = height
        # Initialize OpenGL context
        self.init_gl(width, height)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        # Move camera
        self.left   -= dx*self.zoom_level
        self.right  -= dx*self.zoom_level
        self.bottom -= dy*self.zoom_level
        self.top    -= dy*self.zoom_level

    def on_mouse_scroll(self, x, y, dx, dy):
        # Get scale factor
        f = ZOOM_IN_FACTOR if dy > 0 else ZOOM_OUT_FACTOR if dy < 0 else 1
        # If zoom_level is in the proper range
        if .2 < self.zoom_level*f < 5:

            self.zoom_level *= f

            mouse_x = x/self.width
            mouse_y = y/self.height

            mouse_x_in_world = self.left   + mouse_x*self.zoomed_width
            mouse_y_in_world = self.bottom + mouse_y*self.zoomed_height

            self.zoomed_width  *= f
            self.zoomed_height *= f

            self.left   = mouse_x_in_world - mouse_x*self.zoomed_width
            self.right  = mouse_x_in_world + (1 - mouse_x)*self.zoomed_width
            self.bottom = mouse_y_in_world - mouse_y*self.zoomed_height
            self.top    = mouse_y_in_world + (1 - mouse_y)*self.zoomed_height

    def on_draw(self):
        # Initialize Projection matrix
        glMatrixMode( GL_PROJECTION )
        glLoadIdentity()

        # Initialize Modelview matrix
        glMatrixMode( GL_MODELVIEW )
        glLoadIdentity()
        # Save the default modelview matrix
        glPushMatrix()

        # Clear window with ClearColor
        glClear( GL_COLOR_BUFFER_BIT )

        # Set orthographic projection matrix
        glOrtho( self.left, self.right, self.bottom, self.top, 1, -1 )

        # Draw quad
        glBegin( GL_QUADS )
        glColor3ub( 0xFF, 0, 0 )
        glVertex2i( 10, 10 )

        glColor3ub( 0xFF, 0xFF, 0 )
        glVertex2i( 110, 10 )

        glColor3ub( 0, 0xFF, 0 )
        glVertex2i( 110, 110 )

        glColor3ub( 0, 0, 0xFF )
        glVertex2i( 10, 110 )
        glEnd()

        # Remove default modelview matrix
        glPopMatrix()

    def run(self):
        pyglet.app.run()


App(500, 500).run()
导入pyglet 从pyglet.gl导入* #缩放常数 放大系数=1.2 缩小系数=1/放大系数 类应用程序(pyglet.window.window): 定义初始值(自身、宽度、高度、*args、**kwargs): conf=Config(示例缓冲区=1, 样本=4, 深度×尺寸=16,