Python+OpenGL绘制3D模型(五)绘制三角型 📅 发布时间:2026/9/18 14:30:04 👁 浏览次数: 系列文章基础PythonOpenGL绘制3D模型一Python 和 PyQt环境搭建PythonOpenGL绘制3D模型二程序框架PyQt5PythonOpenGL绘制3D模型三程序框架PyQt6PythonOpenGL绘制3D模型四绘制线段PythonOpenGL绘制3D模型五绘制三角型PythonOpenGL绘制3D模型六材质文件载入和贴图映射PythonOpenGL绘制3D模型七制作3dsmax导出插件PythonOpenGL 杂谈一高级用 DeepDraw 几何引擎开发建筑设计软件一SketchUp 替代用 DeepDraw 几何引擎开发建筑设计软件二下载DeepDraw用 DeepDraw 几何引擎开发建筑设计软件三用代码绘制线段用 DeepDraw 几何引擎开发建筑设计软件四用代码绘制面用 DeepDraw 几何引擎开发建筑设计软件五创建选择工具用 DeepDraw 几何引擎开发建筑设计软件六读取模型文件用 DeepDraw 几何引擎开发建筑设计软件七InputPoint输入捕获器用 DeepDraw 几何引擎开发建筑设计软件八画线工具未完待续…前言Sketchup作为目前设计院最为流行的设计软件(非工程制图软件深受设计师的喜爱软件小巧而功能强大有不少为之开发的插件应运而生不过呢关于底层数据结构和工作原理相关的文章少之又少本文意在填补一下这方面的空缺。PythonOpenGL绘制3D模型五绘制三角型运行效果文章目录系列文章前言PythonOpenGL绘制3D模型五绘制三角型一、绘制三角型二、绘制轮廓线三、运行四、Z-Buffer问题五、最终效果六、全部代码系列文章预告一、绘制三角型绘制面的最小单元是三角形如果你在想为什么不用OpenGL的多边形来绘制。很好的问题根据实践所有的3D软件都是把多边形转成三角型来绘制的而且转换的过程所用到的Tessellation算法非常耗时要把3D空间的模型转到2D空间才能计算。绘制多边形你要考虑所有顶点是不是在一个平面上多边形是不是凸多边形线是否有交叉中间是否有开孔等等。。所以3D绘图还是老老实实用三角面吧defdraw_tirangle(p1,p2,p3,gl):gl.glBegin(gl.GL_TRIANGLES)gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glVertex3d(p2.x(),p2.y(),p2.z())gl.glVertex3d(p3.x(),p3.y(),p3.z())gl.glEnd()一个4边型是由2个三角型组成的所以绘制1个面需要完整的调用2次三角形绘制defdraw_single_face(p1,p2,p3,p4,gl):gl.glBegin(gl.GL_TRIANGLES)gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glVertex3d(p2.x(),p2.y(),p2.z())gl.glVertex3d(p3.x(),p3.y(),p3.z())gl.glEnd()gl.glBegin(gl.GL_TRIANGLES)gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glVertex3d(p2.x(),p2.y(),p2.z())gl.glVertex3d(p3.x(),p3.y(),p3.z())gl.glEnd()一个完整的立方体由6个面组成我们现在来把它们全部画出来defdraw_box_faces(gl):p1QVector3D(-1,-1,0)p2QVector3D(1,-1,0)p3QVector3D(1,1,0)p4QVector3D(-1,1,0)p5QVector3D(-1,-1,2)p6QVector3D(1,-1,2)p7QVector3D(1,1,2)p8QVector3D(-1,1,2)draw_single_face(p1,p2,p3,p4,gl)draw_single_face(p5,p6,p7,p8,gl)draw_single_face(p1,p2,p6,p5,gl)draw_single_face(p3,p4,p8,p7,gl)draw_single_face(p2,p3,p7,p6,gl)draw_single_face(p4,p1,p5,p8,gl)二、绘制轮廓线现在的程序是没有开启明暗处理和灯光的所以绘制的所有面都是一个颜色的画出来的东西是一片混沌区分不出不同的面现在我们用单色面线框的方式来绘制我们把盒子的所有线断都绘制出来defdraw_box_lines(gl):p1QVector3D(-1,-1,0)p2QVector3D(1,-1,0)p3QVector3D(1,1,0)p4QVector3D(-1,1,0)p5QVector3D(-1,-1,2)p6QVector3D(1,-1,2)p7QVector3D(1,1,2)p8QVector3D(-1,1,2)# 一个立方体有12条边draw_single_line(p1,p2,gl)draw_single_line(p2,p3,gl)draw_single_line(p3,p4,gl)draw_single_line(p4,p1,gl)draw_single_line(p5,p6,gl)draw_single_line(p6,p7,gl)draw_single_line(p7,p8,gl)draw_single_line(p8,p5,gl)draw_single_line(p1,p5,gl)draw_single_line(p2,p6,gl)draw_single_line(p3,p7,gl)draw_single_line(p4,p8,gl)defdraw_single_line(p1,p2,gl):gl.glBegin(gl.GL_LINES)gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glVertex3d(p2.x(),p2.y(),p2.z())gl.glEnd()三、运行运行后我们得到一个方形的盒子很漂亮用这么少的代码就可以达到如此的效果四、Z-Buffer问题我们已经绘制出模型和轮廓了但是有个很明显的问题模型的轮廓有时候是虚线有时候是实线闪来闪去看着很不舒服这是3D编辑软件都会遇到的一个问题因为3D软件需要显示模型的线框但是画线和画面在遇到同一个像素时就会出现Z-Buffer的值一样那么这个像素最后是画线时的颜色还是画面时的颜色是个不确定的值。这在3D领域有个专有名词叫做z-fighting就是说2个面靠的很近很近的时候这2个面就会来回闪硕的现象。解决这个问题有个技巧叫做z-buff bias也叫做z-buff偏移具体的办法是在绘制面的时候算出的z-buff值稍微增加一个很小的单位那么在画线的时候这个地方的Z值就肯定比画线的Z值小那么一点就能够保证线能正常显示不会和面发生z-buff冲突五、最终效果六、全部代码fromPyQt5.QtGuiimportQVector3D############# draw# 绘图主入口############defdraw(gl):# PythonOpenGL绘制3D模型四 绘制线段#draw_rect(gl)# PythonOpenGL绘制3D模型五 绘制三角面draw_filled_cube(gl)############# draw_filed_cube# 绘制填充的方形############defdraw_filled_cube(gl):# 设置z-buff偏移gl.glEnable(gl.GL_POLYGON_OFFSET_FILL)gl.glPolygonOffset(1,1)# 绘制填充面gl.glColor3f(0.9,0.83,0.6)draw_box_faces(gl)# 关闭z-buff偏移gl.glDisable(gl.GL_POLYGON_OFFSET_FILL)# 绘制线框gl.glColor3f(0.0,0.0,0.0)draw_box_lines(gl)############# draw_box_faces# 画面 - 中间的填充部分############defdraw_box_faces(gl):p1QVector3D(-1,-1,0)p2QVector3D(1,-1,0)p3QVector3D(1,1,0)p4QVector3D(-1,1,0)p5QVector3D(-1,-1,2)p6QVector3D(1,-1,2)p7QVector3D(1,1,2)p8QVector3D(-1,1,2)draw_single_face(p1,p2,p3,p4,gl)draw_single_face(p5,p6,p7,p8,gl)draw_single_face(p1,p2,p6,p5,gl)draw_single_face(p3,p4,p8,p7,gl)draw_single_face(p2,p3,p7,p6,gl)draw_single_face(p4,p1,p5,p8,gl)defdraw_single_face(p1,p2,p3,p4,gl):gl.glBegin(gl.GL_TRIANGLES)gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glVertex3d(p2.x(),p2.y(),p2.z())gl.glVertex3d(p3.x(),p3.y(),p3.z())gl.glEnd()gl.glBegin(gl.GL_TRIANGLES)gl.glVertex3d(p3.x(),p3.y(),p3.z())gl.glVertex3d(p4.x(),p4.y(),p4.z())gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glEnd()############# draw_box_lines# 画面 外侧的线############defdraw_box_lines(gl):p1QVector3D(-1,-1,0)p2QVector3D(1,-1,0)p3QVector3D(1,1,0)p4QVector3D(-1,1,0)p5QVector3D(-1,-1,2)p6QVector3D(1,-1,2)p7QVector3D(1,1,2)p8QVector3D(-1,1,2)# 一个立方体有12条边draw_single_line(p1,p2,gl)draw_single_line(p2,p3,gl)draw_single_line(p3,p4,gl)draw_single_line(p4,p1,gl)draw_single_line(p5,p6,gl)draw_single_line(p6,p7,gl)draw_single_line(p7,p8,gl)draw_single_line(p8,p5,gl)draw_single_line(p1,p5,gl)draw_single_line(p2,p6,gl)draw_single_line(p3,p7,gl)draw_single_line(p4,p8,gl)defdraw_single_line(p1,p2,gl):gl.glBegin(gl.GL_LINES)gl.glVertex3d(p1.x(),p1.y(),p1.z())gl.glVertex3d(p2.x(),p2.y(),p2.z())gl.glEnd()############# draw_rect# 绘制线段组成的方形############defdraw_rect(gl):gl.glColor3f(1.0,0.0,0.0)gl.glBegin(gl.GL_LINES)gl.glVertex3d(-1,0,0)gl.glVertex3d(1,0,0)gl.glEnd()gl.glBegin(gl.GL_LINES)gl.glVertex3d(-1,0,2)gl.glVertex3d(1,0,2)gl.glEnd()gl.glBegin(gl.GL_LINES)gl.glVertex3d(-1,0,0)gl.glVertex3d(-1,0,2)gl.glEnd()gl.glBegin(gl.GL_LINES)gl.glVertex3d(1,0,0)gl.glVertex3d(1,0,2)gl.glEnd()系列文章预告目标是开发一个Sketchup Viewer能够显示Sketchup的.skp文件中的3D模型Corona渲染器照片级渲染效果