Python+OpenGL绘制3D模型(九)完善插件功能: 矩阵,材质,法线

系列文章

一、逆向工程
Sketchup 逆向工程(一)破解.skp文件数据结构
Sketchup 逆向工程(二)分析三维模型数据结构
Sketchup 逆向工程(三)软件逆向工程从何处入手
Sketchup 逆向工程(四)破解的乐趣 钩子 外挂 代码注入

二、OpenGL渲染模型
Python+OpenGL绘制3D模型(一)Python 和 PyQt环境搭建
Python+OpenGL绘制3D模型(二)程序框架PyQt5
Python+OpenGL绘制3D模型(三)程序框架PyQt6
Python+OpenGL绘制3D模型(四)绘制线段
Python+OpenGL绘制3D模型(五)绘制三角型
Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射
Python+OpenGL绘制3D模型(七)制作3dsmax导出插件
Python+OpenGL绘制3D模型(八)绘制插件导出的插件
Python+OpenGL绘制3D模型(九)完善插件功能: 矩阵,材质,法线
Python+OpenGL 杂谈(一)

三、成果
疫情期间关在家里实在没事干,破解了Sketchup,成功做出可以读取并显示.skp文件的程序SuViewer

前言

Sketchup作为目前设计院最为流行的设计软件(非工程制图软件),深受设计师的喜爱,软件小巧,而功能强大,有不少为之开发的插件应运而生,不过呢,关于底层数据结构和工作原理相关的文章少之又少,本文意在填补一下这方面的空缺,通过逆向软件分析,展示软件内部奥秘。本文用到的工具:IDA Pro,Immunity Debugger,Visual Studio (逆向工程三件套)数据结构属于知识产权的核心机密:


文章目录

  • 系列文章
  • 前言
    • 一、模型的变换矩阵
    • 二、导出材质、贴图
    • 三、导出法线
    • 四、 源代码
      • 1、maxplus_export_sel_model.py
      • 2、CModel.py
  • 系列文章预告

一、模型的变换矩阵

TODO

二、导出材质、贴图

TODO

三、导出法线

TODO

四、 源代码

1、maxplus_export_sel_model.py

import MaxPlus
import pickle
import base64
from CModel import CModel, CMaterial, CMesh, CTriangle, CVector3################################
#                   FILE DESCRIPTION
#  文件描述:CModelExport
#  对应文章:Python+OpenGL绘制3D模型(九) 完善插件功能: 矩阵,材质,法线
#  作者:李航 Lihang
#  使用方法:
#   1、选择要导出的模型
#   2、在命令行窗口中输入
#          python.ExecuteFile "C:/_proj/SuViewer/articles/step3/maxplus_export_sel_model.py"
#   3、把命令行拖入工具栏可以生成快捷方式,方便下次使用
#   4、测试可使用的版本:3dsmax2016
#   ELSE..
################################# 注意: 保证c:/temp目录存在,否则无法导出
EXPORT_PATH_FILE = "c:/temp/CModel.pickle"############
# CModelExport
############  
class CModelExport:def __init__(self):self.list_mats = []############# export#   插件主入口############  def export(self):model = CModel()for n, obj, triObj in self.EnumSeletciontGeometry():print ("find %s, class:%s"%(n, obj.GetClassName()) )mesh = triObj.GetMesh()out_mesh = self.ProcMesh(n, mesh)model.list_mesh.append(out_mesh)self.printMats()model.list_mats = [mo for mi, mo in self.list_mats]hf = open("c:/temp/CModel.pickle",  "wb")pickle.dump(model,  hf,  2)hf.close()############# EnumSeletciontGeometry#   1、遍历选择的物体#   2、生成列表sel_list并返回############  def EnumSeletciontGeometry(self):sel_list = []for n in MaxPlus.SelectionManager.Nodes:        # objectobj = n.EvalWorldState().Getobj()if obj.CanConvertToType(MaxPlus.ClassIds.TriMeshGeometry):triObj = obj.ConvertToType(MaxPlus.ClassIds.TriMeshGeometry)item = (n, obj, MaxPlus.TriObject._CastFrom(triObj))sel_list.append(item)#print ("find %s, class:%s"%(n, obj.GetClassName()) )else:print("can't conv triMesh, Type is:%s" % obj.GetClassName())return sel_list############# ProcMesh#   1、处理max中的模型#   2、转成需要的CModel数据############def ProcMesh(self, node, mesh):print("---ProcMesh()---")#=====================# Collect Infomation#=====================tm = node.GetWorldTM()# colornew_mesh = CMesh()color1 = node.GetWireColor()new_mesh.color = (color1.GetR(), color1.GetG(), color1.GetB())# materialm = node.GetMaterial()new_mesh.mat = self.ProcMeshMaterial(m, mesh) if m else None#=====================# Vertices#=====================num_verts = mesh.GetNumVertices()print ("numVertics:%d"%num_verts)for i in range(num_verts):loc_pos = mesh.GetVertex(i)point = tm.PointTransform(loc_pos)nv = CVector3(point.X, point.Y, point.Z)new_mesh.list_vertices.append(nv)#=====================# Normals#=====================normalBuilder = NormalBuilder()normalBuilder.BuildNormals(mesh)num_normals = len(normalBuilder.list_normals)print("numNormals:%d"%num_normals)for i in range(num_normals):ln = normalBuilder.list_normals[i]nm = tm.VectorTransform(ln).Normalize()new_mesh.list_normals.append(CVector3(nm.X,  nm.Y, nm.Z))#=====================# UV#=====================num_tverts = mesh.GetNumTVerts()print ("numTVerts:%d"%num_tverts)for i in range(num_tverts):uv = mesh.GetTVert(i)nv = CVector3(uv.X, uv.Y, uv.Z)new_mesh.list_uvs.append(nv)#=====================# Triangles#=====================num_faces = mesh.GetNumFaces()print ("numFaces:%d"%num_faces)for i in range(num_faces):tri = mesh.GetFace(i)smGroup = tri.GetSmGroup()vi1 = tri.GetVert(0)vi2= tri.GetVert(1)vi3 = tri.GetVert(2)ni1 = normalBuilder.GetNormal(vi1, smGroup )ni2 = normalBuilder.GetNormal(vi2, smGroup )ni3 = normalBuilder.GetNormal(vi3, smGroup )tface = mesh.GetTVFace(i)ui1 = tface.GetA()ui2 = tface.GetB()ui3 = tface.GetC()ev1 = True if tri.GetEdgeVis(0) else Falseev2 = True if tri.GetEdgeVis(1) else Falseev3 = True if tri.GetEdgeVis(2) else Falsent = CTriangle()nt.a = (vi1, ni1, ui1)nt.b = (vi2, ni2, ui2)nt.c = (vi3, ni3, ui3)norm = mesh.FaceNormal(i)nt.matId = tri.GetMatID()nt.faceNormal = CVector3(norm.X, norm.Y, norm.Z)nt.smGroup = tri.GetSmGroup()nt.edgevis = (ev1, ev2, ev3)new_mesh.list_tris.append(nt)#print(" Tri: %d %d %d"%(tri.GetVert(0), tri.GetVert(1), tri.GetVert(2) ))return new_mesh############# Material############def ProcMeshMaterial(self, m, mesh):print("---CollectMeshMaterials()---")if m.IsMultiMtl():num_submat = m.GetNumSubMtls()refcount = [0] * num_submatnum_faces = mesh.GetNumFaces()for i in range(num_faces):f = mesh.GetFace(i)mid = f.GetMatID()refcount[mid] += 1print("refcount:"+str(refcount))list_submats = []for i in range(num_submat):if refcount[i]:mMat = m.GetSubMtl(i)if mMat:cm = self.addMaterial(mMat)list_submats.append(cm)else:list_submats.append(None)else:list_submats.append(None)return list_submatselse:return self.addMaterial(m)def addMaterial(self, mi):#==============#  Find Exist#==============for min, mout in self.list_mats:if min == mi:return mout#==============#  Create Out Material#==============mo = CMaterial()# Diffusecolor1 = mi.GetDiffuse()mo.diffuse = (color1.GetR(), color1.GetG(), color1.GetB())# Textureisubmap = MaxPlus.ISubMap._CastFrom(mi)#assert(isubmap, "can't cast to ISubMap")tex = isubmap.GetSubTexmap(1)if tex:bitmap = MaxPlus.BitmapTex._CastFrom(tex)texmap = bitmap.GetMapName()mo.tex_filepath = texmapmo.tex_bindata = self.loadFileData(texmap)# Add to listitem = (mi, mo)self.list_mats.append(item)return modef loadFileData(self, filename):file1 = open(filename,  mode='rb')imgdata = bytes(file1.read())file1.close()return base64.b64encode(imgdata)def printMats(self):print("---printMats()---")print("Number of Materials: %d"% len(self.list_mats))print("----------------")for matId, m in enumerate(self.list_mats):mi, mo = mprint("ID: %d"% matId)print("source:" + str(mi))print("diffuse: " + str(mo.diffuse))print("texture: " + mo.tex_filepath)############
# NormalBuilder
############
class NormalBuilder:def __init__(self):self.list_verts = []self.list_normals = []class Vertex:def __init__(self, p):self.v = pself.an = Nonedef normals(self):if self.an is None:return ()elif type(self.an) is list:return self.anelse:return (self.an, )def addNormal(self, n, sg):for vn in self.normals():if vn.sg & sg:vn.n = vn.n + nreturn#not findvn = NormalBuilder.VNormal(n, sg)if self.an is None:self.an = vnelif type(self.an) is list:self.an.append(vn)else:self.an = [self.an, vn]class VNormal:def __init__(self, n, sg):self.n = nself.sg = sgself.idx = -1def add(self, n):self.n =  self.n + ndef BuildNormals(self, mesh):print("-----BuildNormals------")#=====================# Vertices#=====================num_verts = mesh.GetNumVertices()for i in range(num_verts):point = mesh.GetVertex(i)v = NormalBuilder.Vertex(point)self.list_verts.append(v)num_faces = mesh.GetNumFaces()for i in range(num_faces):f = mesh.GetFace(i)faceNormal = mesh.FaceNormal(i)smGroup = f.GetSmGroup()v1 = f.GetVert(0)self.list_verts[v1].addNormal(faceNormal, smGroup)v2 = f.GetVert(1)self.list_verts[v2].addNormal(faceNormal, smGroup)v3 = f.GetVert(2)self.list_verts[v3].addNormal(faceNormal, smGroup)idx = 0for v in self.list_verts:for vn in v.normals():vn.n = vn.n.Normalize()self.list_normals.append(vn.n)vn.idx = idxidx += 1def GetNormal(self, vi, sg):v = self.list_verts[vi]for vn in v.normals():if vn.sg & sg:return vn.idxassert(False)############
# Main
#   1、创建插件导出对象CModelExport
#   2、执行export
############
modelExport = CModelExport()
modelExport.export()

2、CModel.py

import mathclass CModel:def __init__(self):self.list_mats = []self.list_mesh = []class CMaterial:def __init__(self):self.diffuse = (0, 0, 0)self.tex_filepath = ""self.tex_bindata = Noneclass CMesh:def __init__(self):self.name = ""self.color = (0, 0, 0)self.list_vertices = []self.list_normals = []self.list_uvs = []self.list_tris = []class CTriangle:def __init__(self):self.a=(0, 0, 0)self.b=(0, 0, 0)self.c=(0, 0, 0)self.faceNormal = CVector3.zero()self.matId = 0self.smGroup = 0self.edgevis=(True, True, True)class CVector3:def __init__(self, x, y, z):self.x=xself.y=yself.z=z@classmethoddef zero2(cls):return CVector3(0.0, 0.0, 0.0)@staticmethoddef zero():return CVector3(0.0, 0.0, 0.0)def normalize(self):s = 1.0 / math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z)self.x *= sself.y *= sself.z *= sdef __add__(self,  R):return CVector3(self.x + R.x, self.y + R.y, self.z + R.z)

系列文章预告

目标是一个完善的Viewer,能够显示Sketchup的.skp文件中的3D模型
在这里插入图片描述

Corona渲染器照片级渲染效果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/586828.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶学习笔记(二十三)——车辆控制模型

#Apollo开发者# 学习课程的传送门如下,当您也准备学习自动驾驶时,可以和我一同前往: 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo开放平台9.0专项技术公开课》免费报名—>传送门 文章目录 前言 运动学模型 动力学模型 总结…

MyBatis-config.xml配置文件

1、基本介绍: mybatis的核心配置文件(mybatis-config.xml),比如配置jdbc连接信息,注册mapper等等,我们需要对这个配置文件有详细的了解。 官网地址有详细介绍 mybatis – MyBatis 3 | 配置 2、properties属性 在通常的情况下&am…

Java 运算符

&&运算比||运算的优先级高 C与Java

【Unity入门】热更新框架之xLua

目录 一、xLua概述1.1xLua简介1.2xLua安装 二、Lua文件加载2.1执行字符串2.2加载Lua文件2.3自定义loader 三、xLua文件配置3.1打标签3.2静态列表3.3动态列表 四、Lua与C#交互4.1 C#访问Lua4.1.1 获取一个全局基本数据类型4.1.2 访问一个全局的table4.1.3 访问一个全局的functio…

STM32 ESP8266 物联网智能温室大棚 源码PCB原理图 设计文档

资料下载: https://download.csdn.net/download/vvoennvv/88680924 一、概述 本系统以STM32F103C8T6单片机为主控芯片,采用相关传感器构建系统硬件电路。其中使用DHT11温湿度传感器对温度和湿度的采集,MQ-7一氧化碳传感器检测CO浓度,GP2Y101…

Hive集群出现报错信息解决办法

一、报错信息:hive> show databases;FAILED: HiveException java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient 解决办法:1.删除mysql中的元数据库(metastore&#xff0…

车载电子电器架构 —— 电子电气系统开发角色定义

车载电子电器架构 —— 电子电气系统开发角色定义 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 注:本文12000字,深度思考者进!!! 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的…

Spark编程实验四:Spark Streaming编程

目录 一、目的与要求 二、实验内容 三、实验步骤 1、利用Spark Streaming对三种类型的基本数据源的数据进行处理 2、利用Spark Streaming对Kafka高级数据源的数据进行处理 3、完成DStream的两种有状态转换操作 4、把DStream的数据输出保存到文本文件或MySQL数据库中 四…

什么是检索增强生成?

检索增强生成(Retrieval Augmented Generation,RAG)是指对大型语言模型(Large Language Model,LLM)输出进行优化,使其能够在生成响应之前引用训练数据来源之外的权威知识库。LLM 用海量数据进行…

win11出现安全中心空白和IT管理员已限制对某些区域的访问(不一样的解决方式),真实的个人经历,并且解决经过

1、个人的产生问题的经历 2023年12月22日,由于我买了一块电脑的固态硬盘1T,想要扩容,原来电脑自带512G(由于个人是一个程序员,导致512G实在太古鸡肋)装好以后,想要重装一下系统,来个大清理。结果不出意料&…

DrGraph原理示教 - OpenCV 4 功能 - 颜色空间

前言 前段时间,甲方提出明确需求,让把软件国产化。稍微研究了一下,那就转QT开发,顺便把以前的功能代码重写一遍。 至于在Ubuntu下折腾QT、OpenCV安装事宜,网上文章很多,照猫画虎即可。 这个过程&#xff0…

据报道,微软的下一代 Surface 笔记本电脑将是其首款真正的“人工智能 PC”

明年,微软计划推出 Surface Laptop 6和 Surface Pro 10,这两款设备将提供 Arm 和 Intel 两种处理器选项。不愿意透露姓名的不透露姓名人士透露,这些新设备将引入先进的人工智能功能,包括配备下一代神经处理单元 (NPU)。据悉&#…

MCS-51单片机的中断源

目录 MCS-51中断源: 中断控制: 1.定时控制寄存器(TCON) 2.串行口控制寄存器(SCON) 3.中断允许寄存器(IE) 4.中断优先级控制寄存器(IP) 中断处理: 中断采样: 中断查询: 中断…

.FileZilla的使用和主动模式被动模式介绍

FileZilla的使用和主动模式被动模式介绍 1.FileZilla的使用和主动模式被动模式介绍1.安装下载2.新建组和用户2.1打开后出现如下界面2.2点击编辑打开组这个选项2.3点击添加组以后,点击确认2.4输入组的名称,列如我输入的niyin2.5点击用户选项2.6像上面一样…

【Vue2+3入门到实战】(15)VUE路由入门声明式导航的基本使用与详细代码示例

目录 一、声明式导航-导航链接1.需求2.解决方案3.通过router-link自带的两个样式进行高亮4.总结 二、声明式导航-两个类名1.router-link-active2.router-link-exact-active3.在地址栏中输入二级路由查看类名的添加4.总结 三、声明式导航-自定义类名(了解&#xff09…

中间人攻击是什么,会产生哪些危害,如何有效防止中间人攻击

简介 中间人攻击(Man-in-the-Middle Attack,简称MITM攻击)是一种网络攻击,其原理是攻击者通过各种技术手段将受攻击者控制的一台计算机虚拟放置在网络连接中的两台通信计算机之间,这台计算机称为“中间人”。在攻击过…

【设计模式】状态模式

文章目录 引例状态模式理论状态模式代码优化结合享元模式并发问题解决 策略模式 VS 状态模式 引例 交通信号灯系统的设计与实现 方案一 传统设计方案 定义交通灯颜色的枚举 public enum LightColor { Green,Red,Yellow }交通灯类TrafficLight,处理颜色转换等业务…

安全配置审计概念、应用场景、常用基线及扫描工具

软件安装完成后都会有默认的配置,但默认配置仅保证了服务正常运行,却很少考虑到安全防护问题,攻击者往往利用这些默认配置产生的脆弱点发起攻击。虽然安全人员已经意识到正确配置软件的重要性,但面对复杂的业务系统和网络结构、网…

【数学建模美赛M奖速成系列】Matplotlib绘图技巧(一)

Matplotlib图像基础 写在前面1 基本绘图实例:sin、cos函数图2 plot()函数详解**kwargs参数: 3 matplotlib中绘图的默认配置4 设置图的横纵坐标的上下界5 设置横纵坐标上的记号6 调整图像的脊柱7 添加图例8 给一些特殊点加注释9 子图最后 写在前面 前面我…