aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2018-09-06 21:28:12 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2018-09-06 21:28:12 +0800
commit4dbcafc6ae54eddd9668f060a7313517e0baaf22 (patch)
tree356941c82ec823a408b51cbd0c6c37fcd08f2463
downloadoddities-4dbcafc6ae54eddd9668f060a7313517e0baaf22.tar.xz
Initial commit...?
-rw-r--r--Virtools/3dxml.py194
1 files changed, 194 insertions, 0 deletions
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()