diff options
-rw-r--r-- | io_mesh_ply/__init__.py | 24 | ||||
-rw-r--r-- | io_mesh_ply/export_ply.py | 154 | ||||
-rw-r--r-- | io_mesh_ply/import_ply.py | 16 |
3 files changed, 120 insertions, 74 deletions
diff --git a/io_mesh_ply/__init__.py b/io_mesh_ply/__init__.py index 835ae60e..2cfb09c3 100644 --- a/io_mesh_ply/__init__.py +++ b/io_mesh_ply/__init__.py @@ -21,9 +21,9 @@ bl_info = { "name": "Stanford PLY format", "author": "Bruce Merry, Campbell Barton", - "version": (1, 1, 0), - "blender": (2, 82, 0), - "location": "File > Import-Export", + "version": (2, 0, 0), + "blender": (2, 90, 0), + "location": "File > Import/Export", "description": "Import-Export PLY mesh data with UVs and vertex colors", "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/mesh_ply.html", "support": 'OFFICIAL', @@ -107,6 +107,10 @@ class ExportPLY(bpy.types.Operator, ExportHelper): filename_ext = ".ply" filter_glob: StringProperty(default="*.ply", options={'HIDDEN'}) + use_ascii: BoolProperty( + name="ASCII", + description="Export using ASCII file format, otherwise use binary", + ) use_selection: BoolProperty( name="Selection Only", description="Export selected objects only", @@ -164,10 +168,20 @@ class ExportPLY(bpy.types.Operator, ExportHelper): filepath = self.filepath filepath = bpy.path.ensure_ext(filepath, self.filename_ext) - return export_ply.save(self, context, **keywords) + export_ply.save(context, **keywords) + + return {'FINISHED'} def draw(self, context): - pass + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + sfile = context.space_data + operator = sfile.active_operator + + col = layout.column(heading="Format") + col.prop(operator, "use_ascii") class PLY_PT_export_include(bpy.types.Panel): diff --git a/io_mesh_ply/export_ply.py b/io_mesh_ply/export_ply.py index 812aeb54..060b3d02 100644 --- a/io_mesh_ply/export_ply.py +++ b/io_mesh_ply/export_ply.py @@ -24,8 +24,55 @@ colors, and texture coordinates per face or per vertex. """ -def save_mesh(filepath, mesh, use_normals=True, use_uv_coords=True, use_colors=True): - import os +def _write_binary(fw, ply_verts, ply_faces, mesh_verts): + from struct import pack + + # Vertex data + # --------------------------- + + for index, normal, uv_coords, color in ply_verts: + fw(pack("<3f", *mesh_verts[index].co)) + if normal is not None: + fw(pack("<3f", *normal)) + if uv_coords is not None: + fw(pack("<2f", *uv_coords)) + if color is not None: + fw(pack("<4B", *color)) + + # Face data + # --------------------------- + + for pf in ply_faces: + length = len(pf) + fw(pack("<B%dI" % length, length, *pf)) + + +def _write_ascii(fw, ply_verts, ply_faces, mesh_verts): + + # Vertex data + # --------------------------- + + for index, normal, uv_coords, color in ply_verts: + fw(b"%.6f %.6f %.6f" % mesh_verts[index].co[:]) + if normal is not None: + fw(b" %.6f %.6f %.6f" % normal) + if uv_coords is not None: + fw(b" %.6f %.6f" % uv_coords) + if color is not None: + fw(b" %u %u %u %u" % color) + fw(b"\n") + + # Face data + # --------------------------- + + for pf in ply_faces: + fw(b"%d" % len(pf)) + for index in pf: + fw(b" %d" % index) + fw(b"\n") + + +def save_mesh(filepath, mesh, use_ascii, use_normals, use_uv_coords, use_colors): import bpy def rvec3d(v): @@ -56,10 +103,11 @@ def save_mesh(filepath, mesh, use_normals=True, use_uv_coords=True, use_colors=T for i, f in enumerate(mesh.polygons): - smooth = not use_normals or f.use_smooth - if not smooth: - normal = f.normal[:] - normal_key = rvec3d(normal) + if use_normals: + smooth = f.use_smooth + if not smooth: + normal = f.normal[:] + normal_key = rvec3d(normal) if use_uv_coords: uv = [ @@ -76,7 +124,7 @@ def save_mesh(filepath, mesh, use_normals=True, use_uv_coords=True, use_colors=T for j, vidx in enumerate(f.vertices): v = mesh_verts[vidx] - if smooth: + if use_normals and smooth: normal = v.normal[:] normal_key = rvec3d(normal) @@ -104,90 +152,72 @@ def save_mesh(filepath, mesh, use_normals=True, use_uv_coords=True, use_colors=T pf.append(pf_vidx) - with open(filepath, "w", encoding="utf-8", newline="\n") as file: + with open(filepath, "wb") as file: fw = file.write + file_format = b"ascii" if use_ascii else b"binary_little_endian" # Header # --------------------------- - fw("ply\n") - fw("format ascii 1.0\n") - fw( - f"comment Created by Blender {bpy.app.version_string} - " - f"www.blender.org, source file: {os.path.basename(bpy.data.filepath)!r}\n" - ) + fw(b"ply\n") + fw(b"format %s 1.0\n" % file_format) + fw(b"comment Created by Blender %s - www.blender.org\n" % bpy.app.version_string.encode("utf-8")) - fw(f"element vertex {len(ply_verts)}\n") + fw(b"element vertex %d\n" % len(ply_verts)) fw( - "property float x\n" - "property float y\n" - "property float z\n" + b"property float x\n" + b"property float y\n" + b"property float z\n" ) if use_normals: fw( - "property float nx\n" - "property float ny\n" - "property float nz\n" + b"property float nx\n" + b"property float ny\n" + b"property float nz\n" ) if use_uv_coords: fw( - "property float s\n" - "property float t\n" + b"property float s\n" + b"property float t\n" ) if use_colors: fw( - "property uchar red\n" - "property uchar green\n" - "property uchar blue\n" - "property uchar alpha\n" + b"property uchar red\n" + b"property uchar green\n" + b"property uchar blue\n" + b"property uchar alpha\n" ) - fw(f"element face {len(mesh.polygons)}\n") - fw("property list uchar uint vertex_indices\n") - - fw("end_header\n") + fw(b"element face %d\n" % len(mesh.polygons)) + fw(b"property list uchar uint vertex_indices\n") + fw(b"end_header\n") - # Vertex data + # Geometry # --------------------------- - for i, v in enumerate(ply_verts): - fw("%.6f %.6f %.6f" % mesh_verts[v[0]].co[:]) - if use_normals: - fw(" %.6f %.6f %.6f" % v[1]) - if use_uv_coords: - fw(" %.6f %.6f" % v[2]) - if use_colors: - fw(" %u %u %u %u" % v[3]) - fw("\n") - - # Face data - # --------------------------- - - for pf in ply_faces: - fw(f"{len(pf)}") - for v in pf: - fw(f" {v}") - fw("\n") - - print(f"Writing {filepath!r} done") - - return {'FINISHED'} + if use_ascii: + _write_ascii(fw, ply_verts, ply_faces, mesh_verts) + else: + _write_binary(fw, ply_verts, ply_faces, mesh_verts) def save( - operator, context, filepath="", + use_ascii=False, use_selection=False, use_mesh_modifiers=True, use_normals=True, use_uv_coords=True, use_colors=True, - global_matrix=None + global_matrix=None, ): + import time import bpy import bmesh + t = time.time() + if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') @@ -224,14 +254,16 @@ def save( if use_normals: mesh.calc_normals() - ret = save_mesh( + save_mesh( filepath, mesh, - use_normals=use_normals, - use_uv_coords=use_uv_coords, - use_colors=use_colors, + use_ascii, + use_normals, + use_uv_coords, + use_colors, ) bpy.data.meshes.remove(mesh) - return ret + t_delta = time.time() - t + print(f"Export completed {filepath!r} in {t_delta:.3f}") diff --git a/io_mesh_ply/import_ply.py b/io_mesh_ply/import_ply.py index 6df2ec81..2bc67746 100644 --- a/io_mesh_ply/import_ply.py +++ b/io_mesh_ply/import_ply.py @@ -272,20 +272,20 @@ def load_ply_mesh(filepath, ply_name): if len(colindices) == 3: mesh_colors.extend([ ( - vertices[index][colindices[0]] * colmultiply[0], - vertices[index][colindices[1]] * colmultiply[1], - vertices[index][colindices[2]] * colmultiply[2], - 1.0, + vertices[index][colindices[0]] * colmultiply[0], + vertices[index][colindices[1]] * colmultiply[1], + vertices[index][colindices[2]] * colmultiply[2], + 1.0, ) for index in indices ]) elif len(colindices) == 4: mesh_colors.extend([ ( - vertices[index][colindices[0]] * colmultiply[0], - vertices[index][colindices[1]] * colmultiply[1], - vertices[index][colindices[2]] * colmultiply[2], - vertices[index][colindices[3]] * colmultiply[3], + vertices[index][colindices[0]] * colmultiply[0], + vertices[index][colindices[1]] * colmultiply[1], + vertices[index][colindices[2]] * colmultiply[2], + vertices[index][colindices[3]] * colmultiply[3], ) for index in indices ]) |