3D Print Toolbox: Add hollow out #105194
@ -853,66 +853,66 @@ class MESH_OT_print3d_hollow(Operator):
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pyopenvdb as vdb
|
import pyopenvdb as vdb
|
||||||
|
|
||||||
offset = self.offset
|
if not self.offset:
|
||||||
resolution = self.resolution
|
return {'FINISHED'}
|
||||||
join = self.join
|
|
||||||
|
|
||||||
mode_orig = context.mode
|
|
||||||
|
|
||||||
MikhailRachinskiy marked this conversation as resolved
|
|||||||
# Target object
|
# Target object
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
m = obj.data # mesh
|
depsgraph = context.evaluated_depsgraph_get()
|
||||||
|
mesh_target = bpy.data.meshes.new_from_object(obj.evaluated_get(depsgraph))
|
||||||
|
mesh_target.transform(obj.matrix_world)
|
||||||
|
|
||||||
# Read mesh to numpy arrays
|
# Read mesh to numpy arrays
|
||||||
nverts = len(m.vertices)
|
nverts = len(mesh_target.vertices)
|
||||||
ntris = len(m.loop_triangles)
|
ntris = len(mesh_target.loop_triangles)
|
||||||
verts = np.zeros(3*nverts, dtype=np.float32)
|
verts = np.zeros(3 * nverts, dtype=np.float32)
|
||||||
tris = np.zeros(3*ntris, dtype=np.int32)
|
tris = np.zeros(3 * ntris, dtype=np.int32)
|
||||||
m.vertices.foreach_get('co', verts)
|
mesh_target.vertices.foreach_get('co', verts)
|
||||||
verts.shape = (-1, 3)
|
verts.shape = (-1, 3)
|
||||||
m.loop_triangles.foreach_get('vertices', tris)
|
mesh_target.loop_triangles.foreach_get('vertices', tris)
|
||||||
tris.shape = (-1, 3)
|
tris.shape = (-1, 3)
|
||||||
|
|
||||||
# Generate VDB levelset
|
# Generate VDB levelset
|
||||||
half_width = max(3.0, math.ceil(abs(offset)/resolution) + 2.0) # half_width has to envelop offset
|
half_width = max(3.0, math.ceil(abs(self.offset) / self.resolution) + 2.0) # half_width has to envelop offset
|
||||||
trans = vdb.Transform()
|
trans = vdb.Transform()
|
||||||
trans.scale(resolution)
|
trans.scale(self.resolution)
|
||||||
levelset = vdb.FloatGrid.createLevelSetFromPolygons(verts, triangles=tris,
|
levelset = vdb.FloatGrid.createLevelSetFromPolygons(verts, triangles=tris, transform=trans, halfWidth=half_width)
|
||||||
transform=trans, halfWidth=half_width)
|
|
||||||
|
|
||||||
# Generate offset surface
|
# Generate offset surface
|
||||||
newverts, newquads = levelset.convertToQuads(offset)
|
newverts, newquads = levelset.convertToQuads(self.offset)
|
||||||
polys = [x for x in newquads]
|
polys = list(newquads)
|
||||||
|
|
||||||
# Instantiate new object in Blender
|
# Instantiate new object in Blender
|
||||||
mesh = bpy.data.meshes.new(m.name + ' offset')
|
mesh_offset = bpy.data.meshes.new(mesh_target.name + ' offset')
|
||||||
mesh.from_pydata(newverts, [], polys)
|
mesh_offset.from_pydata(newverts, [], polys)
|
||||||
newobj = bpy.data.objects.new(obj.name + ' offset', mesh)
|
obj_offset = bpy.data.objects.new(obj.name + ' offset', mesh_offset)
|
||||||
newobj.matrix_world = obj.matrix_world.copy()
|
bpy.context.collection.objects.link(obj_offset)
|
||||||
bpy.context.collection.objects.link(newobj)
|
|
||||||
|
|
||||||
if not join:
|
if not self.join:
|
||||||
# For some reason OpenVDB has inverted normals
|
# For some reason OpenVDB has inverted normals
|
||||||
mesh.flip_normals()
|
mesh_offset.flip_normals()
|
||||||
|
# This mesh will not be used anymore
|
||||||
|
bpy.data.meshes.remove(mesh_target)
|
||||||
else:
|
else:
|
||||||
if offset < 0.0:
|
# Create a copy of the target object with applied modifiers, scale
|
||||||
|
obj_hollow = bpy.data.objects.new(obj.name + " hollow", mesh_target)
|
||||||
|
bpy.context.collection.objects.link(obj_hollow)
|
||||||
|
if self.offset < 0.0:
|
||||||
# Offset surface already has normals as they should, see above
|
# Offset surface already has normals as they should, see above
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# Offset surface is outside, correct normals, see above
|
# Offset surface is outside, correct normals, see above
|
||||||
mesh.flip_normals()
|
mesh_offset.flip_normals()
|
||||||
# Original surface is inside, flip its normals
|
# Original surface is inside, flip its normals
|
||||||
m.flip_normals()
|
mesh_target.flip_normals()
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
bpy.ops.object.select_all(action='DESELECT')
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
newobj.select_set(True)
|
obj_offset.select_set(True)
|
||||||
obj.select_set(True)
|
obj_hollow.select_set(True)
|
||||||
context.view_layer.objects.active = obj
|
context.view_layer.objects.active = obj_hollow
|
||||||
bpy.ops.object.join()
|
bpy.ops.object.join()
|
||||||
|
|
||||||
if mode_orig == 'EDIT_MESH':
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
@ -921,6 +921,8 @@ class MESH_OT_print3d_hollow(Operator):
|
|||||||
self.offset = print_3d.hollow_offset
|
self.offset = print_3d.hollow_offset
|
||||||
self.resolution = print_3d.hollow_resolution
|
self.resolution = print_3d.hollow_resolution
|
||||||
self.join = print_3d.hollow_join
|
self.join = print_3d.hollow_join
|
||||||
|
if context.mode == 'EDIT_MESH':
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user
It's better to not create unnecessary local variables, especially when they are rarely used.