Skip to content
Snippets Groups Projects
Commit 3659c4da authored by Jacques Lucke's avatar Jacques Lucke
Browse files

port 'Stanford PLY format' addon to Blender 2.8

Here are a couple of example files for testing: https://people.sc.fsu.edu/~jburkardt/data/ply/ply.html

I removed the texture support that was implemented here: rBA471370
(it is no official part of the file format; the exporter did not support it; reimplementing it is a bit of a hassle)

Reviewers: brecht

Differential Revision: https://developer.blender.org/D3754
parent 608cf349
No related branches found
No related tags found
No related merge requests found
......@@ -22,7 +22,7 @@ bl_info = {
"name": "Stanford PLY format",
"author": "Bruce Merry, Campbell Barton",
"version": (1, 0, 0),
"blender": (2, 74, 0),
"blender": (2, 80, 0),
"location": "File > Import-Export",
"description": "Import-Export PLY mesh data withs UV's and vertex colors",
"warning": "",
......@@ -56,8 +56,8 @@ from bpy.props import (
from bpy_extras.io_utils import (
ImportHelper,
ExportHelper,
orientation_helper,
axis_conversion,
orientation_helper
)
......@@ -67,15 +67,15 @@ class ImportPLY(bpy.types.Operator, ImportHelper):
bl_label = "Import PLY"
bl_options = {'UNDO'}
files = CollectionProperty(name="File Path",
files: CollectionProperty(name="File Path",
description="File path used for importing "
"the PLY file",
type=bpy.types.OperatorFileListElement)
directory = StringProperty()
directory: StringProperty()
filename_ext = ".ply"
filter_glob = StringProperty(default="*.ply", options={'HIDDEN'})
filter_glob: StringProperty(default="*.ply", options={'HIDDEN'})
def execute(self, context):
paths = [os.path.join(self.directory, name.name)
......@@ -91,7 +91,6 @@ class ImportPLY(bpy.types.Operator, ImportHelper):
return {'FINISHED'}
@orientation_helper(axis_forward='Y', axis_up='Z')
class ExportPLY(bpy.types.Operator, ExportHelper):
"""Export a single object as a Stanford PLY with normals, """ \
......@@ -100,14 +99,14 @@ class ExportPLY(bpy.types.Operator, ExportHelper):
bl_label = "Export PLY"
filename_ext = ".ply"
filter_glob = StringProperty(default="*.ply", options={'HIDDEN'})
filter_glob: StringProperty(default="*.ply", options={'HIDDEN'})
use_mesh_modifiers = BoolProperty(
use_mesh_modifiers: BoolProperty(
name="Apply Modifiers",
description="Apply Modifiers to the exported mesh",
default=True,
)
use_normals = BoolProperty(
use_normals: BoolProperty(
name="Normals",
description="Export Normals for smooth and "
"hard shaded faces "
......@@ -115,18 +114,18 @@ class ExportPLY(bpy.types.Operator, ExportHelper):
"as individual faces)",
default=True,
)
use_uv_coords = BoolProperty(
use_uv_coords: BoolProperty(
name="UVs",
description="Export the active UV layer",
default=True,
)
use_colors = BoolProperty(
use_colors: BoolProperty(
name="Vertex Colors",
description="Export the active vertex color layer",
default=True,
)
global_scale = FloatProperty(
global_scale: FloatProperty(
name="Scale",
min=0.01, max=1000.0,
default=1.0,
......@@ -149,7 +148,7 @@ class ExportPLY(bpy.types.Operator, ExportHelper):
))
global_matrix = axis_conversion(to_forward=self.axis_forward,
to_up=self.axis_up,
).to_4x4() * Matrix.Scale(self.global_scale, 4)
).to_4x4() @ Matrix.Scale(self.global_scale, 4)
keywords["global_matrix"] = global_matrix
filepath = self.filepath
......
......@@ -100,10 +100,8 @@ def save_mesh(filepath,
col = active_col_layer[i]
col = col.color1[:], col.color2[:], col.color3[:], col.color4[:]
f_verts = f.vertices
pf = ply_faces[i]
for j, vidx in enumerate(f_verts):
for j, vidx in enumerate(f.vertices):
v = mesh_verts[vidx]
if smooth:
......@@ -119,6 +117,7 @@ def save_mesh(filepath,
color = (int(color[0] * 255.0),
int(color[1] * 255.0),
int(color[2] * 255.0),
255
)
key = normal_key, uvcoord_key, color
......@@ -193,7 +192,6 @@ def save(operator,
global_matrix=None
):
scene = context.scene
obj = context.active_object
if global_matrix is None:
......@@ -204,14 +202,15 @@ def save(operator,
bpy.ops.object.mode_set(mode='OBJECT')
if use_mesh_modifiers and obj.modifiers:
mesh = obj.to_mesh(scene, True, 'PREVIEW')
mesh = obj.to_mesh(context.depsgraph, True)
else:
mesh = obj.data.copy()
if not mesh:
raise Exception("Error, could not get mesh data from active object")
mesh.transform(global_matrix * obj.matrix_world)
mesh.transform(global_matrix @ obj.matrix_world)
if use_normals:
mesh.calc_normals()
......@@ -221,7 +220,6 @@ def save(operator,
use_colors=use_colors,
)
if use_mesh_modifiers:
bpy.data.meshes.remove(mesh)
bpy.data.meshes.remove(mesh)
return ret
......@@ -126,7 +126,6 @@ class object_spec(object):
def read(filepath):
format = b''
texture = b''
version = b'1.0'
format_specs = {b'binary_little_endian': '<',
b'binary_big_endian': '>',
......@@ -168,13 +167,6 @@ def read(filepath):
valid_header = True
break
elif tokens[0] == b'comment':
if len(tokens) < 2:
continue
elif tokens[1] == b'TextureFile':
if len(tokens) < 4:
print('Invalid texture line')
else:
texture = tokens[2]
continue
elif tokens[0] == b'obj_info':
continue
......@@ -214,7 +206,7 @@ def read(filepath):
obj = obj_spec.load(format_specs[format], plyf)
return obj_spec, obj, texture
return obj_spec, obj
import bpy
......@@ -222,9 +214,8 @@ import bpy
def load_ply_mesh(filepath, ply_name):
from bpy_extras.io_utils import unpack_face_list
# from bpy_extras.image_utils import load_image # UNUSED
obj_spec, obj, texture = read(filepath)
obj_spec, obj = read(filepath)
if obj is None:
print('Invalid file')
return
......@@ -346,35 +337,8 @@ def load_ply_mesh(filepath, ply_name):
col[2] = ply_col[j][2]
col[3] = ply_col[j][3]
mesh.validate()
mesh.update()
if texture and uvindices:
import os
import sys
from bpy_extras.image_utils import load_image
encoding = sys.getfilesystemencoding()
encoded_texture = texture.decode(encoding=encoding)
name = bpy.path.display_name_from_filepath(texture)
image = load_image(encoded_texture, os.path.dirname(filepath), recursive=True, place_holder=True)
if image:
texture = bpy.data.textures.new(name=name, type='IMAGE')
texture.image = image
material = bpy.data.materials.new(name=name)
material.use_shadeless = True
mtex = material.texture_slots.add()
mtex.texture = texture
mtex.texture_coords = 'UV'
mtex.use_map_color_diffuse = True
mesh.materials.append(material)
for face in mesh.uv_textures[0].data:
face.image = image
mesh.validate()
return mesh
......@@ -389,12 +353,10 @@ def load_ply(filepath):
if not mesh:
return {'CANCELLED'}
scn = bpy.context.scene
obj = bpy.data.objects.new(ply_name, mesh)
scn.objects.link(obj)
scn.objects.active = obj
obj.select = True
bpy.context.collection.objects.link(obj)
bpy.context.view_layer.objects.active = obj
obj.select_set("SELECT")
print('\nSuccessfully imported %r in %.3f sec' % (filepath, time.time() - t))
return {'FINISHED'}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment