You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyOpenGL实现鼠标旋转3D场景(仿Blender视角控制)

实现Blender风格的3D场景鼠标旋转效果

嘿,我来帮你搞定这个3D旋转的需求!要实现类似Blender的鼠标旋转场景(本质是轨道相机绕物体运动),咱们用PyOpenGL+GLUT来做最直观,下面一步步给你讲清楚:

核心思路

Blender里旋转视图的逻辑是相机围绕目标物体做轨道运动,始终看向物体中心。咱们不用真的旋转整个场景,而是通过更新相机的位置和朝向来模拟这种效果——这样比旋转场景更高效,也更符合3D交互的常规逻辑。

步骤1:搭建环境

首先得装必要的库,打开终端跑这俩命令:

pip install PyOpenGL PyOpenGL-accelerate

(如果是Windows系统,可能需要额外装GLUT的二进制包,不过PyOpenGL一般会自带基础支持)

步骤2:完整实现代码

下面是可以直接运行的代码,我给你标了关键注释:

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import math

# 相机参数:方位角(绕Y轴)、俯仰角(绕X轴)、距离目标点的距离
camera_azimuth = 0.0
camera_elevation = 0.0
camera_distance = 5.0

# 鼠标状态记录
mouse_down = False
last_x = 0
last_y = 0

def draw_cube():
    # 画一个中心在原点的立方体
    glBegin(GL_QUADS)
    # 前面
    glColor3f(1.0, 0.0, 0.0)
    glVertex3f(-1, -1, 1)
    glVertex3f(1, -1, 1)
    glVertex3f(1, 1, 1)
    glVertex3f(-1, 1, 1)
    # 后面
    glColor3f(0.0, 1.0, 0.0)
    glVertex3f(-1, -1, -1)
    glVertex3f(-1, 1, -1)
    glVertex3f(1, 1, -1)
    glVertex3f(1, -1, -1)
    # 左面
    glColor3f(0.0, 0.0, 1.0)
    glVertex3f(-1, -1, -1)
    glVertex3f(-1, -1, 1)
    glVertex3f(-1, 1, 1)
    glVertex3f(-1, 1, -1)
    # 右面
    glColor3f(1.0, 1.0, 0.0)
    glVertex3f(1, -1, -1)
    glVertex3f(1, 1, -1)
    glVertex3f(1, 1, 1)
    glVertex3f(1, -1, 1)
    # 上面
    glColor3f(1.0, 0.0, 1.0)
    glVertex3f(-1, 1, -1)
    glVertex3f(-1, 1, 1)
    glVertex3f(1, 1, 1)
    glVertex3f(1, 1, -1)
    # 下面
    glColor3f(0.0, 1.0, 1.0)
    glVertex3f(-1, -1, -1)
    glVertex3f(1, -1, -1)
    glVertex3f(1, -1, 1)
    glVertex3f(-1, -1, 1)
    glEnd()

def update_camera():
    # 根据方位角和俯仰角计算相机位置
    rad_azimuth = math.radians(camera_azimuth)
    rad_elevation = math.radians(camera_elevation)
    
    # 球面坐标转笛卡尔坐标
    x = camera_distance * math.sin(rad_azimuth) * math.cos(rad_elevation)
    y = camera_distance * math.sin(rad_elevation)
    z = camera_distance * math.cos(rad_azimuth) * math.cos(rad_elevation)
    
    # 设置相机:位置(x,y,z),看向原点(0,0,0),头顶方向(0,1,0)
    gluLookAt(x, y, z,
              0, 0, 0,
              0, 1, 0)

def display():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    
    # 更新相机位置
    update_camera()
    
    # 画立方体
    draw_cube()
    
    glutSwapBuffers()

def mouse_motion(x, y):
    global camera_azimuth, camera_elevation, last_x, last_y
    if mouse_down:
        # 计算鼠标偏移量,转换成角度(每像素0.1度)
        delta_x = x - last_x
        delta_y = y - last_y
        
        camera_azimuth += delta_x * 0.1
        camera_elevation -= delta_y * 0.1
        
        # 限制俯仰角,避免翻转
        camera_elevation = max(-89.0, min(89.0, camera_elevation))
        
        last_x = x
        last_y = y
        glutPostRedisplay()

def mouse_button(button, state, x, y):
    global mouse_down, last_x, last_y
    if button == GLUT_LEFT_BUTTON:
        if state == GLUT_DOWN:
            mouse_down = True
            last_x = x
            last_y = y
        else:
            mouse_down = False

def init():
    glEnable(GL_DEPTH_TEST)  # 开启深度测试,正确显示3D层级
    glClearColor(0.1, 0.1, 0.1, 1.0)  # 背景色
    glMatrixMode(GL_PROJECTION)
    gluPerspective(45, 800/600, 0.1, 100.0)  # 透视投影
    glMatrixMode(GL_MODELVIEW)

if __name__ == "__main__":
    glutInit()
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
    glutInitWindowSize(800, 600)
    glutCreateWindow(b"Blender-style 3D Rotation")
    init()
    glutDisplayFunc(display)
    glutMotionFunc(mouse_motion)
    glutMouseFunc(mouse_button)
    glutMainLoop()

关键部分解释

  • 轨道相机逻辑:用球面坐标计算相机位置,gluLookAt负责设置相机的视角,始终看向立方体中心(原点)。
  • 鼠标交互:按下左键时记录初始位置,拖动时计算偏移量,转换成相机的方位角和俯仰角变化,同时限制俯仰角防止画面翻转。
  • 深度测试:glEnable(GL_DEPTH_TEST)确保3D物体的遮挡关系正确,不会出现前面的面被后面的面覆盖的情况。

运行效果

你运行代码后,按住鼠标左键拖动,就能像Blender里那样旋转视角,围着立方体看各个面啦!如果想调整距离,可以加个滚轮回调函数,修改camera_distance的值就行。

内容的提问来源于stack exchange,提问作者Misunderstood Salad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:28:20