From 4dbcafc6ae54eddd9668f060a7313517e0baaf22 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Thu, 6 Sep 2018 21:28:12 +0800 Subject: Initial commit...? --- Virtools/3dxml.py | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 Virtools/3dxml.py (limited to 'Virtools/3dxml.py') diff --git a/Virtools/3dxml.py b/Virtools/3dxml.py new file mode 100644 index 0000000..e54f794 --- /dev/null +++ b/Virtools/3dxml.py @@ -0,0 +1,194 @@ +#Chris Xiong 2018 +#Expat (MIT) License +bl_info={ + "name":"3DXML (3.0) import", + "description":"Import 3DXML 3.0", + "author":"Chris Xiong", + "version":(0,1), + "blender":(2,79,0), + "category":"Import-Export", + "support":"TESTING" +} +import bpy,bmesh,bpy_extras,mathutils,zipfile,struct,time +import xml.etree.ElementTree as etree +import pathlib + +NS="{http://www.3ds.com/xsd/3DXML}" + +meshes=dict() +meshmat=dict() +materials=dict() +textures=dict() + +unitfactor=0.01292 +texdir="/Ballance/Textures/" + +def load_textures(tree): + txd=pathlib.Path(texdir) + for tex in tree.findall(f".//{NS}Image"): + txname=tex.attrib["name"] + txp=[i for i in txd.iterdir() if i.stem.lower()==txname.lower()] + tx=bpy.data.textures.new(txname,'IMAGE') + try: + tx.image=bpy.data.images.load(str(txp[0]),True) + except IndexError: + print(txname) + textures[tex.attrib["id"]]=tx + +def load_materials(tree): + for mat in tree.findall(f".//{NS}GraphicMaterial"): + mname=mat.attrib["name"] + m=bpy.data.materials.new(mname) + mslot=m.texture_slots.add() + try: + mslot.texture=textures[mat.attrib["texture"].split(":")[-1]] + except KeyError: + pass + m.diffuse_color=[float(mat.find(f"{NS}Diffuse").attrib[i])for i in ["red","green","blue"]] + m.diffuse_intensity=float(mat.attrib["diffuseCoef"]) + m.specular_color=[float(mat.find(f"{NS}Specular").attrib[i])for i in ["red","green","blue"]] + m.specular_alpha=float(mat.find(f"{NS}Specular").attrib["alpha"]) + m.specular_intensity=float(mat.attrib["specularCoef"]) + materials[mat.attrib["id"]]=m + +def load_meshes(tree): + for rep in tree.findall(f".//{NS}Representation"): + rid=rep.attrib["id"] + verts=unflatten(rep.find(f".//{NS}Positions").text,float,3,unitfactor) + uvs=unflatten(rep.find(f".//{NS}TextureCoordinates").text,float,2) + faces=[] + facemat=[] + matslots=[] + defmat=-1 + facesel=rep.find(f".//{NS}Faces") + if facesel.find(f"{NS}SurfaceAttributes/{NS}MaterialApplication/{NS}MaterialId") is not None: + defmat=0 + matslots.append(facesel.find(f"./{NS}SurfaceAttributes/{NS}MaterialApplication/{NS}MaterialId").text) + for face in facesel.findall(f"{NS}Face"): + fmat=defmat + if face.find(f".//{NS}MaterialId") is not None: + matp=-1 + try: + matp=matslots.index(face.find(f".//{NS}MaterialId").text) + except ValueError: + matp=len(matslots) + matslots.append(face.find(f".//{NS}MaterialId").text) + fmat=matp + if "triangles" in face.attrib: + faces.extend(unflatten(face.attrib["triangles"],int,3)) + facemat.extend([fmat]*len(unflatten(face.attrib["triangles"],int,3))) + if "fans" in face.attrib: + faces.extend(unflatten(face.attrib["fans"],int,4)) + facemat.extend([fmat]*len(unflatten(face.attrib["fans"],int,4))) + meshmat[rid]=matslots + create_mesh(verts,faces,facemat,uvs,rid) + +def load_objects(tree): + rr=tree.findall(f".//{NS}ReferenceRep[@format='TESSELLATED']") + i3d=tree.findall(f".//{NS}Instance3D") + for ref,i3 in zip(rr,i3d): + meshid=ref.attrib["associatedFile"].split(":")[-1] + objname=ref.attrib["name"] + objname=objname[0:objname.rfind('_')] + mat=list(map(float,i3.find(f"./{NS}RelativeMatrix").text.split(' '))) + obj=bpy.data.objects.new(objname,meshes[meshid]) + _wmat=mathutils.Matrix() + for r in range(0,3): + _wmat[r]=[mat[i] for i in range(r,12,3)] + for m in meshmat[meshid]: + obj.data.materials.append(materials[m]) + obj.matrix_world=_wmat + scn=bpy.context.scene + scn.objects.link(obj) + scn.objects.active=obj + obj.select=True + +def create_mesh(verts,faces,facemat,uvs,objidx): + if len(uvs)>len(verts): + uvs.append([uvs[0]]*(len(verts)-len(uvs))) + objname=f"Mesh_{objidx}" + mesh=bmesh.new() + for i in verts: + mesh.verts.new(i) + mesh.verts.ensure_lookup_table() + mesh.verts.index_update() + for i,m in zip(faces,facemat): + f=[mesh.verts[j]for j in i] + try: + nf=mesh.faces.new(f) + if m!=-1:nf.material_index=m + except ValueError: + pass + uv=mesh.loops.layers.uv.new() + for face in mesh.faces: + for lp in face.loops: + lp[uv].uv=mathutils.Vector(uvs[lp.vert.index]) + msh=bpy.data.meshes.new(objname) + mesh.to_mesh(msh) + meshes[objidx]=msh + mesh.free() + +def unflatten(seq,func,step,fac=1): + seq=seq.replace(' ',',') + seq=seq.split(',') + seq=list(map(func,seq)) + nseq=len(seq) + return [tuple(seq[i+j]*fac for j in range(0,step))for i in range(0,nseq,step)] + +def read(filename): + time1=time.time() + if zipfile.is_zipfile(filename): + zf=zipfile.ZipFile(filename,"r") + try: + member=zf.namelist().index("Root.3dxml") + except ValueError: + print("not a 3DXML 3.0 file!") + filename=zf.open("Root.3dxml") + tree=etree.parse(filename) + load_textures(tree) + load_materials(tree) + load_meshes(tree) + load_objects(tree) + time2=time.time() + print("Total import time is: %.2f seconds."%(time2-time1)) + +class ImportDialog(bpy.types.Operator,bpy_extras.io_utils.ImportHelper): + bl_idname="object.tdxml_import" + bl_label="3DXML Import" + filter_glob=bpy.props.StringProperty(default='*.3dxml',options={'HIDDEN'}) + + pt=bpy.props.StringProperty(name="Texture path",default=texdir) + uf=bpy.props.FloatProperty(name="Unit factor",default=unitfactor) + + def execute(self,context): + global texdir,unitfactor + texdir=self.pt + unitfactor=self.uf + read(self.filepath) + return {'FINISHED'} + +class _3DXMLImport(bpy.types.Operator): + """Import a 3DXML 3.0 file""" + bl_idname="import_mesh.tdxml" + bl_label="Import 3DXML 3.0..." + bl_options={'UNDO'} + filename_ext=".3dxml" + + def execute(self,context): + bpy.ops.object.tdxml_import('INVOKE_DEFAULT') + return {'FINISHED'} + +def menu_func_import_tdxml(self,context): + self.layout.operator(_3DXMLImport.bl_idname,text="3DXML 3.0 (.3dxml)") + +def register(): + bpy.utils.register_class(ImportDialog) + bpy.utils.register_class(_3DXMLImport) + bpy.types.INFO_MT_file_import.append(menu_func_import_tdxml) + +def unregister(): + bpy.utils.unregister_class(_3DXMLImport) + bpy.utils.unregister_class(ImportDialog) + +if __name__=="__main__": + register() -- cgit v1.2.3