Revert "PLY: refactor exporter"
This reverts commit 7f4c2d5e48
.
Issues with unit tests.
This commit is contained in:
parent
3fc4640761
commit
4c7e2b5a9e
|
@ -20,7 +20,7 @@
|
|||
|
||||
bl_info = {
|
||||
"name": "Stanford PLY format",
|
||||
"author": "Bruce Merry, Campbell Barton, Bastien Montagne, Mikhail Rachinsky",
|
||||
"author": "Bruce Merry, Campbell Barton", "Bastien Montagne"
|
||||
"version": (2, 1, 0),
|
||||
"blender": (2, 90, 0),
|
||||
"location": "File > Import/Export",
|
||||
|
|
|
@ -23,17 +23,23 @@ This script exports Stanford PLY files from Blender. It supports normals,
|
|||
colors, and texture coordinates per face or per vertex.
|
||||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
class _PLYface:
|
||||
__slots__ = "verts", "sides"
|
||||
|
||||
def __init__(self, sides: int) -> None:
|
||||
self.verts = []
|
||||
self.sides = sides
|
||||
|
||||
|
||||
def _write_binary(fw, ply_verts: list, ply_faces: list) -> None:
|
||||
def _write_binary(fw, ply_verts: list, ply_faces: list[_PLYface], mesh_verts: list) -> None:
|
||||
from struct import pack
|
||||
|
||||
# Vertex data
|
||||
# ---------------------------
|
||||
|
||||
for v, normal, uv_coords, color in ply_verts:
|
||||
fw(pack("<3f", *v.co))
|
||||
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:
|
||||
|
@ -45,21 +51,20 @@ def _write_binary(fw, ply_verts: list, ply_faces: list) -> None:
|
|||
# ---------------------------
|
||||
|
||||
for pf in ply_faces:
|
||||
length = len(pf)
|
||||
fw(pack(f"<B{length}I", length, *pf))
|
||||
fw(pack(f"<B{pf.sides}I", pf.sides, *pf.verts))
|
||||
|
||||
|
||||
def _write_ascii(fw, ply_verts: list, ply_faces: list) -> None:
|
||||
def _write_ascii(fw, ply_verts: list, ply_faces: list[_PLYface], mesh_verts: list) -> None:
|
||||
|
||||
# Vertex data
|
||||
# ---------------------------
|
||||
|
||||
for v, normal, uv_coords, color in ply_verts:
|
||||
fw(b"%.6f %.6f %.6f" % v.co[:])
|
||||
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[:])
|
||||
fw(b" %.6f %.6f %.6f" % normal)
|
||||
if uv_coords is not None:
|
||||
fw(b" %.6f %.6f" % uv_coords[:])
|
||||
fw(b" %.6f %.6f" % uv_coords)
|
||||
if color is not None:
|
||||
fw(b" %u %u %u %u" % color)
|
||||
fw(b"\n")
|
||||
|
@ -68,46 +73,94 @@ def _write_ascii(fw, ply_verts: list, ply_faces: list) -> None:
|
|||
# ---------------------------
|
||||
|
||||
for pf in ply_faces:
|
||||
fw(b"%d" % len(pf))
|
||||
for index in pf:
|
||||
fw(b"%d" % pf.sides)
|
||||
for index in pf.verts:
|
||||
fw(b" %d" % index)
|
||||
fw(b"\n")
|
||||
|
||||
|
||||
def save_mesh(filepath, bm, use_ascii, use_normals, use_uv, use_color):
|
||||
uv_lay = bm.loops.layers.uv.active
|
||||
col_lay = bm.loops.layers.color.active
|
||||
def save_mesh(filepath, mesh, use_ascii, use_normals, use_uv_coords, use_colors):
|
||||
import bpy
|
||||
|
||||
use_uv = use_uv and uv_lay is not None
|
||||
use_color = use_color and col_lay is not None
|
||||
uv = color = None
|
||||
def rvec3d(v):
|
||||
return round(v[0], 6), round(v[1], 6), round(v[2], 6)
|
||||
|
||||
ply_verts = [None for _ in range(len(bm.verts))]
|
||||
def rvec2d(v):
|
||||
return round(v[0], 6), round(v[1], 6)
|
||||
|
||||
if use_uv_coords and mesh.uv_layers:
|
||||
active_uv_layer = mesh.uv_layers.active.data
|
||||
else:
|
||||
use_uv_coords = False
|
||||
|
||||
if use_colors and mesh.vertex_colors:
|
||||
active_col_layer = mesh.vertex_colors.active.data
|
||||
else:
|
||||
use_colors = False
|
||||
|
||||
# in case
|
||||
color = uvcoord = uvcoord_key = normal = normal_key = None
|
||||
|
||||
mesh_verts = mesh.vertices
|
||||
# vdict = {} # (index, normal, uv) -> new index
|
||||
vdict = [{} for _ in range(len(mesh_verts))]
|
||||
ply_verts = []
|
||||
ply_faces = []
|
||||
vert_count = 0
|
||||
|
||||
for f in mesh.polygons:
|
||||
|
||||
if use_normals:
|
||||
smooth = f.use_smooth
|
||||
if not smooth:
|
||||
normal = f.normal[:]
|
||||
normal_key = rvec3d(normal)
|
||||
|
||||
if use_uv_coords:
|
||||
uv = [
|
||||
active_uv_layer[l].uv[:]
|
||||
for l in range(f.loop_start, f.loop_start + f.loop_total)
|
||||
]
|
||||
if use_colors:
|
||||
col = [
|
||||
active_col_layer[l].color[:]
|
||||
for l in range(f.loop_start, f.loop_start + f.loop_total)
|
||||
]
|
||||
|
||||
pf = _PLYface(f.loop_total)
|
||||
for i, vidx in enumerate(f.vertices):
|
||||
v = mesh_verts[vidx]
|
||||
|
||||
if use_normals and smooth:
|
||||
normal = v.normal[:]
|
||||
normal_key = rvec3d(normal)
|
||||
|
||||
if use_uv_coords:
|
||||
uvcoord = uv[i][0], uv[i][1]
|
||||
uvcoord_key = rvec2d(uvcoord)
|
||||
|
||||
if use_colors:
|
||||
color = col[i]
|
||||
color = (
|
||||
int(color[0] * 255.0),
|
||||
int(color[1] * 255.0),
|
||||
int(color[2] * 255.0),
|
||||
int(color[3] * 255.0),
|
||||
)
|
||||
key = normal_key, uvcoord_key, color
|
||||
|
||||
vdict_local = vdict[vidx]
|
||||
pf_vidx = vdict_local.get(key) # Will be None initially
|
||||
|
||||
if pf_vidx is None: # Same as vdict_local.has_key(key)
|
||||
pf_vidx = vdict_local[key] = vert_count
|
||||
ply_verts.append((vidx, normal, uvcoord, color))
|
||||
vert_count += 1
|
||||
|
||||
pf.verts.append(pf_vidx)
|
||||
|
||||
for f in bm.faces:
|
||||
pf = []
|
||||
ply_faces.append(pf)
|
||||
|
||||
normal = None
|
||||
if use_normals and not f.smooth:
|
||||
normal = f.normal
|
||||
|
||||
for loop in f.loops:
|
||||
v = loop.vert
|
||||
pf.append(v.index)
|
||||
|
||||
if not v.tag:
|
||||
if use_normals and normal is None:
|
||||
normal = v.normal
|
||||
if use_uv:
|
||||
uv = loop[uv_lay].uv
|
||||
if use_color:
|
||||
color = tuple(int(x * 255.0) for x in loop[col_lay])
|
||||
|
||||
ply_verts[v.index] = (v, normal, uv, color)
|
||||
v.tag = True
|
||||
|
||||
with open(filepath, "wb") as file:
|
||||
fw = file.write
|
||||
file_format = b"ascii" if use_ascii else b"binary_little_endian"
|
||||
|
@ -131,12 +184,12 @@ def save_mesh(filepath, bm, use_ascii, use_normals, use_uv, use_color):
|
|||
b"property float ny\n"
|
||||
b"property float nz\n"
|
||||
)
|
||||
if use_uv:
|
||||
if use_uv_coords:
|
||||
fw(
|
||||
b"property float s\n"
|
||||
b"property float t\n"
|
||||
)
|
||||
if use_color:
|
||||
if use_colors:
|
||||
fw(
|
||||
b"property uchar red\n"
|
||||
b"property uchar green\n"
|
||||
|
@ -144,7 +197,7 @@ def save_mesh(filepath, bm, use_ascii, use_normals, use_uv, use_color):
|
|||
b"property uchar alpha\n"
|
||||
)
|
||||
|
||||
fw(b"element face %d\n" % len(ply_faces))
|
||||
fw(b"element face %d\n" % len(mesh.polygons))
|
||||
fw(b"property list uchar uint vertex_indices\n")
|
||||
fw(b"end_header\n")
|
||||
|
||||
|
@ -152,9 +205,9 @@ def save_mesh(filepath, bm, use_ascii, use_normals, use_uv, use_color):
|
|||
# ---------------------------
|
||||
|
||||
if use_ascii:
|
||||
_write_ascii(fw, ply_verts, ply_faces)
|
||||
_write_ascii(fw, ply_verts, ply_faces, mesh_verts)
|
||||
else:
|
||||
_write_binary(fw, ply_verts, ply_faces)
|
||||
_write_binary(fw, ply_verts, ply_faces, mesh_verts)
|
||||
|
||||
|
||||
def save(
|
||||
|
@ -169,6 +222,7 @@ def save(
|
|||
global_matrix=None,
|
||||
):
|
||||
import time
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
t = time.time()
|
||||
|
@ -203,22 +257,26 @@ def save(
|
|||
if (ngons := [f for f in bm.faces if len(f.verts) > 255]):
|
||||
bmesh.ops.triangulate(bm, faces=ngons)
|
||||
|
||||
mesh = bpy.data.meshes.new("TMP PLY EXPORT")
|
||||
bm.to_mesh(mesh)
|
||||
bm.free()
|
||||
|
||||
if global_matrix is not None:
|
||||
bm.transform(global_matrix)
|
||||
mesh.transform(global_matrix)
|
||||
|
||||
if use_normals:
|
||||
bm.normal_update()
|
||||
mesh.calc_normals()
|
||||
|
||||
save_mesh(
|
||||
filepath,
|
||||
bm,
|
||||
mesh,
|
||||
use_ascii,
|
||||
use_normals,
|
||||
use_uv_coords,
|
||||
use_colors,
|
||||
)
|
||||
|
||||
bm.free()
|
||||
bpy.data.meshes.remove(mesh)
|
||||
|
||||
t_delta = time.time() - t
|
||||
print(f"Export completed {filepath!r} in {t_delta:.3f}")
|
||||
|
|
Loading…
Reference in New Issue