如何像在搅拌机中一样用鼠标拖动相机

Posted

技术标签:

【中文标题】如何像在搅拌机中一样用鼠标拖动相机【英文标题】:how to drag camera with the mouse like in blender 【发布时间】:2022-01-20 16:53:50 【问题描述】:

我找到了一个程序,你可以在 pyopengl 中用鼠标在相机周围移动,通过做一些我没有完全理解的事情

from pygame.locals import *
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *


def cube():
    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)
    )
    edegs = (
        (0,1),
        (0,3),
        (0,4),
        (2,1),
        (2,3),
        (2,7),
        (6,3),
        (6,4),
        (6,7),
        (5,1),
        (5,4),
        (5,7),
    )
    glBegin(GL_LINES)
    glColor3fv((1,1,1))
    for edeg in edegs:
        for vertex in edeg:
            glVertex3fv(vertices[vertex])
    glEnd()
pygame.init()
screen = (800,600)
pygame.display.set_mode(screen, DOUBLEBUF|OPENGL)
glMatrixMode(GL_PROJECTION)

gluPerspective(45, (screen[0]/screen[1]), 0.1, 50.0)

glTranslate(0.0,0.0,-5)
glMatrixMode(GL_MODELVIEW)  
modelMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)

busy = True
button_down = False
zoom = -0.5
while True:
    glPushMatrix()
    glLoadIdentity()

    for event in pygame.event.get():
        if(event.type == pygame.QUIT):
            pygame.quit()
            busy = False
        elif event.type == pygame.MOUSEMOTION:
            if(button_down):
                glRotatef(event.rel[1], 1, 0, 0)
                glRotatef(event.rel[0], 0, 1, 0)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 4:
                zoom += 0.2
            if event.button == 5:
                zoom -= 0.2
    if(not busy): break
    for event in pygame.mouse.get_pressed():
        if pygame.mouse.get_pressed()[0] == 1:
            button_down = True
        elif pygame.mouse.get_pressed()[0] == 0:
            button_down = False
            
    #mouse scroll
    
            
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    glMultMatrixf(modelMatrix)
    modelMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)

    glLoadIdentity()
    glTranslatef(0.0,0.0,zoom)
    
    glMultMatrixf(modelMatrix)

    cube()

    
    glPopMatrix()
    
        

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

但是当你在它周围拖动对象时,它开始失去从上到下的方向,这与 Blender 和 SketchUp 等程序不同,有没有办法解决这个问题或用其他方法来操纵相机?

【问题讨论】:

【参考方案1】:

只需将绕 x 轴的旋转和绕 y 轴的旋转相加即可。先绕y轴旋转,再绕x轴旋转:

modelview = translate * rotateY * raotateX

完整示例:

from pygame.locals import *
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

def cube():
    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)
    )
    edegs = (
        (0,1), (0,3), (0,4), (2,1), (2,3), (2,7),
        (6,3), (6,4), (6,7), (5,1), (5,4), (5,7),
    )
    glBegin(GL_LINES)
    glColor3fv((1,1,1))
    for edeg in edegs:
        for vertex in edeg:
            glVertex3fv(vertices[vertex])
    glColor3fv((1,0,0))    
    glVertex3f(0, -2, 0)  
    glVertex3f(0, 2, 0)    
    glEnd()

pygame.init()
screen = (400, 300)
pygame.display.set_mode(screen, DOUBLEBUF|OPENGL)

glEnable(GL_DEPTH_TEST)

glMatrixMode(GL_PROJECTION)
gluPerspective(45, (screen[0]/screen[1]), 0.1, 50.0)

glMatrixMode(GL_MODELVIEW)  
glTranslate(0.0,0.0,-5)

rot_x, rot_y, zoom = 0, 0, -0.5

clock = pygame.time.Clock()
busy = True
while busy:

    mouse_buttons = pygame.mouse.get_pressed()
    button_down = mouse_buttons[0] == 1
   
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            busy = False
        elif event.type == pygame.MOUSEMOTION:
            if button_down:
                rot_x += event.rel[1]
                rot_y += event.rel[0]
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 4:
                zoom += 0.2
            if event.button == 5:
                zoom -= 0.2
            
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    glPushMatrix()
    glTranslatef(0.0,0.0, zoom)
    glRotatef(rot_x, 1, 0, 0)    
    glRotatef(rot_y, 0, 1, 0)    
    cube()
    glPopMatrix()
    
    pygame.display.flip()
    clock.tick(100)

pygame.quit()

另请参阅How to implement alt+MMB camera rotation like in 3ds max?、How to implement camera pan like in 3dsMax?、How to implement zoom towards mouse like in 3dsMax?。

【讨论】:

以上是关于如何像在搅拌机中一样用鼠标拖动相机的主要内容,如果未能解决你的问题,请参考以下文章

使用鼠标拖动为相机创建边界

如何像在 3dsMax 中一样实现鼠标缩放?

如何在地图上拖动鼠标进行导航?

Html 表格在中间水平滚动,就像在触摸屏上一样

Three.js用相机选择对象,没有鼠标

Cesium.js禁止三维球鼠标旋转、缩放、鼠标中键拖动