资讯详情

Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射

📅 2026/9/18 13:16:41 | 华诺云谱 👁 阅读
Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射
系列文章基础Python+OpenGL绘制3D模型(一)Python 和 PyQt环境搭建Python+OpenGL绘制3D模型(二)程序框架PyQt5Python+OpenGL绘制3D模型(三)程序框架PyQt6Python+OpenGL绘制3D模型(四)绘制线段Python+OpenGL绘制3D模型(五)绘制三角型Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射Python+OpenGL绘制3D模型(七)制作3dsmax导出插件Python+OpenGL 杂谈(一)高级用 DeepDraw 几何引擎开发建筑设计软件(一):SketchUp 替代用 DeepDraw 几何引擎开发建筑设计软件(二):下载DeepDraw用 DeepDraw 几何引擎开发建筑设计软件(三):用代码绘制线段用 DeepDraw 几何引擎开发建筑设计软件(四):用代码绘制面用 DeepDraw 几何引擎开发建筑设计软件(五):创建选择工具用 DeepDraw 几何引擎开发建筑设计软件(六):读取模型文件用 DeepDraw 几何引擎开发建筑设计软件(七):InputPoint输入捕获器用 DeepDraw 几何引擎开发建筑设计软件(八):画线工具未完待续…前言Sketchup作为目前设计院最为流行的设计软件(非工程制图软件),深受设计师的喜爱,软件小巧,而功能强大,有不少为之开发的插件应运而生,不过呢,关于底层数据结构和工作原理相关的文章少之又少,本文意在填补一下这方面的空缺。Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射运行效果:文章目录系列文章前言Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射一、从文件读取贴图二、glBindTexture三、指定贴图坐标四、运行图效果五、2个问题和原因六、源代码1、Draw1.py2、tOpenGLqt5.py系列文章预告一、从文件读取贴图记得以前用c++写的时候,要编译链接图像库,用于对应图片格式的加载,每个用到的格式都要单独搞一遍,在网上找开源的图片库,下载,编译,测试,一套下来搞的人很累,现在,因为有Qt的加持,载入贴图变得非常简单,全部交给Qt来做,只需要几行代码defload_texture_from_file(filepath):withopen(filepath,'rb')ashf:data=hf.read()image=QImage()valid=image.loadFromData(data)ifnotvalid:returnFalsegl_tex_obj=QOpenGLTexture(image.mirrored())returngl_tex_obj图片载入到Qt后,还需要调用OpenGL的库加载贴图数据,另外Qt的图片坐标Y轴是向下增加的,符合显示屏幕坐标的习惯,而OpenGL中的Y轴坐标是正常向上的,所以Y轴需要mirror处理一下is_built=Falsegl_tex=Nonedefdraw(gl):globalis_built,gl_texifnotis_built:gl_tex=load_texture_from_file("c:/temp/cg.jpg")is_built=True为了代码保持简洁,简化接口,不要把简单的事情复杂化:1、载入贴图后,对象保存到全局对象中,2、载入模型的初始工作也内嵌到draw函数中执行,这种思维在项目越做越大也仍然实用3、贴图路径使用了硬编码方式的绝对路径,在没有形成一个模型框架的时候,暂且用这种方式对测试减少不少工作量演示用到的贴图文件下载:二、glBindTexture在绘制模型前,设置一下OpenGL的状态机,调用glBindTexture指定当前纹理单元的数据,然后调用glEnable(GL_TEXTURE)激活纹理单元,因为有贴图作为像素的输入颜色,所以颜色设为纯白gl.glDisable(gl.GL_TEXTURE_2D)gl.glColor3f(0.9,0.83,0.6)# 绘制上下2个面draw_single_face(p1,p2,p3,p4,uv1,uv2,uv3,uv4,gl)draw_single_face(p5,p6,p7,p8,uv1,uv2,uv3,uv4,gl)gl_tex.bind()gl.glEnable(gl.GL_TEXTURE_2D)gl.glColor3f(1,1,1)# 绘制其他4个面,前,后,左,有draw_single_face(p1,p2,p6,p5,uv1,uv2,uv3,uv4,gl)draw_single_face(p3,p4,p8,p7,uv1,uv2,uv3,uv4,gl)draw_single_face(p2,p3,p7,p6,uv1,uv2,uv3,uv4,gl)draw_single_face(p4,p1,p5,p8,uv1,uv2,uv3,uv4,gl)在本例中,前后左右的面映射了贴图,上下2个面仍然用了原来的模型颜色(淡黄色)三、指定贴图坐标在调用glVertex3f之前,需要先指定顶点的贴图坐标属性,调用glTexCoord2fgl.glBegin(gl.GL_TRIANGLES)# 第一个顶点gl.glTexCoord2f(...)gl.glVertex3f(...)# 第二个顶点gl.glTexCoord2f(...)gl.glVertex3f(...)# 第三个顶点gl.glTexCoord2f(...)gl.glVertex3f(...)# 完成gl.glEnd()四、运行图效果五、2个问题和原因第一、模型的位置有点高:这是应为camera坐标系的中心为(0,0,0), 而模型高度是从 0.0 到 2.0,要调整一下中心坐标,可以通过设置概念上的world matrix沿Z轴往下移动1.0个单位,模型就居中了,目前程序框架里控制视角的平移,也可以通过这个方法来解决,不过我还是打算在之后引入Camera对象的计算,计算的逻辑思维更清晰,不容易出错# Cameraself.gl.glMatrixMode(self.gl.GL_MODELVIEW)self.gl.glLoadIdentity()self.gl.glTranslatef(0.0,0.0,-self.zoom)self.gl.glRotatef(self.rotX-90,1.0,0.0,0.0)self.gl.glRotatef(self.rotZ,0.0,0.0,1.0)# Worldself.gl.glTranslatef(0.0,0.0,-1.0)# 在这里加上对world matrix的改变这里的矩阵叠加,是按照相反的顺序乘积的,比较容易搞错,OpenGL中有个机制 PushMatrix PopMatrix,也就是说后面加入的矩阵,可以通过PopMatrix来恢复到之前的矩阵乘积的状态,越靠后面加进来的矩阵,代表子物体的矩阵,在运算中最先乘这个矩阵第二、当模型放大的时候,近的地方会被切掉调整下几行代码,# Projectionself.gl.glMatrixMode(self.gl.GL_PROJECTION)pm=QMatrix4x4()aspectRatio=w/h fov=45/aspectRatioifwhelse45pm.perspective(fov,w/h,2,5000)self.gl.glLoadMatrixf(pm.data())这里是设置透视投影矩阵的代码,pm.perspective(fov, w/h, 2, 5000),这个函数调用的最后2个参数,分别代表了近裁剪平面(z-buff=0.0),和远裁剪平面(z-buff=1.0),这2个值明显不太匹配当前场景的大小,每次应该根据当前场景大小来适当选择取值范围pm
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。