Python小白也能玩转3D用PyOpenGL画你的第一个彩色立方体附完整代码还记得第一次看到3D游戏时的震撼吗那些在屏幕上旋转跳跃的立体模型曾经是那么遥不可及。今天我要告诉你一个秘密用Python和PyOpenGL你也能轻松创造出属于自己的3D世界不需要复杂的数学公式不需要深厚的编程功底跟着我一步步来30分钟后你就能让一个彩色立方体在屏幕上翩翩起舞。1. 环境准备搭建你的3D创作舞台在开始之前我们需要准备好工具。就像画家需要画布和颜料一样3D编程也需要特定的环境支持。好消息是Python让这一切变得异常简单。首先确保你已经安装了Python推荐3.7及以上版本然后打开终端或命令提示符输入以下命令安装必要的库pip install PyOpenGL PyOpenGL_accelerate numpy这三个库各司其职PyOpenGLPython版的OpenGL接口PyOpenGL_accelerate提升PyOpenGL的运行效率numpy处理3D坐标数据的高效工具提示如果你使用的是Anaconda也可以用conda install pyopengl numpy来安装安装完成后新建一个Python文件比如colorful_cube.py我们的3D之旅就从这里开始2. 创建3D窗口打开通往虚拟世界的大门任何3D场景都需要一个展示窗口。在PyOpenGL中我们可以用GLUTOpenGL Utility Toolkit来快速创建一个窗口。别被这些术语吓到实际操作非常简单。from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * import numpy as np class CubeDemo: def __init__(self): # 初始化GLUT glutInit() # 设置显示模式双缓冲RGBA glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH) # 创建800x600像素的窗口 glutInitWindowSize(800, 600) glutCreateWindow(b我的第一个3D立方体) # 设置绘制回调函数 glutDisplayFunc(self.draw_cube) # 设置空闲时调用的函数用于动画 glutIdleFunc(self.animate) # 初始化OpenGL设置 self.init_gl() # 进入主循环 glutMainLoop()这段代码做了以下几件事导入必要的OpenGL模块创建一个窗口并设置标题指定当窗口需要重绘时调用的函数draw_cube设置空闲时调用的动画函数animate初始化一些OpenGL的基本设置3. 绘制彩色立方体从点到面的魔法现在来到最有趣的部分——绘制一个彩色立方体。立方体有8个顶点每个面由4个顶点组成。我们将为每个顶点指定不同的颜色创造出彩虹般的效果。首先定义立方体的顶点和颜色数据def init_gl(self): # 启用深度测试让3D物体正确遮挡 glEnable(GL_DEPTH_TEST) # 设置透视投影 gluPerspective(45, 800/600, 0.1, 50.0) # 将物体向后移动以便在视图中可见 glTranslatef(0.0, 0.0, -5.0) # 立方体的8个顶点坐标 self.vertices np.array([ [1, -1, -1], # 顶点0 [1, 1, -1], # 顶点1 [-1, 1, -1], # 顶点2 [-1, -1, -1], # 顶点3 [1, -1, 1], # 顶点4 [1, 1, 1], # 顶点5 [-1, 1, 1], # 顶点6 [-1, -1, 1] # 顶点7 ], dtypenp.float32) # 每个顶点的颜色RGB self.colors np.array([ [1, 0, 0], # 红色 [0, 1, 0], # 绿色 [0, 0, 1], # 蓝色 [1, 1, 0], # 黄色 [1, 0, 1], # 紫色 [0, 1, 1], # 青色 [1, 1, 1], # 白色 [0, 0, 0] # 黑色 ], dtypenp.float32) # 立方体的6个面每个面由4个顶点组成 self.faces [ [0, 1, 2, 3], # 前面 [4, 5, 6, 7], # 后面 [0, 1, 5, 4], # 右面 [2, 3, 7, 6], # 左面 [1, 2, 6, 5], # 上面 [0, 3, 7, 4] # 下面 ] # 旋转角度 self.rotation [0, 0, 0]接下来是绘制立方体的函数def draw_cube(self): # 清除颜色和深度缓冲 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 应用旋转 glRotatef(self.rotation[0], 1, 0, 0) glRotatef(self.rotation[1], 0, 1, 0) glRotatef(self.rotation[2], 0, 0, 1) # 开始绘制立方体的各个面 glBegin(GL_QUADS) for face in self.faces: for vertex in face: glColor3fv(self.colors[vertex]) glVertex3fv(self.vertices[vertex]) glEnd() # 交换缓冲区双缓冲技术避免闪烁 glutSwapBuffers()4. 让立方体动起来添加旋转动画静态的立方体虽然漂亮但让它旋转起来才更有3D的感觉。我们将通过修改旋转角度来实现动画效果。def animate(self): # 每次调用时增加旋转角度 self.rotation[0] 0.5 # X轴旋转 self.rotation[1] 0.5 # Y轴旋转 self.rotation[2] 0.5 # Z轴旋转 # 标记当前窗口需要重新绘制 glutPostRedisplay()最后添加程序入口if __name__ __main__: CubeDemo()现在运行你的程序你应该能看到一个彩色的立方体在屏幕上旋转按下CtrlC可以退出程序。5. 进阶技巧灯光和材质为了让立方体看起来更真实我们可以添加简单的光照效果。修改init_gl函数def init_gl(self): # 之前的设置保持不变... # 启用光照 glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) # 设置光源位置 light_pos [1.0, 1.0, 1.0, 0.0] glLightfv(GL_LIGHT0, GL_POSITION, light_pos) # 设置材质反射属性 mat_specular [1.0, 1.0, 1.0, 1.0] mat_shininess [50.0] glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular) glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess) # 启用颜色材质这样顶点的颜色会影响材质 glEnable(GL_COLOR_MATERIAL) glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)现在立方体看起来会有明暗变化更像一个真实的物体了6. 完整代码清单为了方便参考以下是完整的代码from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * import numpy as np class CubeDemo: def __init__(self): glutInit() glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH) glutInitWindowSize(800, 600) glutCreateWindow(b我的第一个3D立方体) glutDisplayFunc(self.draw_cube) glutIdleFunc(self.animate) self.init_gl() glutMainLoop() def init_gl(self): glEnable(GL_DEPTH_TEST) gluPerspective(45, 800/600, 0.1, 50.0) glTranslatef(0.0, 0.0, -5.0) self.vertices np.array([ [1, -1, -1], [1, 1, -1], [-1, 1, -1], [-1, -1, -1], [1, -1, 1], [1, 1, 1], [-1, 1, 1], [-1, -1, 1] ], dtypenp.float32) self.colors np.array([ [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1], [1, 1, 1], [0, 0, 0] ], dtypenp.float32) self.faces [ [0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 5, 4], [2, 3, 7, 6], [1, 2, 6, 5], [0, 3, 7, 4] ] self.rotation [0, 0, 0] # 光照设置 glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) light_pos [1.0, 1.0, 1.0, 0.0] glLightfv(GL_LIGHT0, GL_POSITION, light_pos) mat_specular [1.0, 1.0, 1.0, 1.0] mat_shininess [50.0] glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular) glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess) glEnable(GL_COLOR_MATERIAL) glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) def draw_cube(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glRotatef(self.rotation[0], 1, 0, 0) glRotatef(self.rotation[1], 0, 1, 0) glRotatef(self.rotation[2], 0, 0, 1) glBegin(GL_QUADS) for face in self.faces: for vertex in face: glColor3fv(self.colors[vertex]) glVertex3fv(self.vertices[vertex]) glEnd() glutSwapBuffers() def animate(self): self.rotation[0] 0.5 self.rotation[1] 0.5 self.rotation[2] 0.5 glutPostRedisplay() if __name__ __main__: CubeDemo()7. 创意扩展让你的立方体与众不同现在你已经掌握了基本技巧可以尝试以下创意扩展改变颜色方案尝试单色调的立方体不同面使用同一颜色的不同深浅使用渐变色让颜色从一个顶点平滑过渡到另一个顶点添加纹理用glTexImage2D加载图片作为立方体的纹理为不同面使用不同的纹理图片交互控制用键盘控制立方体的旋转方向和速度添加鼠标交互让用户能拖动旋转立方体多个立方体创建多个立方体让它们以不同速度和方向旋转尝试让立方体之间产生碰撞效果# 示例键盘控制旋转 def keyboard(self, key, x, y): if key bx: self.rotation[0] 5 elif key by: self.rotation[1] 5 elif key bz: self.rotation[2] 5 glutPostRedisplay() # 在__init__中添加 glutKeyboardFunc(self.keyboard)第一次看到自己创建的3D立方体在屏幕上旋转时那种成就感是难以言表的。记得我刚开始学习3D编程时花了一整天时间才让一个三角形正确显示。现在有了PyOpenGL和Python整个过程变得如此简单。如果你遇到了问题不妨调整一下视角参数或者检查顶点定义是否正确——3D编程中最常见的错误往往就藏在这些细节中。