本文主要是介绍PyOpenGL的安装与操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、安装
在PyOpenGL中,不能直接用pip指令安装,因为pip默认安装的是32位版本的,如果直接安装,运行一段GL代码以后,会报错,具体报错内容如下:
NullFunctionError: Attempt to call an undefined function glutInit, check for bool(glutInit) before calling
所以这个库不能直接通过pip安装,只能去官网下载,地址:
https://www.lfd.uci.edu/~gohlke/pythonlibs/
进入后,找到PyOpenGL:bindings to OpenGL,GLUT,and GLE. 蓝色字样标题,然后在下面下载对应自己python版本的文件(一共两个,本人用的是3.8版本)。
下载好以后,打开cmd,cd到这两个文件所在的位置,然后通过pip来安装,安装时,pip会把释放的文件自动存在site-package中,具体的指令如下:
pip install PyOpenGL-3.1.6-cp38-cp38-win_amd64.whl
pip install PyOpenGL_accelerate-3.1.6-cp38-cp38-win_amd64.whl
二、语法以及详细注释
博文参考
https://blog.csdn.net/weixin_42954615/article/details/113747847?spm=1001.2014.3001.5502 实践教程往这看!!!!!!!
https://blog.csdn.net/xufive/article/details/86565130 各个函数的实用方法往这看 !!!!!!!!!!
OpenGL 函数库相关的 API 有核心库(gl)、实用库(glu)、实用工具库(glut)、辅助库(aux)、窗口库(glx、agl、wgl)和扩展函数库等。
gl是核心,glu是对gl的部分封装。glut是为跨平台的OpenGL程序的工具包,比aux功能强大。glx、agl、wgl 是针对不同窗口系统的函数。
扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩展机制开发的函数。常见的库前缀有 gl、glu、glut、aux、wgl、glx、agl 等。库前缀表示该函数属于 OpenGL 哪一个开发库。
从函数名后面中还可以看出需要多少个参数以及参数的类型。I 代表 int 型,f 代表 float 型,d 代表 double 型,u 代表无符号整型。
例如 glColor3f() 表示了该函数属于gl库,参数是三个浮点数。
1. 一个实际操作与详细解释(绘制一个2d窗口)
from OpenGL.GL import * # 核心库
from OpenGL.GLU import * # 实用库
from OpenGL.GLUT import * # 实用工具库# 渲染用的函数,初始化的时候要用到
def renderfunc():pass# 绘图前必须要干的事情
glutInit() # 初始化实用工具库、主要是为了初始化窗口
glutInitDisplayMode(GLUT_RGBA|GLUT_SINGLE)# https://blog.csdn.net/u010087338/article/details/119343961?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165933097816782350811597%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165933097816782350811597&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119343961-null-null.142^v37^pc_rank_v37&utm_term=glutInitDisplayMode&spm=1018.2226.3001.4187# 参数有GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL# GLUT_RGBA表示颜色模式,另外还有GLUT_RGB 和 GLUT_INDEX模式,其中GLUT_RGBA为默认的颜色模式# 缓冲区类型:GLUT_DOUBLE表示使用双缓冲窗口,与之对应的是GLUT_SINGLE模式# 单缓冲,实际上就是将所有的绘图指令在窗口上执行,就是直接在窗口上绘图,这样的绘图效率是比较慢的,# 如果使用单缓冲,而电脑比较慢,屏幕会发生闪烁。一般只用于显示单独的一副非动态的图像# 双缓冲,实际上的绘图指令是在一个缓冲区完成,这里的绘图非常的快,在绘图指令完成之后,# 再通过交换指令把完成的图形立即显示在屏幕上,这就避免了出现绘图的不完整,同时效率很高。一般用于生成动画效果。
glutInitWindowSize(800,700) # 指定窗口大小 width height
glutCreateWindow('HELLO WORlD!!终于有中文了'.encode('gbk')) # 这里起窗口的名字,中文会乱码,要指定字体库,或者指定解码
glutDisplayFunc(renderfunc) # 回调函数,用来响应刷新消息
glutIdleFunc(renderfunc) # 回调函数,用来响应刷新消息,当事件队列中没有事件需要处理时,该空闲回调函数得到执行
glClearColor(0,0,0,0) # 设置背景颜色
gluOrtho2D(-1.0,-1.0,-1.0,1.0) # 截取图像的大小,gluOrtho2D(x_mix, x_max, y_mix, y_max)
glutMainLoop() # 阻断了系统的正常流程,在关闭glutCreateWindow()创建的窗口后,glutMainLoop()直接用exit(0)退出程序,# 而不会继续执行glutMainLoop()后的语句,有可能会造成内存泄漏,处理内存泄露方法如下# 1、使用glutLeaveMainLoop()代替glutMainLoop()。# 2、处理代码中exit(0)的部分。# 3、在glutMainLoop之前先设置:# glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);# 然后再用glutMainLoop();则 glutMainLoop()会在退出后,继续执行其后的代码。# 原文链接:https://blog.csdn.net/ronggang175/article/details/6068854
2. 创建一个3D渲染窗口,因为窗口里没东西,所以打开后会闪退
w,h = (800,800)
glutInit()
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(w,h)
glutCreateWindow('title')
glEnable(GL_DEPTH_TEST) # 开启更新深度缓冲区的功能,也就是,如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作。# 启动它,OpenGL就可以跟踪再Z轴上的像素,这样,它只会再那个像素前方没有东西时,才会绘画这个像素glDepthFunc(GL_LEQUAL) # 设置深度测试函数(GL_LEQUAL只是选项之一)
glEnable(GL_TEXTURE_2D) # 激活纹理单元,这玩意很重要!!!!!!!!!!!!
glClearColor(0, 0, 0, 0.0)
glClearDepth(1.0) # 指定初始深度值,如果是1,由于真实物体的每个像素都小于等于1,所以整个物体都会显示出来# 如果是0,由于真实物体的每个像素都大于等于0,所以整个物体就不会显示出来# 如果是0.5,真实物体深度值小于0.5的那部分才可以被看到glDepthFunc(GL_LESS) # 目标像素与当前像素在z方向上值大小比较,符合该函数关系的目标像素才进行绘制,否则对目标像素不予绘制,缺省GL_LESS# GL_NEVER,不通过(输入的深度值不取代参考值)# GL_LESS,如果输入的深度值小于参考值,则通过# GL_EQUAL,如果输入的深度值等于参考值,则通过# GL_LEQUAL,如果输入的深度值小于或等于参考值,则通过# GL_GREATER,如果输入的深度值大于参考值,则通过# GL_NOTE_QUAL,如果输入的深度值不等于参考值,则通过# GL_GEQUAL,如果输入的深度值大于或等于参考值,则通过# GL_ALWAYS,总是通过(输入的深度值取代参考值)glShadeModel(GL_SMOOTH) # 用于控制opengl中绘制指定两点间其他点颜色的过渡模式,参数一般为GL_SMOOTH(默认)# 如果两点的如果两点颜色不同,GL_SMOOTH会出现过渡效果# GL_FLAT 则只是以指定的某一点的单一色绘制其他所有点glEnable(GL_CULL_FACE) # 开启剔除操作效果,里面参数详解看下面
glCullFace(GL_BACK) # 参数包括GL_FRONT和GL_BACK。表示禁用多边形正面或者背面上的光照、阴影和颜色计算及操作,# GL_FRONT表示显示模式将适用于物体的前向面(也就是物体能看到的面)# GL_BACK表示显示模式将适用于物体的后向面(也就是物体上不能看到的面)# 消除不必要的渲染计算。例如某对象无论如何位置变化,我们都只能看到构成其组成的多边形的某一面时,可使用该函数# 也就是说,如果六面都看的话,要glDisable(GL_CULL_FACE),下面的正方体例子中就有这个问题# 里面还有一个函数,详情见 https://blog.csdn.net/iteye_9368/article/details/82170342glEnable(GL_POINT_SMOOTH) # 启用抗锯齿,针对点
glEnable(GL_LINE_SMOOTH) # 启用抗锯齿,针对线
glEnable(GL_POLYGON_SMOOTH) # 启用抗锯齿,针对多边形
glMatrixMode(GL_PROJECTION) # 原文链接:https://blog.csdn.net/u012861978/article/details/88552546# 在OpenGL中,如果想对模型进行操作,就要对这个模型的状态(当前的矩阵)乘上这个操作对应的一个矩阵.# 如果当前矩阵乘以变换矩阵(平移, 缩放, 旋转), 那相乘之后, 模型的位置被变换;# 如果当前矩阵乘以投影矩阵(将3D物体投影到2D平面), 相乘后, 模型的投影方式被设置;# 如果当前矩阵乘以纹理矩阵(), 模型的纹理方式被设置.# 而用来指定当前矩阵, 就是glMatriMode(GLenum mode);# glMatrixMode有3种模式: GL_PROJECTION 投影, GL_MODELVIEW 模型视图, GL_TEXTURE 纹理.# 所以,在操作投影矩阵以前,需要调用函数:# glMatrixMode(GL_PROJECTION); 将当前矩阵指定为投影矩阵# 然后把矩阵设为单位矩阵:# glLoadIdentity(); 重置当前矩阵为单位矩阵# 然后调用glFrustum()或gluPerspective(),它们生成的矩阵会与当前的矩阵相乘,生成透视投影的效果;
# glFrustum(GLdouble left, GLdouble Right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)# 创建一个透视型的视景体。其操作是创建一个透视投影的矩阵,并且用这个矩阵乘以当前矩阵。# 这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐标,即(left,bottom,-near)和(right,top,-near);# 最后一个参数far是远裁剪平面的离视点的距离值,其左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。# near和far表示离视点的远近,它们总为正值(near/far 必须>0)。 # glOrtho(left, right, bottom, top, near, far)# 和上面那个差不多,遵守左下、右上、近远原则# glOrtho(投影变换函数)创建一个正交平行的视景体,一般用于"物体不会因为离屏幕的远近而产生大小的变换"的情况。# glOrtho将产生一个矩阵,这个矩阵将填到投影矩阵上# glOrtho(0,with,height,0,-100,100)# OpenGL中有两个比较重要的投影变换函数,glViewport和glOrtho。
# glViewPort(x:GLInt;y:GLInt;Width:GLSizei;Height:GLSizei)# 调用glViewPort函数来决定视见区域,告诉OpenGL应把渲染之后的图形绘制在窗体的哪个部位。# 当视见区域是整个窗体时,OpenGL将把渲染结果绘制到整个窗口# 参数X,Y指定了视见区域的左下角在窗口中的位置,一般情况下为(0,0),Width和Height指定了视见区域的宽度和高度glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)# 原文链接:https://blog.csdn.net/l_andy/article/details/51773490# 这玩意是配合抗锯齿来使用的,参数target说明控制什么行为:# GL_POINT_SMOOTH_HINT、GL_LINE_SMOOTH_HINT和GL_POLYGON_SMOOTH_HINT分别指定点、线和多边形的采样质量;# GL_FOG_HINT指出雾是按像素进行(GL_NICEST)还是按顶点进行(GL_FASTEST);# GL_PERSPECTIVE_CORRECTION_HINT指定了颜色纹理插值的质量并可纠正由单纯线性插值所带来的一些视觉错误。# 参数hint可以是:GL_FASTEST(给出最有效的选择)、GL_NICEST(给出最高质量的选择)、GL_DONT_CARE(没有选择)。
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
glLoadIdentity()
gluPerspective(45.0,w / h, 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)# glFlush()
# glutSwapBuffers()# glFlush(),强制马上输出命令执行的结果,而不是存储在缓冲区中,继续等待其他OpenGL命令# 当执行双缓冲交换的时候,使用glutSwapBuffers。# 但是在有 glutSwapBuffers 的情况下, 不需要 glFlush 就可以达到同样的效果,因为我们执行双缓冲交换的时候,就隐形的执行了一次刷新操作。
# glutpostredisplay()# glutPostRedisplay 标记当前窗口需要重新绘制。通过glutMainLoop下一次循环时,# glutPostRedisplay函数会标记当前窗体来重新显示,它会促使主循环尽快的调用完显示函数# 窗口显示将被回调以重新显示窗口的正常面板。多次调用glutPostRedisplay,在下一个显示回调只产生单一的重新显示回调# 直到所有源代码都使用显示函数作为空闲函数.这意味着当没有任何事件要处理的时候GLUT会调用显示函数,也就是说,它会尽可能频繁的调用显示函数# https://blog.csdn.net/hongqiang200/article/details/17113361/
3. 经典小茶壶(带注释版本)
# 经典小茶壶
# | Y轴
# |
# |
# |____________X轴
# /
# /
# / Z轴def drawFunc():glClear(GL_COLOR_BUFFER_BIT) # 清理画布,将所有像素点还原未底色,有四个canshu# GL_COLOR_BUFFER_BIT 指定当前被激活为写操作的颜色缓存# GL_DEPTH_BUFFER_BIT 指定深度缓存# GL_ACCUM_BUFFER_BIT 指定累加缓存# GL_STENCIL_BUFFER_BIT 指定模板缓存指定模板缓存glRotatef(0.01, 1, 1, 1) # 指定旋转的方向,glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z),第一个参数是速度,其他的是角度# 想象:从 坐标(0,0,0)即原点,引出一条线到(1,0,0),然后茶壶绕着这条线逆时针旋转,具体轴线见上图glutWireTeapot(0.5) # 这玩意就是茶壶glFlush() # 用来强制刷新缓冲,保证绘图命令将被执行,而不是存储在缓冲区中等待其他的OpenGL命令glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"First")
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glClearColor(0.1,0.8,0.05,1)
glutMainLoop()
4. 开始绘图,第三段时绘图时都要用到的代码,cv就好
glBegin(mode)开始绘图,mode可以为:GL_POINTS,很多个点GL_LINES,很多条线段GL_LINE_STRIP,连续线段GL_LINE_LOOP、GL_POLYGON,多边形 (自动封口)GL_TRIANGLES,很多个三角形GL_TRIANGLE_STRIP,一串连续三角形(见示意图)GL_TRIANGLE_FAN,一串连续三角形(见示意图)GL_QUADS,很多四边形(注意不一定是矩形)GL_QUAD_STRIP,一串连续四边形
glColor3f(r,g,b)设置颜色,均为0~1之间的整数
glVertex2f(x,y)绘制一个点(单独一个点或者一个顶点)
glEnd()结束绘制
glPolygonMode(face,mode) 其中face为GL_FRONT(正面)或GL_BACK(背面,在2d绘图里没啥用), mode 为GL_LINE(只有线)或GL_FILL(不仅有线,还有填充)
绘制一个2D的图
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def init():glClearColor(0.0, 0.0, 0.0, 1.0)gluOrtho2D(-1.0, 1.0, -1.0, 1.0)def drawFunc():glClear(GL_COLOR_BUFFER_BIT)glColor3f(0.0, 1.0, 1.0)glPolygonMode(GL_FRONT, GL_LINE)glPolygonMode(GL_BACK, GL_FILL)glBegin(GL_QUADS)glVertex2f(-0.8, -0.8)glVertex2f(-0.8, 0.8)glVertex2f(0.8, 0.8)glVertex2f(0.8, -0.8)glEnd()glFlush()glutInit()
glutInitDisplayMode(GLUT_RGBA|GLUT_SINGLE)
glutInitWindowSize(400, 400)
glutCreateWindow(b"My OpenGL window")
glutDisplayFunc(drawFunc)
init()
glutMainLoop()
glEnable(GL_DEPTH_TEST)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)
glMatrixMode(GL_PROJECTION)
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
glMatrixMode(GL_MODELVIEW)
# 如果要添加材质,一定要把下面这个也给初始化了
glEnable(GL_TEXTURE_2D)
5. 一个立方体示意,尤其注意被注释的那两行
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)glRotatef(0.01, 1, 1, 0)vertex = [[[0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0]],[[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]], [[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1]],[[1, 0, 0], [1, 1, 0], [1, 1, 1], [1, 0, 1]], [[0, 0, 0], [0, 0, 1], [0, 1, 1], [0, 1, 0]]]for i in range(len(vertex)):glColor3f(1, 1, 1)glBegin(GL_QUADS)glVertex3f(*vertex[i][0]) # 绘制顶点glVertex3f(*vertex[i][1])glVertex3f(*vertex[i][2])glVertex3f(*vertex[i][3])glEnd()glFlush()glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(800, 800)
glutCreateWindow(b"OpenGL")
glClearColor(0, 0, 0, 0)
glEnable(GL_DEPTH_TEST)
glClearDepth(1)
glDepthFunc(GL_LESS)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)
glMatrixMode(GL_PROJECTION)
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST)
glMatrixMode(GL_MODELVIEW)
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glTranslatef(0,0,0)
glutMainLoop()
6. 给立方体加上材质
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
def drawFunc():glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)glRotatef(0.03, 1, 0, 0)vertex = [[[0,0,1],[1,0,1],[1,1,1],[0,1,1]],[[0,1,0],[0,1,1],[1,1,1],[1,1,0]],[[0,0,0],[0,1,0],[1,1,0],[1,0,0]],[[0,0,0],[1,0,0],[1,0,1],[0,0,1]],[[1,0,0],[1,1,0],[1,1,1],[1,0,1]],[[0,0,0],[0,0,1],[0,1,1],[0,1,0]]]for i in range(len(vertex)):glBindTexture(GL_TEXTURE_2D,1)glBegin(GL_QUADS)glTexCoord2f(0.0, 0.0)glVertex3f(*vertex[i][0])glTexCoord2f(1.0, 0.0)glVertex3f(*vertex[i][1])glTexCoord2f(1.0, 1.0)glVertex3f(*vertex[i][2])glTexCoord2f(0.0, 1.0)glVertex3f(*vertex[i][3])glEnd()glFlush()glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH)
glutInitWindowSize(800, 800)
glutCreateWindow(b"OpenGL")
glClearColor(0,0,0,0)
glEnable(GL_DEPTH_TEST)
glClearDepth(1)
# glDepthFunc(GL_GEQUAL)
# glDepthFunc(GL_LESS)
# glDepthFunc(GL_LEQUAL)
glShadeModel(GL_SMOOTH)# glDisable(GL_CULL_FACE)
# glEnable(GL_CULL_FACE)
# glFrontFace(GL_CW)
# glCullFace(GL_FRONT)
# glCullFace(GL_BACK)glPolygonMode(GL_BACK,GL_POINT)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)
glMatrixMode(GL_PROJECTION)
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
# glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)
glMatrixMode(GL_MODELVIEW)
glEnable(GL_TEXTURE_2D)img = Image.open('b.png')
width, height = img.size
img = img.tobytes('raw','RGB',0,-1)
glGenTextures(2) # 根据纹理参数返回N个纹理索引
glBindTexture(GL_TEXTURE_2D, 1) # 告诉OpenGL下面代码中对2D纹理的任何设置都是针对索引为1的纹理的
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGB,GL_UNSIGNED_BYTE,img)# 绘制一个2D纹理# 0 代表图像的详细程度, 默认为0即可# 3 颜色成分R(红色分量)、G(绿色分量)、B(蓝色分量)三部分,若为4则是R(红色分量)、G(绿色分量)、B(蓝色分量)、Alpha# width 纹理的宽度# height 纹理的高度# 0 边框的值# GL_RGB 告诉OpenGL图像数据由红、绿、蓝三色数据组成# GL_UNSIGNED_BYTE 组成图像的数据是无符号字节类型# img 告诉OpenGL纹理数据的来源,此例中指向存放在TextureImage[0]记录中的数据
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP) # 指定贴图方式,并滤波,详情 https://blog.csdn.net/flycatdeng/article/details/82595267# 第一个参数,只能取GL_TEXTURE_1D或者GL_TEXTURE_2D# 第二个参数,GL_TEXTURE_WRAP_S: S方向上的贴图模式,T就是T方向上贴图# GL_TEXTURE_MAG_FILTER: 放大过滤# GL_TEXTURE_MIN_FILTER: 缩小过滤# # 第三个参数,GL_LINEAR: 线性过滤, 使用距离当前渲染像素中心最近的4个纹素加权平均值# GL_LINEAR_MIPMAP_NEAREST: 使用GL_NEAREST对最接近当前多边形的解析度的两个层级贴图进行采样,然后用这两个值进行线性插值# GL_NEAREST: 这种方式没有真正进行滤波。它只占用很小的处理能力,看起来也很差。唯一的好处是在很快和很慢的机器上都可以正常运行#
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_DECAL)
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glLoadIdentity() # 重置矩阵为单位矩阵
glTranslatef(0, -0.5, 0) # 移动模型位置
glPolygonMode(GL_BACK,GL_FILL)
glutMainLoop()
7. 上面是让正方体自己转起来,这个是让自己的摄像机旋转起来,不知道为什么,这个运行不起来,以后再来看
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
import math
theta,phi = (60,30)
pos = (3,60,60)
def target():global theta,phix = math.sin(theta) * math.cos(phi)y = math.sin(theta) * math.sin(phi)z = math.cos(theta)return x,y,z
def setLookAt():global postar = target()gluLookAt(*pos,*tar,0,1,0)glLoadIdentity()
def drawFunc():glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)setLookAt()# glRotatef(0.01,0,1,0)vertex = [[[0,0,1],[1,0,1],[1,1,1],[0,1,1]],[[0,0,0],[0,1,0],[1,1,0],[1,0,0]],[[0,1,0],[0,1,1],[1,1,1],[1,1,0]],[[0,0,0],[1,0,0],[1,0,1],[0,0,1]],[[1,0,0],[1,1,0],[1,1,1],[1,0,1]],[[0,0,0],[0,0,1],[0,1,1],[0,1,0]]]for i in range(len(vertex)):glBindTexture(GL_TEXTURE_2D,1)glBegin(GL_QUADS)glTexCoord2f(0.0, 0.0)glVertex3f(*vertex[i][0])glTexCoord2f(1.0, 0.0)glVertex3f(*vertex[i][1])glTexCoord2f(1.0, 1.0)glVertex3f(*vertex[i][2])glTexCoord2f(0.0, 1.0)glVertex3f(*vertex[i][3])glEnd()glFlush()
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(800, 800)
glutCreateWindow(b"OpenGL")
glClearColor(0,0,0,0)
# glEnable(GL_DEPTH_TEST)
# glClearDepth(1)
# glDepthFunc(GL_LESS)
# glShadeModel(GL_SMOOTH)
# glEnable(GL_CULL_FACE)
# glCullFace(GL_BACK)
# glEnable(GL_POINT_SMOOTH)
# glEnable(GL_LINE_SMOOTH)
# glEnable(GL_POLYGON_SMOOTH)
# glMatrixMode(GL_PROJECTION)
# glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
# glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
# glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
# glMatrixMode(GL_MODELVIEW)
glEnable(GL_TEXTURE_2D)
img = Image.open('b.png')
width, height = img.size
img = img.tobytes('raw','RGB',0,-1)
glGenTextures(2)
glBindTexture(GL_TEXTURE_2D, 1)
glTexImage2D(GL_TEXTURE_2D, 0, 4,width,height, 0, GL_RGB,GL_UNSIGNED_BYTE,img)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_DECAL)
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
8. OpenGL鼠标与键盘监听事件
OpenGL支持的事件很少,都是由GLUT提供的,有:
键盘按下(glutKeyboardFunc、glutSpecialFunc)
鼠标移动(glutMotionFunc、glutPassiveMotionFunc)
鼠标按下、放开(glutMouseFunc)
注册方式都是register(func),例如 glutKeyboardFunc(keyboard)
原文链接:https://blog.csdn.net/weixin_42954615/article/details/113767921
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():glClear(GL_COLOR_BUFFER_BIT)glRotatef(0.01, 0, 1, 0)glutWireTeapot(0.5)glFlush()def procKeyboard(key, x, y): # 函数中key代表按键,x和y代表的是鼠标的位置print('KEYBOARD RECALL:')print('MOUSE:%s,%s' % (x, y))print('KEY:%s' % key.decode())glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"First")
glutKeyboardFunc(procKeyboard) # 监听键盘的动作
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
一些其他的监听键位,其与glutKeyboardFunc相似,但只处理特殊键↓ \downarrow↓
GLUT_KEY_BEGIN
GLUT_KEY_DELETE
GLUT_KEY_DOWN
GLUT_KEY_END
GLUT_KEY_F1
GLUT_KEY_F2
GLUT_KEY_F3
GLUT_KEY_F4
GLUT_KEY_F5
GLUT_KEY_F6
GLUT_KEY_F7
GLUT_KEY_F8
GLUT_KEY_F9
GLUT_KEY_F10
GLUT_KEY_F11
GLUT_KEY_F12
GLUT_KEY_HOME
GLUT_KEY_INSERT
GLUT_KEY_LEFT
GLUT_KEY_NUM_LOCK
GLUT_KEY_PAGE_DOWN
GLUT_KEY_PAGE_UP
GLUT_KEY_REPEAT_DEFAULT
GLUT_KEY_REPEAT_OFF
GLUT_KEY_REPEAT_ON
GLUT_KEY_RIGHT
GLUT_KEY_UP
特殊键位监听的例子
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():glClear(GL_COLOR_BUFFER_BIT)glRotatef(1, 0, 1, 0)glutWireTeapot(0.5)glFlush()def procKeyboard(key, x, y):print('KEYBOARD RECALL:')print('MOUSE:%s,%s' % (x, y))print('KEY:%s' % key)glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"First")
glutSpecialFunc(procKeyboard) # 一些特殊键位的监听
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
将鼠标拖拽的位置返回
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():glClear(GL_COLOR_BUFFER_BIT)glRotatef(1, 0, 1, 0)glutWireTeapot(0.5)glFlush()def procMotion(x, y):print('MOTION RECALL:')print('MOUSE:%s,%s' % (x, y))glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"First")
glutMotionFunc(procMotion) # 鼠标拖拽位置
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
鼠标在界面移动位置实时返回
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():glClear(GL_COLOR_BUFFER_BIT)glRotatef(1, 0, 1, 0)glutWireTeapot(0.5)glFlush()def procMotion(x, y):print('MOTION RECALL:')print('MOUSE:%s,%s' % (x, y))glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"First")
glutPassiveMotionFunc(procMotion) # 鼠标移动位置实时返回
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
鼠标点击位置实时返回
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():glClear(GL_COLOR_BUFFER_BIT)glRotatef(1, 0, 1, 0)glutWireTeapot(0.5)glFlush()def procMouse(btn, state, x, y):st = 'pressed' if (state == GLUT_DOWN) else 'released'print('MOTION RECALL:')print('button %s %s' % (btn, st))print('MOUSE:%s,%s' % (x, y))glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"First")
glutMouseFunc(procMouse) # 鼠标按键点击位置实时返回
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
9. 用来屏幕上像素操作的
glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data)width:像素图宽度height:像素图高度format:GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_RED, GL_GREEN, GL_BLUE中的一个,表示颜色模式,推荐使用GL_RGBtype:表示数据类型,推荐使用GL_UNSIGNED_BYTE,详情见 https://blog.csdn.net/weixin_42954615/article/details/113832148data像素图,c++中使用列表指针,python中使用bytearrayglRasterPos2i(GLint x,GLint y) # x和y指定绘制的位置glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * data)储存指定窗口大小中的像素,也就是截屏x和y表示起始位置width和height表示长和高format表示颜色模式,同glDrawPixels中的formattype表示数据类型,同glDrawPixels中的typedata在c++中表示存储像素数据的列表,在python中没有此参数,由返回值代替OpenGL中,像素操作的坐标为left bottom坐标,而不是大家所熟悉的left top坐标OpenGL中,屏幕坐标原点在正中央,而不是左上角
用glRasterPos2i,glDrawPixels单独让图片存在
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
import numpy as np
def convert_img():img = Image.open('a.jpg').convert('RGB')arr = np.array(img).tolist()w,h = img.sizebuf = bytearray(w * h * 3)for i in range(h):for j in range(w):ind = w * i + jbuf[ind * 3] = arr[i][j][0]buf[ind * 3 + 1] = arr[i][j][1]buf[ind * 3 + 2] = arr[i][j][2]return buf,w,h
img,w,h = convert_img()
def drawFunc():glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)glRotatef(0.01, 1, 1, 0)vertex = [[[0,0,1],[1,0,1],[1,1,1],[0,1,1]],[[0,0,0],[0,1,0],[1,1,0],[1,0,0]],[[0,1,0],[0,1,1],[1,1,1],[1,1,0]],[[0,0,0],[1,0,0],[1,0,1],[0,0,1]],[[1,0,0],[1,1,0],[1,1,1],[1,0,1]],[[0,0,0],[0,0,1],[0,1,1],[0,1,0]]]for i in range(len(vertex)):glColor3f(65 / 255,105 / 255,1)glBegin(GL_QUADS)glVertex3f(*vertex[i][0])glVertex3f(*vertex[i][1])glVertex3f(*vertex[i][2])glVertex3f(*vertex[i][3])glEnd()glRasterPos2i(0,0)glDrawPixels(w,h,GL_RGB,GL_UNSIGNED_BYTE,img)glFlush()
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"OpenGL")
glClearColor(0,0,0,0)
glEnable(GL_DEPTH_TEST)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)
glMatrixMode(GL_PROJECTION)
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
glMatrixMode(GL_MODELVIEW)
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
窗口截图功能
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
import numpy as np
def drawFunc():glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)glRotatef(0.01, 1, 1, 0)vertex = [[[0,0,1],[1,0,1],[1,1,1],[0,1,1]],[[0,0,0],[0,1,0],[1,1,0],[1,0,0]],[[0,1,0],[0,1,1],[1,1,1],[1,1,0]],[[0,0,0],[1,0,0],[1,0,1],[0,0,1]],[[1,0,0],[1,1,0],[1,1,1],[1,0,1]],[[0,0,0],[0,0,1],[0,1,1],[0,1,0]]]for i in range(len(vertex)):glColor3f(65 / 255,105 / 255,1)glBegin(GL_QUADS)glVertex3f(*vertex[i][0])glVertex3f(*vertex[i][1])glVertex3f(*vertex[i][2])glVertex3f(*vertex[i][3])glEnd()glFlush()
def keyboard(key,x,y):if(key == b's'):img = glReadPixels(0,0,400,400,GL_RGB,GL_UNSIGNED_INT)img = Image.fromarray(np.array(img,dtype=np.uint8))img.save('screenshot.jpg')
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"OpenGL")
glClearColor(0,0,0,0)
glEnable(GL_DEPTH_TEST)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)
glMatrixMode(GL_PROJECTION)
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
glMatrixMode(GL_MODELVIEW)
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutKeyboardFunc(keyboard)
glutMainLoop()
颜色拾取:
https://blog.csdn.net/weixin_42954615/article/details/113899170灯光:
https://blog.csdn.net/gamesdev/article/details/12112761https://blog.csdn.net/weixin_42954615/article/details/113901093半透明:
https://blog.csdn.net/weixin_42954615/article/details/114123071其他牛逼操作:
https://blog.csdn.net/xufive/article/details/86565130
加载材质时将
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_DECAL)
替换成
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE)画之前加入
glClearDepth(1.0)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)画之后加入
glDisable(GL_BLEND)即可。
10. VBO概念,原文链接:https://blog.csdn.net/xufive/article/details/86565130
# 六面体数据
# ------------------------------------------------------
# v4----- v5
# /| /|
# v0------v1|
# | | | |
# | v7----|-v6
# |/ |/
# v3------v2import numpy as np
# 顶点集
vertices = np.array([-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, # v0-v1-v2-v3-0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5 # v4-v5-v6-v7
], dtype=np.float32)# 索引集
indices = np.array([0, 1, 2, 3, # v0-v1-v2-v3 (front)4, 5, 1, 0, # v4-v5-v1-v0 (top)3, 2, 6, 7, # v3-v2-v6-v7 (bottom)5, 4, 7, 6, # v5-v4-v7-v6 (back)1, 5, 6, 2, # v1-v5-v6-v2 (right)4, 0, 3, 7 # v4-v0-v3-v7 (left)
], dtype=np.int)# 那么在GPU上创建的VBO就如下所示
from OpenGL.arrays import vbovbo_vertices = vbo.VBO(vertices)
vbo_indices = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)创建 顶点 VBO 时,默认 target=GL_ARRAY_BUFFER, 而创建索引 VBO 时,target=GL_ELEMENT_ARRAY_BUFFER,
因为顶点的数据类型是 np.float32,索引的数据类型是np.int。其他的不想写了,去看博客
11. OpenGL和pygame的一次示例
import pygame
from pygame.locals import *from OpenGL.GL import *
from OpenGL.GLU import *verticies = ( # 顶点坐标 瞎写的(2, 0, 0),(0, 1, 0),(0, 1, 1),(0, 0, 1)
)edges = ( # 边的顺序(0, 1),(0, 2),(0, 3),(1, 2),(2, 3),(3, 1)
)def Cube():glColor3f(1.0, 0.0, 0.0) # 设置颜色glBegin(GL_LINES) # glBegin和glEnd()是绘图的必备函数for edge in edges:for vertex in edge:glVertex3fv(verticies[vertex]) # 这个函数就是连点,这个函数执行两次画一条线,两点确定一条直线,参数为三维的坐标glEnd()def main():pygame.init()display = (800, 600)pygame.display.set_mode(display, DOUBLEBUF | OPENGL)glClearColor(1.0, 1.0, 1.0, 1.0) # 设置背景颜色gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)# Z轴就是我们眼睛到屏幕方向的轴,负是远,正是近,其实就是让物体相对与屏幕在XYZ各方向移动几个距离glTranslatef(0, 0, -5)while True:for event in pygame.event.get():if event.type == pygame.QUIT: # 退出事件响应pygame.quit()quit()glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 用来删除就得画面,清空画布Cube() # 创建模型glRotatef(1, 0, 1, 1) # 旋转矩阵pygame.display.flip() # 显示画面pygame.time.wait(10) # 10ms刷新一次main()
12. PyQT和OpenGL的一次示例
import sys
# from PyQt6.QtOpenGLWidgets import QOpenGLWidget
# from PyQt6.QtWidgets import QApplication
# from PyQt6.QtGui import QIcon
# from PyQt6.QtCore import Qt, QPointfrom PySide2.QtOpenGL import QGLWidget
# from PySide2.QtOpenGLWidgets import QOpenGLWidget
from PySide2.QtWidgets import QApplication
from PySide2.QtGui import QIcon
from PySide2.QtCore import Qt, QPointimport numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *class MyGLWidget(QGLWidget):"""从QOpenGLWidget类派生的桌面应用程序窗口类"""def __init__(self):"""构造函数"""super(MyGLWidget, self).__init__()self.setWindowTitle('集成OpenGL')self.setWindowIcon(QIcon('res/qt.png'))self.resize(800, 600)self.show()def initializeGL(self):"""重写GL初始化函数"""glClearColor(0.0, 0.0, 0.2, 1.0) # 设置画布背景色glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系glDepthFunc(GL_LEQUAL) # 设置深度测试函数self.oecs = [0.0, 0.0, 0.0] # 视点坐标系原点self.cam_pos = [0.0, 0.0, 5.0] # 相机位置self.cam_up = [0.0, 1.0, 0.0] # 指向上方的向量self.dist = 5.0 # 相机距离视点坐标系原点的距离self.azim = 0.0 # 初始方位角self.elev = 0.0 # 初始高度角self.leftdown = False # 鼠标左键按下self.mpos = QPoint(0, 0) # 鼠标位置def paintGL(self):"""重写绘制函数"""# 根据窗口宽高计算视锥体k = self.csize[0] / self.csize[1]view = (-k, k, -1, 1, 3, 10) if k > 1 else (-1, 1, -1 / k, 1 / k, 3, 10)glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 清除屏幕及深度缓存glViewport(0, 0, *self.csize) # 设置视口# 设置投影(透视投影)glMatrixMode(GL_PROJECTION)glLoadIdentity()glFrustum(*view)# 设置视点gluLookAt(*self.cam_pos, *self.oecs, *self.cam_up)# 六面体顶点编号示意图# v4----- v7# /| /|# v0------v3|# | | | |# | v5----|-v6# |/ |/# v1------v2# 六面体顶点集vertices = [[-1, 1, 1], [-1, -1, 1], [1, -1, 1], [1, 1, 1], # v0-v1-v2-v3[-1, 1, -1], [-1, -1, -1], [1, -1, -1], [1, 1, -1] # v4-v5-v6-v7]# 顶点集对用的颜色colors = [[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8], [1, 1, 0.2], # v0-v1-v2-v3[1, 0.2, 1], [0.2, 1, 1], [0.5, 1, 0], [0, 1, 0.5] # v4-v5-v6-v7]# 顶点构成四边形的索引集indices = [0, 1, 2, 3, # v0-v1-v2-v3 (front)4, 0, 3, 7, # v4-v0-v3-v7 (top)1, 5, 6, 2, # v1-v5-v6-v2 (bottom)7, 6, 5, 4, # v7-v6-v5-v4 (back)3, 2, 6, 7, # v3-v2-v6-v7 (right)4, 5, 1, 0 # v4-v5-v1-v0 (left)]glBegin(GL_QUADS) # 开始绘制四角面for i in indices:glColor3f(*colors[i])glVertex3f(*vertices[i])glEnd() # 结束绘制四角面def resizeGL(self, width, height):"""重写改变窗口事件函数"""self.csize = (width, height)def mousePressEvent(self, evt):"""重写鼠标按键被按下事件函数"""if evt.buttons() == Qt.MouseButton.LeftButton:self.leftdown = Trueself.mpos = evt.position()def mouseReleaseEvent(self, evt):"""重写鼠标按键被释放事件函数"""if evt.buttons() == Qt.MouseButton.LeftButton:self.leftdown = Falsedef mouseMoveEvent(self, evt):"""重写鼠标移动事件函数"""if self.leftdown:pos = evt.position()dx, dy = pos.x() - self.mpos.x(), pos.y() - self.mpos.y()self.mpos = posazim = self.azim - self.cam_up[1] * (180 * dx / self.csize[0])elev = self.elev + 90 * dy / self.csize[1]self.update_cam_and_up(azim=azim, elev=elev)self.update()def wheelEvent(self, evt):"""重写鼠标滚轮事件函数"""if evt.angleDelta().y() < 0:dist = self.dist * 1.02else:dist = self.dist * 0.98self.update_cam_and_up(dist=dist)self.update()def update_cam_and_up(self, dist=None, azim=None, elev=None):"""根据相机与ECS原点的距离、方位角、仰角等参数,重新计算相机位置和up向量"""if not dist is None:self.dist = distif not azim is None:self.azim = (azim + 180) % 360 - 180if not elev is None:self.elev = (elev + 180) % 360 - 180azim, elev = np.radians(self.azim), np.radians(self.elev)d = self.dist * np.cos(elev)self.cam_pos[1] = self.dist * np.sin(elev) + self.oecs[1]self.cam_pos[2] = d * np.cos(azim) + self.oecs[2]self.cam_pos[0] = d * np.sin(azim) + self.oecs[0]self.cam_up[1] = 1.0 if -90 <= self.elev <= 90 else -1.0if __name__ == '__main__':app = QApplication(sys.argv)win = MyGLWidget()sys.exit(app.exec_())
13. wxPython(类似于QT)和OpenGL的一次示例
# -*- coding: utf-8 -*-import wx
from triangle import *APP_TITLE = u'架起沟通 wxPython 和 pyOpenGL 的桥梁'class mainFrame(wx.Frame):"""程序主窗口类,继承自wx.Frame"""def __init__(self):"""构造函数"""wx.Frame.__init__(self, None, -1, APP_TITLE, style=wx.DEFAULT_FRAME_STYLE)self.SetBackgroundColour(wx.Colour(224, 224, 224))self.SetSize((800, 600))self.Center()self.scene = WxGLScene(self)class mainApp(wx.App):def OnInit(self):self.SetAppName(APP_TITLE)self.Frame = mainFrame()self.Frame.Show()return Trueif __name__ == "__main__":app = mainApp()app.MainLoop()
# -*- coding: utf-8 -*-import wx
from wx import glcanvas
from OpenGL.GL import *
from OpenGL.GLU import *class WxGLScene(glcanvas.GLCanvas):"""GL场景类"""def __init__(self, parent, eye=[0, 0, 5], aim=[0, 0, 0], up=[0, 1, 0], view=[-1, 1, -1, 1, 3.5, 10]):"""构造函数parent - 父级窗口对象eye - 观察者的位置(默认z轴的正方向)up - 对观察者而言的上方(默认y轴的正方向)view - 视景体"""glcanvas.GLCanvas.__init__(self, parent, -1,style=glcanvas.WX_GL_RGBA | glcanvas.WX_GL_DOUBLEBUFFER | glcanvas.WX_GL_DEPTH_SIZE)self.parent = parent # 父级窗口对象self.eye = eye # 观察者的位置self.aim = aim # 观察目标(默认在坐标原点)self.up = up # 对观察者而言的上方self.view = view # 视景体self.size = self.GetClientSize() # OpenGL窗口的大小self.context = glcanvas.GLContext(self) # OpenGL上下文self.zoom = 1.0 # 视口缩放因子self.mpos = None # 鼠标位置self.initGL() # 画布初始化self.Bind(wx.EVT_SIZE, self.onResize) # 绑定窗口尺寸改变事件self.Bind(wx.EVT_ERASE_BACKGROUND, self.onErase) # 绑定背景擦除事件self.Bind(wx.EVT_PAINT, self.onPaint) # 绑定重绘事件self.Bind(wx.EVT_LEFT_DOWN, self.onLeftDown) # 绑定鼠标左键按下事件self.Bind(wx.EVT_LEFT_UP, self.onLeftUp) # 绑定鼠标左键弹起事件self.Bind(wx.EVT_RIGHT_UP, self.onRightUp) # 绑定鼠标右键弹起事件self.Bind(wx.EVT_MOTION, self.onMouseMotion) # 绑定鼠标移动事件self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel) # 绑定鼠标滚轮事件def onResize(self, evt):"""响应窗口尺寸改变事件"""if self.context:self.SetCurrent(self.context)self.size = self.GetClientSize()self.Refresh(False)evt.Skip()def onErase(self, evt):"""响应背景擦除事件"""passdef onPaint(self, evt):"""响应重绘事件"""self.SetCurrent(self.context)glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 清除屏幕及深度缓存self.drawGL() # 绘图self.SwapBuffers() # 切换缓冲区,以显示绘制内容evt.Skip()def onLeftDown(self, evt):"""响应鼠标左键按下事件"""self.CaptureMouse()self.mpos = evt.GetPosition()def onLeftUp(self, evt):"""响应鼠标左键弹起事件"""try:self.ReleaseMouse()except:passdef onRightUp(self, evt):"""响应鼠标右键弹起事件"""passdef onMouseMotion(self, evt):"""响应鼠标移动事件"""if evt.Dragging() and evt.LeftIsDown():pos = evt.GetPosition()try:dx, dy = pos - self.mposexcept:returnself.mpos = pos# 限于篇幅省略改变观察者位置的代码self.Refresh(False)def onMouseWheel(self, evt):"""响应鼠标滚轮事件"""if evt.WheelRotation < 0:self.zoom *= 1.1if self.zoom > 100:self.zoom = 100elif evt.WheelRotation > 0:self.zoom *= 0.9if self.zoom < 0.01:self.zoom = 0.01self.Refresh(False)def initGL(self):"""初始化GL"""self.SetCurrent(self.context)glClearColor(0, 0, 0, 0) # 设置画布背景色glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系glDepthFunc(GL_LEQUAL) # 设置深度测试函数glShadeModel(GL_SMOOTH) # GL_SMOOTH(光滑着色)/GL_FLAT(恒定着色)glEnable(GL_BLEND) # 开启混合glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # 设置混合函数glEnable(GL_ALPHA_TEST) # 启用Alpha测试glAlphaFunc(GL_GREATER, 0.05) # 设置Alpha测试条件为大于0.05则通过glFrontFace(GL_CW) # 设置逆时针索引为正面(GL_CCW/GL_CW)glEnable(GL_LINE_SMOOTH) # 开启线段反走样glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)def drawGL(self):"""绘制"""# 清除屏幕及深度缓存glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)# 设置视口glViewport(0, 0, self.size[0], self.size[1])# 设置投影(透视投影)glMatrixMode(GL_PROJECTION)glLoadIdentity()k = self.size[0] / self.size[1]if k > 1:glFrustum(self.zoom * self.view[0] * k,self.zoom * self.view[1] * k,self.zoom * self.view[2],self.zoom * self.view[3],self.view[4], self.view[5])else:glFrustum(self.zoom * self.view[0],self.zoom * self.view[1],self.zoom * self.view[2] / k,self.zoom * self.view[3] / k,self.view[4], self.view[5])# 设置视点gluLookAt(self.eye[0], self.eye[1], self.eye[2],self.aim[0], self.aim[1], self.aim[2],self.up[0], self.up[1], self.up[2])# 设置模型视图glMatrixMode(GL_MODELVIEW)glLoadIdentity()# ---------------------------------------------------------------glBegin(GL_LINES) # 开始绘制线段(世界坐标系)# 以红色绘制x轴glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点(x轴负方向)glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点(x轴正方向)# 以绿色绘制y轴glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点(y轴负方向)glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点(y轴正方向)# 以蓝色绘制z轴glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点(z轴负方向)glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点(z轴正方向)glEnd() # 结束绘制线段# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴负半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点glEnd() # 结束绘制三角形# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴正半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.5, 0.5, 0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.5, 0.5, 0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, -0.366, 0.5) # 设置三角形顶点glEnd() # 结束绘制三角形
甜甜圈材质光影示例
import wxgl.glplot as gltglt.title('快速体验:$x^2+y^2+z^2=1$')
glt.uvsphere((0,0,0), 1, color='cyan')
glt.show()import wxgl
import wxgl.glplot as gltglt.subplot(121)
glt.title('经纬度网格生成球体')
glt.uvsphere((0,0,0), 1, texture=wxgl.Texture('e0.jpg'))
glt.grid()glt.subplot(122)
glt.title('正八面体迭代细分生成球体')
glt.isosphere((0,0,0), 1, color=(0,1,1), fill=False, iterations=5)
glt.grid()glt.show()import numpy as np
import wxgl.glplot as gltvs = np.random.random((300, 3))*2-1
color = np.random.random(300)
size = np.linalg.norm(vs, axis=1)
size = 30 * (size - size.min()) / (size.max() - size.min())glt.title('随机生成的300个点')
glt.point(vs, color, cm='jet', alpha=0.8, size=size)
glt.colorbar('jet', [0, 100], loc='right', subject='高度')
glt.colorbar('Paired', [-50, 50], loc='bottom', subject='温度', margin_left=5)
glt.colorbar('rainbow', [0, 240], loc='bottom', subject='速度', margin_right=5)
glt.show()import wxgl
import wxgl.glplot as gltglt.subplot(221)
glt.title('太阳光')
glt.torus((0,0,0), 1, 3, vec=(0,1,1), light=wxgl.SunLight(roughness=0, metalness=0, shininess=0.5))glt.subplot(222)
glt.title('灯光')
pos = (1, 0.0, 3)
glt.torus((0,0,0), 1, 3, vec=(0,1,1), light=wxgl.LampLight(position=pos))
glt.point((pos,), color='red', size=30)glt.subplot(223)
glt.title('户外光')
glt.torus((0,0,0), 1, 3, vec=(0,1,1), light=wxgl.SkyLight(sky=(1.0,1.0,1.0)))glt.subplot(224)
glt.title('球谐光')
glt.torus((0,0,0), 1, 3, vec=(0,1,1), light=wxgl.SphereLight(5, factor=0.8))glt.show()import wxgl
import wxgl.glplot as glttf = lambda duration : ((0, 1, 0, (0.02*duration)%360),)
cf = lambda duration : {'azim':(-0.02*duration)%360}tx = wxgl.Texture('e0.jpg')
light = wxgl.SunLight(direction=(1,0,-1))glt.subplot(121)
glt.title('模型旋转')
glt.cylinder((0,1,0), (0,-1,0), 1, texture=tx, transform=tf, light=light)glt.subplot(122)
glt.cruise(cf)
glt.title('相机旋转')
glt.cylinder((0,1,0), (0,-1,0), 1, texture=tx, light=light)glt.show()import wxgl
import wxgl.glplot as gltvshader = """#version 330 corein vec4 a_Position;in vec4 a_Color;uniform mat4 u_ProjMatrix;uniform mat4 u_ViewMatrix;uniform mat4 u_ModelMatrix;out vec4 v_Color;void main() {gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;v_Color = a_Color;}
"""fshader = """#version 330 corein vec4 v_Color;void main() {gl_FragColor = v_Color;}
"""m = wxgl.Model(wxgl.TRIANGLE_STRIP, vshader, fshader) # 实例化模型,设置绘图方法和着色器源码
m.set_vertex('a_Position', [[-1,1,0],[-1,-1,0],[1,1,0],[1,-1,0]]) # 4个顶点坐标
m.set_color('a_Color', [[1,0,0],[0,1,0],[0,0,1],[0,1,1]]) # 4个顶点的颜色
m.set_proj_matrix('u_ProjMatrix') # 设置投影矩阵
m.set_view_matrix('u_ViewMatrix') # 设置视点矩阵
m.set_model_matrix('u_ModelMatrix') # 设置模型矩阵
a = wxgl.glplot.text3d((1,1,1))glt.model(a)
glt.model(m) # 添加模型到画布
glt.show() # 显示画布
14. VBO详解
这段代码不能运行
# 六面体数据
# ------------------------------------------------------
# v4----- v5
# /| /|
# v0------v1|
# | | | |
# | v7----|-v6
# |/ |/
# v3------v2# 顶点集
vertices = np.array([-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, # v0-v1-v2-v3-0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5 # v4-v5-v6-v7
], dtype=np.float32)# 索引集
indices = np.array([0, 1, 2, 3, # v0-v1-v2-v3 (front)4, 5, 1, 0, # v4-v5-v1-v0 (top)3, 2, 6, 7, # v3-v2-v6-v7 (bottom)5, 4, 7, 6, # v5-v4-v7-v6 (back)1, 5, 6, 2, # v1-v5-v6-v2 (right)4, 0, 3, 7 # v4-v0-v3-v7 (left)
], dtype=np.int)from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *# 在CPU上创建VBO
from OpenGL.arrays import vbo
vbo_vertices = vbo.VBO(vertices)
vbo_indices = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)# 创建 顶点 VBO 时,默认 target=GL_ARRAY_BUFFER, 而创建索引 VBO 时,target=GL_ELEMENT_ARRAY_BUFFER,
# 因为顶点的数据类型是 np.float32,索引的数据类型是np.int。
# 在VBO保存的顶点数据集,除了顶点信息外,还可以包含颜色、法线、纹理等数据,这就是顶点混合数组的概念。
# 假定我们在上面的顶点集中增加每个顶点的颜色,则可以写成这样:
vertices = np.array([0.3, 0.6, 0.9, -0.35, 0.35, 0.35, # c0-v00.6, 0.9, 0.3, 0.35, 0.35, 0.35, # c1-v10.9, 0.3, 0.6, 0.35, -0.35, 0.35, # c2-v20.3, 0.9, 0.6, -0.35, -0.35, 0.35, # c3-v30.6, 0.3, 0.9, -0.35, 0.35, -0.35, # c4-v40.9, 0.6, 0.3, 0.35, 0.35, -0.35, # c5-v50.3, 0.9, 0.9, 0.35, -0.35, -0.35, # c6-v60.9, 0.9, 0.3, -0.35, -0.35, -0.35 # c7-v7
], dtype=np.float32)# 分离顶点混合数组
# 使用 glInterleavedArrays() 函数可以从顶点混合数组中分离顶点、颜色、法线和纹理,它一共有11个参数
# 比如,对只包含顶点信息的顶点混合数组:
vbo_indices.bind()
glInterleavedArrays(GL_V3F, 0, None)# glInterleavedArrays(),它里面的参数如下所示,很好记,例如GL_C3F_V3F,就是3个浮点数作为颜色(C),3个浮点数作为顶点(T)# 其中T表示纹理坐标,C表示颜色,N表示法线向量,V表示顶点坐标# GL_V2F# GL_V3F# GL_C4UB_V2F# GL_C4UB_V3F# GL_C3F_V3F# GL_N3F_V3F# GL_C4F_N3F_V3F# GL_T2F_V3F# GL_T4F_V4F# GL_T2F_C4UB_V3F# GL_T2F_C3F_V3F# GL_T2F_N3F_V3F# GL_T2F_C4F_N3F_V3F# GL_T4F_C4F_N3F_V4F# 如果顶点混合数组包含了颜色和顶点信息:
vbo_indices.bind()
glInterleavedArrays(GL_C3F_V3F, 0, None)# 这是一个完整的过程,but运行不了,shit
vbo_indices.bind()
glInterleavedArrays(GL_V3F, 0, None)
vbo_indices.bind()
glDrawElements(GL_QUADS, int(vbo_indices .size/4), GL_UNSIGNED_INT, None)
vbo_indices.unbind()
vbo_indices.unbind()
一次真正的操作(不能运行)
# 第一步,导入库
from OpenGL.GL import *
from OpenGL.arrays import vbo
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as np# 第二步,创建顶点缓冲区对象
# 顶点集
vertices = np.array([-0.5, 0.5, 0.5,0.5, 0.5, 0.5,0.5, -0.5, 0.5,-0.5, -0.5, 0.5,-0.5, 0.5, -0.5,0.5, 0.5, -0.5,0.5, -0.5, -0.5,-0.5, -0.5, -0.5
], 'f')# 索引集
indices = np.array([0, 1, 2, 3,4, 5, 1, 0,3, 2, 6, 7,5, 4, 7, 6,1, 5, 6, 2,4, 0, 3, 7
], 'H')
# numpy数组类型很重要,否则你用不正确的数组绘图就会一片空白(本人真实经历)
# 在这里我解释一下索引集的作用:正方体有6个面,4个点构成一个面,则有24个点,但有16个点是重复的,索引值的作用类似于字串符的索引,
# 你可以把顶点集的一组数据看做一个字符,索引值的每一个值为索引(我讲的有点乱,但知道字串符索引应该理解),把那些数据按索引传到GPU,减小了顶点集占的空间。
# 接下来我们要把这些数据传到GPU上,方法如下:
# 原文链接:https://blog.csdn.net/Css2432lxp/article/details/125749334# 第三步
def cube():...vbo1.bind()glInterleavedArrays(GL_V3F, 0, None)vbo2.bind()glDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, None)# 第四步,绘图
def draw():glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)cube()glutSwapBuffers()...glutDisplayFunc(draw)
能运行的代码来了
from OpenGL.GL import *
from OpenGL.arrays import vbo
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as npdef cube():vertices = np.array([-0.5, 0.5, 0.5,0.5, 0.5, 0.5,0.5, -0.5, 0.5,-0.5, -0.5, 0.5,-0.5, 0.5, -0.5,0.5, 0.5, -0.5,0.5, -0.5, -0.5,-0.5, -0.5, -0.5], 'f')indices = np.array([0, 1, 2, 3,4, 5, 1, 0,3, 2, 6, 7,5, 4, 7, 6,1, 5, 6, 2,4, 0, 3, 7], 'H')vbo1 = vbo.VBO(vertices)vbo2 = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)eboLength = len(indices)vbo1.bind()glInterleavedArrays(GL_V3F, 0, None)vbo2.bind()glDrawElements(GL_QUADS, eboLength, GL_UNSIGNED_SHORT, None)vbo2.unbind()vbo1.unbind()def Draw():glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)cube()glutSwapBuffers()glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)glutInitWindowSize(600, 600)
glutInitWindowPosition(300, 200)
glutCreateWindow('cube')glClearColor(0.0, 0.0, 0.0, 1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)glutDisplayFunc(Draw)glutMainLoop()
如果要让顶点有颜色,得这么写
vertices = np.array([Red,Green,Blue,X,Z,Y])#前三个是颜色,后三个是顶点坐标,栗子如下
def cube(): vertices = np.array([0.3, 0.6, 0.9, -0.5, 0.5, 0.5, 0.6, 0.9, 0.3, 0.5, 0.5, 0.5, 0.9, 0.3, 0.6, 0.5, -0.5, 0.5, 0.3, 0.9, 0.6, -0.5, -0.5, 0.5, 0.6, 0.3, 0.9, -0.5, 0.5, -0.5, 0.9, 0.6, 0.3, 0.5, 0.5, -0.5, 0.3, 0.9, 0.9, 0.5, -0.5, -0.5, 0.9, 0.9, 0.3, -0.5, -0.5, -0.5 ],'f')indices = np.array([0, 1, 2, 3, 4, 5, 1, 0,3, 2, 6, 7,5, 4, 7, 6,1, 5, 6, 2, 4, 0, 3, 7 ],'H')# 写完顶点,还要分离数组,so,如下
def cube_split():#传入顶点数据还是一样vbo1.bind()glInterleavedArrays(GL_C3F_V3F,0,None)vbo2.bind()glDrawElements(GL_QUADS,eboLength,GL_UNSIGNED_SHORT,None)
下面这个栗子不能实现转动效果
from OpenGL.GL import *
from OpenGL.arrays import vbo
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as npdef cube():vertices = np.array([0.3, 0.6, 0.9, -0.5, 0.5, 0.5,0.6, 0.9, 0.3, 0.5, 0.5, 0.5,0.9, 0.3, 0.6, 0.5, -0.5, 0.5,0.3, 0.9, 0.6, -0.5, -0.5, 0.5,0.6, 0.3, 0.9, -0.5, 0.5, -0.5,0.9, 0.6, 0.3, 0.5, 0.5, -0.5,0.3, 0.9, 0.9, 0.5, -0.5, -0.5,0.9, 0.9, 0.3, -0.5, -0.5, -0.5], 'f')indices = np.array([0, 1, 2, 3,4, 5, 1, 0,3, 2, 6, 7,5, 4, 7, 6,1, 5, 6, 2,4, 0, 3, 7], 'H')vbo1 = vbo.VBO(vertices)vbo2 = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)eboLength = len(indices)vbo1.bind()glInterleavedArrays(GL_C3F_V3F, 0, None)vbo2.bind()glDrawElements(GL_QUADS, eboLength, GL_UNSIGNED_SHORT, None)vbo2.unbind()vbo1.unbind()def Draw():glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)cube()glutSwapBuffers()glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)glutInitWindowSize(600, 600)
glutInitWindowPosition(300, 200)
glutCreateWindow('cube')glClearColor(0.0, 0.0, 0.0, 1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)glutDisplayFunc(Draw)glutMainLoop()
这个例子可以实现转动效果
# -*- coding: utf-8 -*-# -------------------------------------------
# quidam_02.py 旋转、缩放、改变视点和参考点
# -------------------------------------------from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as np
from OpenGL.arrays import vboIS_PERSPECTIVE = True # 透视投影
VIEW = np.array([-0.8, 0.8, -0.8, 0.8, 1.0, 200.0]) # 视景体的left/right/bottom/top/near/far六个面
SCALE_K = np.array([1.0, 1.0, 1.0]) # 模型缩放比例
EYE = np.array([0.0, 2.0, 0.0]) # 眼睛的位置(默认z轴的正方向)
LOOK_AT = np.array([0.0, 0.0, 0.0]) # 瞄准方向的参考点(默认在坐标原点)
EYE_UP = np.array([0.0, 1.0, 0.0]) # 定义对观察者而言的上方(默认y轴的正方向)
WIN_W, WIN_H = 640, 480 # 保存窗口宽度和高度的变量
LEFT_IS_DOWNED = False # 鼠标左键被按下
MOUSE_X, MOUSE_Y = 0, 0 # 考察鼠标位移量时保存的起始位置# 计算窗体的中绘图的位置
def getposture():global EYE, LOOK_ATdist = np.sqrt(np.power((EYE - LOOK_AT), 2).sum()) # 计算平方,然后再开平方根print(dist)if dist > 0:phi = np.arcsin((EYE[1] - LOOK_AT[1]) / dist) # 用dist的反正弦值除以它theta = np.arcsin((EYE[0] - LOOK_AT[0]) / (dist * np.cos(phi)))else:phi = 0.0theta = 0.0return dist, phi, thetaDIST, PHI, THETA = getposture() # 眼睛与观察目标之间的距离、仰角、方位角# 初始化函数
def init():glClearColor(0.0, 0.0, 0.0, 1.0) # 设置画布背景色,RGBA,最大值为1glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系glDepthFunc(GL_LEQUAL) # 设置深度测试函数(GL_LEQUAL只是选项之一)# 先设置cube函数,在设置绘图draw()函数之前
def cube():vertices = np.array([0.3, 0.6, 0.9, -0.5, 0.5, 0.5, # c0-v00.6, 0.9, 0.3, 0.5, 0.5, 0.5, # c1-v10.9, 0.3, 0.6, 0.5, -0.5, 0.5, # c2-v20.3, 0.9, 0.6, -0.5, -0.5, 0.5, # c3-v30.6, 0.3, 0.9, -0.5, 0.5, -0.5, # c4-v40.9, 0.6, 0.3, 0.5, 0.5, -0.5, # c5-v50.3, 0.9, 0.9, 0.5, -0.5, -0.5, # c6-v60.9, 0.9, 0.3, -0.5, -0.5, -0.5 # c7-v7], 'f')indices = np.array([0, 1, 2, 3, # v0-v1-v2-v3 (front)4, 5, 1, 0, # v4-v5-v1-v0 (top)3, 2, 6, 7, # v3-v2-v6-v7 (bottom)5, 4, 7, 6, # v5-v4-v7-v6 (back)1, 5, 6, 2, # v1-v5-v6-v2 (right)4, 0, 3, 7 # v4-v0-v3-v7 (left)], 'H')vbo_vertices = vbo.VBO(vertices)vbo_indices = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)eboLength = len(indices)vbo_vertices.bind()glInterleavedArrays(GL_C3F_V3F, 0, None)vbo_indices.bind()glDrawElements(GL_QUADS, eboLength, GL_UNSIGNED_SHORT, None)vbo_indices.unbind()vbo_vertices.unbind()# 绘图函数
def Draw():glMatrixMode(GL_PROJECTION)glLoadIdentity()if WIN_W > WIN_H:if IS_PERSPECTIVE:glFrustum(VIEW[0] * WIN_W / WIN_H, VIEW[1] * WIN_W / WIN_H, VIEW[2], VIEW[3], VIEW[4], VIEW[5])else:glOrtho(VIEW[0] * WIN_W / WIN_H, VIEW[1] * WIN_W / WIN_H, VIEW[2], VIEW[3], VIEW[4], VIEW[5])else:if IS_PERSPECTIVE:glFrustum(VIEW[0], VIEW[1], VIEW[2] * WIN_H / WIN_W, VIEW[3] * WIN_H / WIN_W, VIEW[4], VIEW[5])else:glOrtho(VIEW[0], VIEW[1], VIEW[2] * WIN_H / WIN_W, VIEW[3] * WIN_H / WIN_W, VIEW[4], VIEW[5])# 设置模型视图glMatrixMode(GL_MODELVIEW)glLoadIdentity()# 几何变换glScale(SCALE_K[0], SCALE_K[1], SCALE_K[2])# 设置视点gluLookAt(EYE[0], EYE[1], EYE[2],LOOK_AT[0], LOOK_AT[1], LOOK_AT[2],EYE_UP[0], EYE_UP[1], EYE_UP[2])# 设置视口glViewport(0, 0, WIN_W, WIN_H)glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)cube()glutSwapBuffers()def reshape(width, height):global WIN_W, WIN_HWIN_W, WIN_H = width, heightglutPostRedisplay() # 回调函数,当当前窗体没有变动时,释放CPU资源,有变动就让CPU去再渲染一边def get_data():THz_data = np.load('青源峰达已降噪.npy') # 获取青源峰达数据x,y,z = THz_data.shape # 获取三个维度的值 73,62,9000xss = [] # 创建空列表,用来在循环中获取每一列的数据,也就是x=0时,所有的yxy_list = [] # 用来把每一列数据进行储存,方便绘图for i in range(x): # 通过计算矩阵大小,来计算出每个点对应的矩阵位置for j in range(y):a = (i, j, 0)xss.append(a)xy_list.append(xss)xss = []# print(len(xy_list))# print(xy_list[1])return xy_list# 检测鼠标左键状态和滚轮状态
def mouseclick(button, state, x, y):global SCALE_K # 声明改变压缩比例global LEFT_IS_DOWNED # 声明要改变鼠标状态global MOUSE_X, MOUSE_Y # 声明改变鼠标位置MOUSE_X, MOUSE_Y = x, yif button == GLUT_LEFT_BUTTON: # 如果鼠标左键被按下LEFT_IS_DOWNED = state == GLUT_DOWN # 改变鼠标左键状态elif button == 3: # 滚轮往上滑的时候SCALE_K *= 1.05glutPostRedisplay() # 通知OpenGL开工渲染一次elif button == 4: # 滚轮往下滑的时候,这个地方有点问题SCALE_K *= 0.95glutPostRedisplay()# 如果鼠标在界面上移动了,
def mousemotion(x, y):global LEFT_IS_DOWNEDglobal EYE, EYE_UPglobal MOUSE_X, MOUSE_Yglobal DIST, PHI, THETA # 眼睛与目标之间的距离,仰角,方位角global WIN_W, WIN_Hif LEFT_IS_DOWNED: # 如果鼠标左键被按下为真,也就是说,按下了这段代码才会被执行dx = MOUSE_X - x # MOUSE_X是鼠标此时在屏幕上的位置,x是鼠标按下之后在屏幕上的位置dy = y - MOUSE_YMOUSE_X, MOUSE_Y = x, y # 重新给x,y赋值,赋值为当前鼠标在界面上的悬浮位置# 通过计算来确定在界面中y轴的方向PHI += 2 * np.pi * dy / WIN_HPHI %= 2 * np.piTHETA += 2 * np.pi * dx / WIN_WTHETA %= 2 * np.pir = DIST * np.cos(PHI)EYE[1] = DIST * np.sin(PHI)EYE[0] = r * np.sin(THETA)EYE[2] = r * np.cos(THETA)if 0.5 * np.pi < PHI < 1.5 * np.pi:EYE_UP[1] = -1.0else:EYE_UP[1] = 1.0glutPostRedisplay() # 通知刷新# 用来检测键盘的动态
def keydown(key, x, y):global DIST, PHI, THETAglobal EYE, LOOK_AT, EYE_UPglobal IS_PERSPECTIVE, VIEWif key in [b'x', b'X', b'y', b'Y', b'z', b'Z']:if key == b'x': # 瞄准参考点 x 减小LOOK_AT[0] -= 0.01elif key == b'X': # 瞄准参考 x 增大LOOK_AT[0] += 0.01elif key == b'y': # 瞄准参考点 y 减小LOOK_AT[1] -= 0.01elif key == b'Y': # 瞄准参考点 y 增大LOOK_AT[1] += 0.01elif key == b'z': # 瞄准参考点 z 减小LOOK_AT[2] -= 0.01elif key == b'Z': # 瞄准参考点 z 增大LOOK_AT[2] += 0.01DIST, PHI, THETA = getposture()glutPostRedisplay()elif key == b'\r': # 回车键,视点前进EYE = LOOK_AT + (EYE - LOOK_AT) * 0.9DIST, PHI, THETA = getposture()glutPostRedisplay()elif key == b'\x08': # 退格键,视点后退EYE = LOOK_AT + (EYE - LOOK_AT) * 1.1DIST, PHI, THETA = getposture()glutPostRedisplay()elif key == b' ': # 空格键,切换投影模式IS_PERSPECTIVE = not IS_PERSPECTIVEglutPostRedisplay()if __name__ == "__main__":glutInit()displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTHglutInitDisplayMode(displayMode)glutInitWindowSize(WIN_W, WIN_H)glutInitWindowPosition(300, 200)glutCreateWindow('Quidam Of OpenGL')init() # 初始化画布glutDisplayFunc(Draw) # 注册回调函数draw()glutReshapeFunc(reshape) # 注册响应窗口改变的函数reshape(),监听窗口动态glutMouseFunc(mouseclick) # 注册响应鼠标点击的函数mouseclick()glutMotionFunc(mousemotion) # 注册响应鼠标拖拽的函数mousemotion()glutKeyboardFunc(keydown) # 注册键盘输入的函数keydown()glutMainLoop() # 进入glut主循环
三、一些具体实操
1. 基本的语法
from OpenGL.GL import *
from OpenGL.GLUT import *
def draw():# ---------------------------------------------------------------glBegin(GL_LINES) # 开始绘制线段(世界坐标系)# 以红色绘制x轴glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点(x轴负方向)glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点(x轴正方向)# 以绿色绘制y轴glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点(y轴负方向)glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点(y轴正方向)# 以蓝色绘制z轴glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点(z轴负方向)glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点(z轴正方向)glEnd() # 结束绘制线段# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴负半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点glEnd()# 结束绘制三角形# ---------------------------------------------------------------glFlush() # 清空缓冲区,将指令送往硬件立即执行
if __name__ == "__main__":glutInit() # 1. 初始化glut库glutCreateWindow('Quidam Of OpenGL') # 2. 创建glut窗口glutDisplayFunc(draw) # 3. 注册回调函数draw()glutMainLoop() # 4. 进入glut主循环
2. 旋转的线条小茶壶示例,也是官方示例:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *def drawFunc():# 清楚之前画面glClear(GL_COLOR_BUFFER_BIT)# 让模型转起来glRotatef(0.05, 20, 5, 0) # 旋转速度,剩下三个是它的x,y,z的倾斜角度# 模型的大小glutWireTeapot(0.5)# 刷新显示glFlush()# 使用glut初始化OpenGL
glutInit()
# 显示模式:GLUT_SINGLE无缓冲直接显示|GLUT_RGBA采用RGB(A非alpha)
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
# 窗口位置及大小-生成
# 窗口的弹出位置
glutInitWindowPosition(0, 0)
# 窗口的尺寸
glutInitWindowSize(400, 400)
# 窗口的标题名称
glutCreateWindow(b"test")
# 调用函数绘制图像glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
# 主循环
glutMainLoop()
3. 小狗绘制
图片在此
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
import math
theta,phi = 0,0
pos = (0,0,0)
def target():global theta,phix = math.sin(theta) * math.cos(phi)y = math.sin(theta) * math.sin(phi)z = math.cos(theta)return x,y,z
def setLookAt():global postar = target()gluLookAt(*pos,*tar,0,1,0)glLoadIdentity()
def drawFunc():setLookAt()glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)vertex = [[[0,0,1],[1,0,1],[1,1,1],[0,1,1]],[[0,0,0],[0,1,0],[1,1,0],[1,0,0]],[[0,1,0],[0,1,1],[1,1,1],[1,1,0]],[[0,0,0],[1,0,0],[1,0,1],[0,0,1]],[[1,0,0],[1,1,0],[1,1,1],[1,0,1]],[[0,0,0],[0,0,1],[0,1,1],[0,1,0]]]for i in range(len(vertex)):glBindTexture(GL_TEXTURE_2D,1)glBegin(GL_QUADS)glTexCoord2f(0.0, 0.0)glVertex3f(*vertex[i][0])glTexCoord2f(1.0, 0.0)glVertex3f(*vertex[i][1])glTexCoord2f(1.0, 1.0)glVertex3f(*vertex[i][2])glTexCoord2f(0.0, 1.0)glVertex3f(*vertex[i][3])glEnd()glFlush()
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow(b"OpenGL")
glClearColor(0,0,0,0)
glEnable(GL_DEPTH_TEST)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glShadeModel(GL_SMOOTH)
# glEnable(GL_CULL_FACE)
# glCullFace(GL_BACK)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)
glMatrixMode(GL_PROJECTION)
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)
glMatrixMode(GL_MODELVIEW)
glEnable(GL_TEXTURE_2D)
img = Image.open('a.jpg')
width, height = img.size
img = img.tobytes('raw','RGB',0,-1)
glGenTextures(2)
glBindTexture(GL_TEXTURE_2D, 1)
glTexImage2D(GL_TEXTURE_2D, 0, 4,width,height, 0, GL_RGB,GL_UNSIGNED_BYTE,img)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_DECAL)
glutDisplayFunc(drawFunc)
glutIdleFunc(drawFunc)
glutMainLoop()
4. 一个三维视景体
# -*- coding: utf-8 -*-# -------------------------------------------
# quidam_02.py 旋转、缩放、改变视点和参考点
# -------------------------------------------from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as npIS_PERSPECTIVE = True # 透视投影
VIEW = np.array([-0.8, 0.8, -0.8, 0.8, 1.0, 200.0]) # 视景体的left/right/bottom/top/near/far六个面
SCALE_K = np.array([1.0, 1.0, 1.0]) # 模型缩放比例
EYE = np.array([0.0, 0.0, 2.0]) # 眼睛的位置(默认z轴的正方向)
LOOK_AT = np.array([0.0, 0.0, 0.0]) # 瞄准方向的参考点(默认在坐标原点)
EYE_UP = np.array([0.0, 1.0, 0.0]) # 定义对观察者而言的上方(默认y轴的正方向)
WIN_W, WIN_H = 640, 480 # 保存窗口宽度和高度的变量
LEFT_IS_DOWNED = False # 鼠标左键被按下
MOUSE_X, MOUSE_Y = 0, 0 # 考察鼠标位移量时保存的起始位置# 计算窗体的中绘图的位置
def getposture():global EYE, LOOK_ATdist = np.sqrt(np.power((EYE - LOOK_AT), 2).sum()) # 计算平方,然后再开平方根print(dist)if dist > 0:phi = np.arcsin((EYE[1] - LOOK_AT[1]) / dist) # 用dist的反正弦值除以它theta = np.arcsin((EYE[0] - LOOK_AT[0]) / (dist * np.cos(phi)))else:phi = 0.0theta = 0.0return dist, phi, thetaDIST, PHI, THETA = getposture() # 眼睛与观察目标之间的距离、仰角、方位角# 初始化函数
def init():glClearColor(0.0, 0.0, 0.0, 1.0) # 设置画布背景色,RGBA,最大值为1glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系glDepthFunc(GL_LEQUAL) # 设置深度测试函数(GL_LEQUAL只是选项之一)# 绘图函数
def draw():global IS_PERSPECTIVE, VIEW # 声明变量,要在局部中改变全局变量的值(此处是赋值)global EYE, LOOK_AT, EYE_UPglobal SCALE_Kglobal WIN_W, WIN_HglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 清除屏幕及深度缓存glMatrixMode(GL_PROJECTION) # 设置投影(透视投影)glLoadIdentity() # 重置当前矩阵为单位矩阵if WIN_W > WIN_H: # 比较窗口的长宽大小if IS_PERSPECTIVE: # 判断如果投射投影为真# 设计视景体的左、右、下、上、近、远的点,一共三个坐标(左下、右上、近远,一共三个坐标点)glFrustum(VIEW[0] * WIN_W / WIN_H, VIEW[1] * WIN_W / WIN_H, VIEW[2], VIEW[3], VIEW[4], VIEW[5])else:# 同上glOrtho(VIEW[0] * WIN_W / WIN_H, VIEW[1] * WIN_W / WIN_H, VIEW[2], VIEW[3], VIEW[4], VIEW[5])else:if IS_PERSPECTIVE:glFrustum(VIEW[0], VIEW[1], VIEW[2] * WIN_H / WIN_W, VIEW[3] * WIN_H / WIN_W, VIEW[4], VIEW[5])else:glOrtho(VIEW[0], VIEW[1], VIEW[2] * WIN_H / WIN_W, VIEW[3] * WIN_H / WIN_W, VIEW[4], VIEW[5])# 这两玩意好像有没有都没啥区别,先dont careglMatrixMode(GL_MODELVIEW) # 设置模型视图glLoadIdentity() # 重置当前矩阵为单位矩阵glScale(SCALE_K[0], SCALE_K[1], SCALE_K[2]) # 几何变换,设置压缩比例!!# 设置视点,定义Z的方向和Y的方向gluLookAt(EYE[0], EYE[1], EYE[2],LOOK_AT[0], LOOK_AT[1], LOOK_AT[2],EYE_UP[0], EYE_UP[1], EYE_UP[2])# 设置视口,告诉OpenGL把图绘制在哪里glViewport(0, 0, WIN_W, WIN_H)# ---------------------------------------------------------------glBegin(GL_LINES) # 开始绘制线段(世界坐标系)# 以红色绘制x轴glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点(x轴负方向)glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点(x轴正方向)# 以绿色绘制y轴glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点(y轴负方向)glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点(y轴正方向)# 以蓝色绘制z轴glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点(z轴负方向)glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点(z轴正方向)glEnd() # 结束绘制线段# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴负半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点glEnd() # 结束绘制三角形# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴正半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.5, 0.5, 0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.5, 0.5, 0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, -0.366, 0.5) # 设置三角形顶点glEnd() # 结束绘制三角形# ---------------------------------------------------------------glutSwapBuffers() # 切换缓冲区,以显示绘制内容# glFlush()def reshape(width, height):global WIN_W, WIN_HWIN_W, WIN_H = width, heightglutPostRedisplay() # 回调函数,当当前窗体没有变动时,释放CPU资源,有变动就让CPU去再渲染一边# 检测鼠标左键状态和滚轮状态
def mouseclick(button, state, x, y):global SCALE_K # 声明改变压缩比例global LEFT_IS_DOWNED # 声明要改变鼠标状态global MOUSE_X, MOUSE_Y # 声明改变鼠标位置MOUSE_X, MOUSE_Y = x, yif button == GLUT_LEFT_BUTTON: # 如果鼠标左键被按下LEFT_IS_DOWNED = state == GLUT_DOWN # 改变鼠标左键状态elif button == 3: # 滚轮往上滑的时候SCALE_K *= 1.05glutPostRedisplay() # 通知OpenGL开工渲染一次elif button == 4: # 滚轮往下滑的时候,这个地方有点问题SCALE_K *= 0.95glutPostRedisplay()# 如果鼠标在界面上移动了,
def mousemotion(x, y):global LEFT_IS_DOWNEDglobal EYE, EYE_UPglobal MOUSE_X, MOUSE_Yglobal DIST, PHI, THETA # 眼睛与目标之间的距离,仰角,方位角global WIN_W, WIN_Hif LEFT_IS_DOWNED: # 如果鼠标左键被按下为真,也就是说,按下了这段代码才会被执行dx = MOUSE_X - x # MOUSE_X是鼠标此时在屏幕上的位置,x是鼠标按下之后在屏幕上的位置dy = y - MOUSE_YMOUSE_X, MOUSE_Y = x, y # 重新给x,y赋值,赋值为当前鼠标在界面上的悬浮位置# 通过计算来确定在界面中y轴的方向PHI += 2 * np.pi * dy / WIN_HPHI %= 2 * np.piTHETA += 2 * np.pi * dx / WIN_WTHETA %= 2 * np.pir = DIST * np.cos(PHI)EYE[1] = DIST * np.sin(PHI)EYE[0] = r * np.sin(THETA)EYE[2] = r * np.cos(THETA)if 0.5 * np.pi < PHI < 1.5 * np.pi:EYE_UP[1] = -1.0else:EYE_UP[1] = 1.0glutPostRedisplay() # 通知刷新# 用来检测键盘的动态
def keydown(key, x, y):global DIST, PHI, THETAglobal EYE, LOOK_AT, EYE_UPglobal IS_PERSPECTIVE, VIEWif key in [b'x', b'X', b'y', b'Y', b'z', b'Z']:if key == b'x': # 瞄准参考点 x 减小LOOK_AT[0] -= 0.01elif key == b'X': # 瞄准参考 x 增大LOOK_AT[0] += 0.01elif key == b'y': # 瞄准参考点 y 减小LOOK_AT[1] -= 0.01elif key == b'Y': # 瞄准参考点 y 增大LOOK_AT[1] += 0.01elif key == b'z': # 瞄准参考点 z 减小LOOK_AT[2] -= 0.01elif key == b'Z': # 瞄准参考点 z 增大LOOK_AT[2] += 0.01DIST, PHI, THETA = getposture()glutPostRedisplay()elif key == b'\r': # 回车键,视点前进EYE = LOOK_AT + (EYE - LOOK_AT) * 0.9DIST, PHI, THETA = getposture()glutPostRedisplay()elif key == b'\x08': # 退格键,视点后退EYE = LOOK_AT + (EYE - LOOK_AT) * 1.1DIST, PHI, THETA = getposture()glutPostRedisplay()elif key == b' ': # 空格键,切换投影模式IS_PERSPECTIVE = not IS_PERSPECTIVEglutPostRedisplay()if __name__ == "__main__":glutInit()displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTHglutInitDisplayMode(displayMode)glutInitWindowSize(WIN_W, WIN_H)glutInitWindowPosition(300, 200)glutCreateWindow('Quidam Of OpenGL')init() # 初始化画布glutDisplayFunc(draw) # 注册回调函数draw()glutReshapeFunc(reshape) # 注册响应窗口改变的函数reshape(),监听窗口动态glutMouseFunc(mouseclick) # 注册响应鼠标点击的函数mouseclick()glutMotionFunc(mousemotion) # 注册响应鼠标拖拽的函数mousemotion()glutKeyboardFunc(keydown) # 注册键盘输入的函数keydown()glutMainLoop() # 进入glut主循环
5. 修改后的旋转视景体
from OpenGL.GL import *
from OpenGL.GLUT import *def draw():glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)glRotatef(0.01, 0, 1, 0)# ---------------------------------------------------------------glBegin(GL_LINES) # 开始绘制线段(世界坐标系)# 以红色绘制x轴glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点(x轴负方向)glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点(x轴正方向)# 以绿色绘制y轴glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点(y轴负方向)glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点(y轴正方向)# 以蓝色绘制z轴glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点(z轴负方向)glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点(z轴正方向)glEnd() # 结束绘制线段# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴负半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点glEnd() # 结束绘制三角形# ---------------------------------------------------------------# ---------------------------------------------------------------glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴正半区)glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明glVertex3f(0.5, 0.366, 0.5) # 设置三角形顶点glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明glVertex3f(-0.5, 0.366, -0.5) # 设置三角形顶点glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明glVertex3f(-0.0, -0.5, 0.5) # 设置三角形顶点glEnd() # 结束绘制三角形# ---------------------------------------------------------------glFlush() # 清空缓冲区,将指令送往硬件立即执行if __name__ == "__main__":glutInit() # 1. 初始化glut库glutCreateWindow('Quidam Of OpenGL') # 2. 创建glut窗口glutDisplayFunc(draw) # 3. 注册回调函数draw()glutIdleFunc(draw)glutMainLoop() # 4. 进入glut主循环
这篇关于PyOpenGL的安装与操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!