Python+Opengl实现用B样条曲线在方块上实时交互写字
2021/11/16 22:12:39
本文主要是介绍Python+Opengl实现用B样条曲线在方块上实时交互写字,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
- 引言
- 依赖
- 画方块
- 屏幕坐标转换为世界坐标
- B样条曲线绘制
- 完整代码
引言
博主是北京理工大学计算机2021级研一的学生,这项任务是计算机图形学这门课程的第一个大作业。由于之前并未接触过opengl,所以在完成这个作业过程中费了一些劲。因为网上找不到符合老师需求的代码,所以代码都是自己拼拼凑凑整的,可能仍有不规范之处。当然,这篇博客是在这门课全结束之后才发布的。
依赖
- python3.9
- opengl库
估计python3.7、3.8也都行,但没试过。具体导入库的代码如下:
from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * import numpy as np
画方块
这里使用的是opengl自带的画面函数进行绘制的。
首先给出每个面的点坐标:
vertices2 = 1.4*np.array([ [[0.2, 0.2, 0.2], [-0.2, 0.2, 0.2], [-0.2, -0.2, 0.2], [0.2, -0.2, 0.2]], # 前 [[0.2, 0.2, -0.2], [0.2, -0.2, -0.2], [-0.2, -0.2, -0.2], [-0.2, 0.2, -0.2]], # 后 [[0.2, 0.2, 0.2], [0.2, 0.2, -0.2], [-0.2, 0.2, -0.2], [-0.2, 0.2, 0.2]], # 左 [[0.2, -0.2, 0.2], [0.2, -0.2, -0.2], [-0.2, -0.2, -0.2], [-0.2, -0.2, 0.2]], # 右 [[0.2, 0.2, 0.2], [0.2, -0.2, 0.2], [0.2, -0.2, -0.2], [0.2, 0.2, -0.2]], # 上 [[-0.2, 0.2, 0.2], [-0.2, -0.2, 0.2], [-0.2, -0.2, -0.2], [-0.2, 0.2, -0.2]] # 下 ])
这里的1.4倍是为了调整大小关系,可根据实际情况调整这个系数。
再给出每个面的颜色:
colours = np.array([ [0, 1, 1], [1, 0.5, 0.5], [1, 1, 0], [0.1, 0.1, 1], [0, 1, 0.2], [0.6, 0.6, 0.6] ])
这里的三个数就分别代表RGB的红绿蓝,也可自行调整。
最后再show函数里画出这个立方体。
for i in range(vertices2.shape[0]): glBegin(GL_QUADS) points = vertices2[i, :] color = colours[i, :] for point in points: glColor3f(color[0], color[1], color[2]) glVertex3f(point[0], point[1], point[2]) glEnd()
屏幕坐标转换为世界坐标
这一步试过很多错,网上大部分代码都是基于C++的。
完成转换主要通过opengl里的反映射函数:gluUnProject.
gluUnProject(MOUSE_X, viewport[3] - MOUSE_Y, z, modelview_mat, projection_mat, viewport)
该函数通过调用鼠标点击的位置信息(MOUSE_X,MOUSE_Y)、图片深度信息(z)、三个转换矩阵(modelview_mat, projection_mat, viewport)进行计算。
B样条曲线绘制
这一步试过更多的错。
代码部分很简单,就是利用gluNurbsCurve函数来进行B样条曲线的绘制。其中,NURBS是非均匀有理B样条(Non-Uniform Rational B-Splines)的缩写。
gluNurbsCurve(nurb, KNOTS, POINTS, GL_MAP1_VERTEX_3)
POINTS就是B样条中的控制点,也就是鼠标点击后得到的点坐标。但由于之前KNOTS一直没有配置正确,导致函数无法画出曲线。
KNOTS可直接根据控制点的数量进行生成。
degree = 3 knotNum = len(POINTS) + degree KNOTS = [float(i)/(knotNum-1) for i in range(knotNum)]
完整代码
from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * import numpy as np vertices2 = 1.4*np.array([ [[0.2, 0.2, 0.2], [-0.2, 0.2, 0.2], [-0.2, -0.2, 0.2], [0.2, -0.2, 0.2]], # 前 [[0.2, 0.2, -0.2], [0.2, -0.2, -0.2], [-0.2, -0.2, -0.2], [-0.2, 0.2, -0.2]], # 后 [[0.2, 0.2, 0.2], [0.2, 0.2, -0.2], [-0.2, 0.2, -0.2], [-0.2, 0.2, 0.2]], # 左 [[0.2, -0.2, 0.2], [0.2, -0.2, -0.2], [-0.2, -0.2, -0.2], [-0.2, -0.2, 0.2]], # 右 [[0.2, 0.2, 0.2], [0.2, -0.2, 0.2], [0.2, -0.2, -0.2], [0.2, 0.2, -0.2]], # 上 [[-0.2, 0.2, 0.2], [-0.2, -0.2, 0.2], [-0.2, -0.2, -0.2], [-0.2, 0.2, -0.2]] # 下 ]) colours = np.array([ [0, 1, 1], [1, 0.5, 0.5], [1, 1, 0], [0.1, 0.1, 1], [0, 1, 0.2], [0.6, 0.6, 0.6] ]) IS_PERSPECTIVE = True # 透视投影 VIEW = np.array([-0.5, 0.5, -0.5, 0.5, 0.5, 20.0]) # 视景体的left/right/bottom/top/near/far六个面 RIGHT_IS_DOWNED = False CameraPos = np.array([0.0, 0.0, 1]) CameraFront = np.array([0, 0, 0]) CameraUp = np.array([0, 1, 0]) SCALE_K = np.array([1.0, 1.0, 1.0]) yaw = 0 pitch = 0 MOUSE_X, MOUSE_Y = 0, 0 WIN_W = 480 WIN_H = 480 POINTS = np.array([[0, 0, 0]]) def init(): glClearColor(0.0, 0.0, 0.0, 1.0) # 设置画布背景色。注意:这里必须是4个参数 glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系 glDepthFunc(GL_LEQUAL) # 设置深度测试函数(GL_LEQUAL只是选项之一) global nurb nurb = gluNewNurbsRenderer() global samplingTolerance gluNurbsProperty(nurb, GLU_SAMPLING_TOLERANCE, samplingTolerance) nurb=None samplingTolerance=1.0 def show(): global IS_PERSPECTIVE, VIEW global CameraPos, CameraFront, CameraUp global SCALE_K global WIN_W, WIN_H global vertices2 global POINTS global KNOTS global nurb glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 设置投影(透视投影) glMatrixMode(GL_PROJECTION) glLoadIdentity() if IS_PERSPECTIVE: glFrustum(VIEW[0], VIEW[1], VIEW[2], VIEW[3], VIEW[4], VIEW[5]) # 设置模型视图 glMatrixMode(GL_MODELVIEW) glLoadIdentity() # 几何变换 glScale(SCALE_K[0], SCALE_K[1], SCALE_K[2]) # 视点 gluLookAt( CameraPos[0], CameraPos[1], CameraPos[2], CameraFront[0], CameraFront[1], CameraFront[2], CameraUp[0], CameraUp[1], CameraUp[2] ) glViewport(0, 0, WIN_W, WIN_H) n = POINTS.shape[0] for i in range(n): glPointSize(3.0) glColor3f(1.0, 0.0, 0.0) glBegin(GL_POINTS) glVertex3f(POINTS[i, 0], POINTS[i, 1], POINTS[i, 2]) glEnd() #连续线段连接 glLineWidth(0.2) glColor3f(1.0, 1.0, 1.0) glBegin(GL_LINE_STRIP) for i in range(n): glVertex3f(POINTS[i, 0], POINTS[i, 1], POINTS[i, 2]) glEnd() if n > 2: degree = 3 knotNum = len(POINTS) + degree KNOTS = [float(i)/(knotNum-1) for i in range(knotNum)] gluBeginCurve(nurb) glColor3f(0, 0, 0) glLineWidth(7.0) gluNurbsCurve(nurb, KNOTS, POINTS, GL_MAP1_VERTEX_3) gluEndCurve(nurb) for i in range(vertices2.shape[0]): glBegin(GL_QUADS) points = vertices2[i, :] color = colours[i, :] for point in points: glColor3f(color[0], color[1], color[2]) glVertex3f(point[0], point[1], point[2]) glEnd() glutSwapBuffers() def Mouse_click(button, state, x, y): global RIGHT_IS_DOWNED global MOUSE_X, MOUSE_Y global SCALE_K global WIN_W global WIN_H global POINTS MOUSE_X = x MOUSE_Y = y if button == GLUT_LEFT_BUTTON and state == 0: modelview_mat = OpenGL.GL.glGetDoublev(OpenGL.GL.GL_MODELVIEW_MATRIX) projection_mat = OpenGL.GL.glGetDoublev(OpenGL.GL.GL_PROJECTION_MATRIX) viewport = OpenGL.GL.glGetIntegerv(OpenGL.GL.GL_VIEWPORT) z = OpenGL.GL.glReadPixels(MOUSE_X, viewport[3] - MOUSE_Y, 1, 1, OpenGL.GL.GL_DEPTH_COMPONENT, OpenGL.GL.GL_FLOAT) ret = gluUnProject(MOUSE_X, viewport[3] - MOUSE_Y, z, modelview_mat, projection_mat, viewport) ret_paint = [[ret[0], ret[1], ret[2]]] if abs(ret[0]) < 0.3 and abs(ret[1]) < 0.3 and abs(ret[2]) < 0.3: #方块之外的点不描出 POINTS = np.append(POINTS, ret_paint, axis=0) if button == GLUT_RIGHT_BUTTON: RIGHT_IS_DOWNED = state == GLUT_DOWN def Mouse_motion(x, y): global RIGHT_IS_DOWNED global MOUSE_X, MOUSE_Y global yaw, pitch global CameraPos if RIGHT_IS_DOWNED: dx = x - MOUSE_X dy = y - MOUSE_Y MOUSE_X = x MOUSE_Y = y sensitivity = 0.4 dx = dx * sensitivity dy = dy * sensitivity yaw = yaw + dx pitch = pitch + dy if pitch > 89: pitch = 89 if pitch < -89: pitch = -89 CameraPos[0] = np.cos(np.radians(yaw)) * np.cos(np.radians(pitch)) CameraPos[1] = np.sin(np.radians(pitch)) CameraPos[2] = np.sin(np.radians(yaw)) * np.cos(np.radians(pitch)) glutPostRedisplay() if __name__ == '__main__': glutInit() displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH glutInitDisplayMode(displayMode) glutInitWindowSize(WIN_W, WIN_H) glutInitWindowPosition(300, 200) glutCreateWindow("CUBE") init() glutDisplayFunc(show) glutMouseFunc(Mouse_click) glutMotionFunc(Mouse_motion) glutMainLoop()
这篇关于Python+Opengl实现用B样条曲线在方块上实时交互写字的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程
- 2024-11-17在FastAPI项目中添加一个生产级别的数据库——本地环境搭建指南
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器
- 2024-11-16四种数据科学Web界面框架快速对比:Rio、Reflex、Streamlit和Plotly Dash
- 2024-11-14获取参数学习:Python编程入门教程
- 2024-11-14Python编程基础入门