ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

Python+OpenGL绘制3D模型(九)完善插件功能: 矩阵,材质,法线 系列文章基础PythonOpenGL绘制3D模型一Python 和 PyQt环境搭建PythonOpenGL绘制3D模型二程序框架PyQt5PythonOpenGL绘制3D模型三程序框架PyQt6PythonOpenGL绘制3D模型四绘制线段PythonOpenGL绘制3D模型五绘制三角型PythonOpenGL绘制3D模型六材质文件载入和贴图映射PythonOpenGL绘制3D模型七制作3dsmax导出插件高级用 DeepDraw 几何引擎开发建筑设计软件一SketchUp 替代用 DeepDraw 几何引擎开发建筑设计软件二下载DeepDraw用 DeepDraw 几何引擎开发建筑设计软件三用代码绘制线段用 DeepDraw 几何引擎开发建筑设计软件四用代码绘制面用 DeepDraw 几何引擎开发建筑设计软件五创建选择工具用 DeepDraw 几何引擎开发建筑设计软件六读取模型文件用 DeepDraw 几何引擎开发建筑设计软件七InputPoint输入捕获器用 DeepDraw 几何引擎开发建筑设计软件八画线工具未完待续…前言Sketchup作为目前设计院最为流行的设计软件(非工程制图软件深受设计师的喜爱软件小巧而功能强大有不少为之开发的插件应运而生不过呢关于底层数据结构和工作原理相关的文章少之又少本文意在填补一下这方面的空缺。文章目录系列文章前言一、模型的变换矩阵二、导出材质、贴图三、导出法线四、 源代码1、maxplus_export_sel_model.py2、CModel.py系列文章预告一、模型的变换矩阵TODO二、导出材质、贴图TODO三、导出法线TODO四、 源代码1、maxplus_export_sel_model.pyimportMaxPlusimportpickleimportbase64fromCModelimportCModel,CMaterial,CMesh,CTriangle,CVector3################################# FILE DESCRIPTION# 文件描述CModelExport# 对应文章PythonOpenGL绘制3D模型九 完善插件功能: 矩阵,材质,法线# 作者李航 Lihang# 使用方法# 1、选择要导出的模型# 2、在命令行窗口中输入# python.ExecuteFile C:/_proj/SuViewer/articles/step3/maxplus_export_sel_model.py# 3、把命令行拖入工具栏可以生成快捷方式方便下次使用# 4、测试可使用的版本3dsmax2016# ELSE..################################# 注意: 保证c:/temp目录存在否则无法导出EXPORT_PATH_FILEc:/temp/CModel.pickle############# CModelExport############classCModelExport:def__init__(self):self.list_mats[]############# export# 插件主入口############defexport(self):modelCModel()forn,obj,triObjinself.EnumSeletciontGeometry():print(find %s, class:%s%(n,obj.GetClassName()))meshtriObj.GetMesh()out_meshself.ProcMesh(n,mesh)model.list_mesh.append(out_mesh)self.printMats()model.list_mats[moformi,moinself.list_mats]hfopen(c:/temp/CModel.pickle,wb)pickle.dump(model,hf,2)hf.close()############# EnumSeletciontGeometry# 1、遍历选择的物体# 2、生成列表sel_list并返回############defEnumSeletciontGeometry(self):sel_list[]forninMaxPlus.SelectionManager.Nodes:# objectobjn.EvalWorldState().Getobj()ifobj.CanConvertToType(MaxPlus.ClassIds.TriMeshGeometry):triObjobj.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(cant conv triMesh, Type is:%s%obj.GetClassName())returnsel_list############# ProcMesh# 1、处理max中的模型# 2、转成需要的CModel数据############defProcMesh(self,node,mesh):print(---ProcMesh()---)## Collect Infomation#tmnode.GetWorldTM()# colornew_meshCMesh()color1node.GetWireColor()new_mesh.color(color1.GetR(),color1.GetG(),color1.GetB())# materialmnode.GetMaterial()new_mesh.matself.ProcMeshMaterial(m,mesh)ifmelseNone## Vertices#num_vertsmesh.GetNumVertices()print(numVertics:%d%num_verts)foriinrange(num_verts):loc_posmesh.GetVertex(i)pointtm.PointTransform(loc_pos)nvCVector3(point.X,point.Y,point.Z)new_mesh.list_vertices.append(nv)## Normals#normalBuilderNormalBuilder()normalBuilder.BuildNormals(mesh)num_normalslen(normalBuilder.list_normals)print(numNormals:%d%num_normals)foriinrange(num_normals):lnnormalBuilder.list_normals[i]nmtm.VectorTransform(ln).Normalize()new_mesh.list_normals.append(CVector3(nm.X,nm.Y,nm.Z))## UV#num_tvertsmesh.GetNumTVerts()print(numTVerts:%d%num_tverts)foriinrange(num_tverts):uvmesh.GetTVert(i)nvCVector3(uv.X,uv.Y,uv.Z)new_mesh.list_uvs.append(nv)## Triangles#num_facesmesh.GetNumFaces()print(numFaces:%d%num_faces)foriinrange(num_faces):trimesh.GetFace(i)smGrouptri.GetSmGroup()vi1tri.GetVert(0)vi2tri.GetVert(1)vi3tri.GetVert(2)ni1normalBuilder.GetNormal(vi1,smGroup)ni2normalBuilder.GetNormal(vi2,smGroup)ni3normalBuilder.GetNormal(vi3,smGroup)tfacemesh.GetTVFace(i)ui1tface.GetA()ui2tface.GetB()ui3tface.GetC()ev1Trueiftri.GetEdgeVis(0)elseFalseev2Trueiftri.GetEdgeVis(1)elseFalseev3Trueiftri.GetEdgeVis(2)elseFalsentCTriangle()nt.a(vi1,ni1,ui1)nt.b(vi2,ni2,ui2)nt.c(vi3,ni3,ui3)normmesh.FaceNormal(i)nt.matIdtri.GetMatID()nt.faceNormalCVector3(norm.X,norm.Y,norm.Z)nt.smGrouptri.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) ))returnnew_mesh############# Material############defProcMeshMaterial(self,m,mesh):print(---CollectMeshMaterials()---)ifm.IsMultiMtl():num_submatm.GetNumSubMtls()refcount[0]*num_submat num_facesmesh.GetNumFaces()foriinrange(num_faces):fmesh.GetFace(i)midf.GetMatID()refcount[mid]1print(refcount:str(refcount))list_submats[]foriinrange(num_submat):ifrefcount[i]:mMatm.GetSubMtl(i)ifmMat:cmself.addMaterial(mMat)list_submats.append(cm)else:list_submats.append(None)else:list_submats.append(None)returnlist_submatselse:returnself.addMaterial(m)defaddMaterial(self,mi):## Find Exist#formin,moutinself.list_mats:ifminmi:returnmout## Create Out Material#moCMaterial()# Diffusecolor1mi.GetDiffuse()mo.diffuse(color1.GetR(),color1.GetG(),color1.GetB())# TextureisubmapMaxPlus.ISubMap._CastFrom(mi)#assert(isubmap, cant cast to ISubMap)texisubmap.GetSubTexmap(1)iftex:bitmapMaxPlus.BitmapTex._CastFrom(tex)texmapbitmap.GetMapName()mo.tex_filepathtexmap mo.tex_bindataself.loadFileData(texmap)# Add to listitem(mi,mo)self.list_mats.append(item)returnmodefloadFileData(self,filename):file1open(filename,moderb)imgdatabytes(file1.read())file1.close()returnbase64.b64encode(imgdata)defprintMats(self):print(---printMats()---)print(Number of Materials: %d%len(self.list_mats))print(----------------)formatId,minenumerate(self.list_mats):mi,momprint(ID: %d%matId)print(source:str(mi))print(diffuse: str(mo.diffuse))print(texture: mo.tex_filepath)############# NormalBuilder############classNormalBuilder:def__init__(self):self.list_verts[]self.list_normals[]classVertex:def__init__(self,p):self.vp self.anNonedefnormals(self):ifself.anisNone:return()eliftype(self.an)islist:returnself.anelse:return(self.an,)defaddNormal(self,n,sg):forvninself.normals():ifvn.sgsg:vn.nvn.nnreturn#not findvnNormalBuilder.VNormal(n,sg)ifself.anisNone:self.anvneliftype(self.an)islist:self.an.append(vn)else:self.an[self.an,vn]classVNormal:def__init__(self,n,sg):self.nn self.sgsg self.idx-1defadd(self,n):self.nself.nndefBuildNormals(self,mesh):print(-----BuildNormals------)## Vertices#num_vertsmesh.GetNumVertices()foriinrange(num_verts):pointmesh.GetVertex(i)vNormalBuilder.Vertex(point)self.list_verts.append(v)num_facesmesh.GetNumFaces()foriinrange(num_faces):fmesh.GetFace(i)faceNormalmesh.FaceNormal(i)smGroupf.GetSmGroup()v1f.GetVert(0)self.list_verts[v1].addNormal(faceNormal,smGroup)v2f.GetVert(1)self.list_verts[v2].addNormal(faceNormal,smGroup)v3f.GetVert(2)self.list_verts[v3].addNormal(faceNormal,smGroup)idx0forvinself.list_verts:forvninv.normals():vn.nvn.n.Normalize()self.list_normals.append(vn.n)vn.idxidx idx1defGetNormal(self,vi,sg):vself.list_verts[vi]forvninv.normals():ifvn.sgsg:returnvn.idxassert(False)############# Main# 1、创建插件导出对象CModelExport# 2、执行export############modelExportCModelExport()modelExport.export()2、CModel.pyimportmathclassCModel:def__init__(self):self.list_mats[]self.list_mesh[]classCMaterial:def__init__(self):self.diffuse(0,0,0)self.tex_filepathself.tex_bindataNoneclassCMesh:def__init__(self):self.nameself.color(0,0,0)self.list_vertices[]self.list_normals[]self.list_uvs[]self.list_tris[]classCTriangle:def__init__(self):self.a(0,0,0)self.b(0,0,0)self.c(0,0,0)self.faceNormalCVector3.zero()self.matId0self.smGroup0self.edgevis(True,True,True)classCVector3:def__init__(self,x,y,z):self.xx self.yy self.zzclassmethoddefzero2(cls):returnCVector3(0.0,0.0,0.0)staticmethoddefzero():returnCVector3(0.0,0.0,0.0)defnormalize(self):s1.0/math.sqrt(self.x*self.xself.y*self.yself.z*self.z)self.x*s self.y*s self.z*sdef__add__(self,R):returnCVector3(self.xR.x,self.yR.y,self.zR.z)系列文章预告目标是开发一个Sketchup Viewer能够显示Sketchup的.skp文件中的3D模型Corona渲染器照片级渲染效果
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进