Following the comments in the question and the edit of it, here is a script that automates the cuts and smooth normals to the original.
The principle is the following:
- Copy the original mesh
- Set a data transfer modifier on the copy targeting the original
- Cut the copy
- Remove double vertices (because the cuts may create doubles and these doubles explain what is shown in the edited question)
- Apply the modifier
The code is commented below. But if the comments are not clear enough, please tell.
import bpy, bmesh
from math import pi
from mathutils import Vector
#Utility: test if obj exists and is a mesh
def MeshObject( obj ):
return obj is not None and obj.type == 'MESH'
#Utility: go in the specified mode, call the lambda and returns to previous mode
def InMode( obj, mode, call ):
prevMode = obj.mode
result = None
try:
bpy.ops.object.mode_set( mode = mode, toggle = False )
result = call()
finally:
bpy.ops.object.mode_set( mode = prevMode, toggle = False )
return result
#Cut the mesh and gets the normals for the vertices created during the cut
def CutMesh( obj, cuts ): #Original code from CoDEmanX
bm = bmesh.from_edit_mesh( obj.data )
for (plane_co, plane_no) in cuts:
#Adds a bisectrice following the cut
result = bmesh.ops.bisect_plane( bm, geom = bm.verts[:] + bm.edges[:] + bm.faces[:], plane_co = plane_co, plane_no = plane_no )
#Gets the created bm edges from the result
edges = [e for e in result['geom_cut'] if isinstance( e, bmesh.types.BMEdge )]
#Splits the mesh according to these edges
bmesh.ops.split_edges( bm, edges = edges )
bmesh.update_edit_mesh( obj.data )
#Select all
def SelectAllVertices( obj ):
for v in obj.data.vertices: v.select = True
#Get selected objects
def GetSelectedObjects():
return bpy.context.selected_objects[:]
#Removes double vertices at the normals positions
def RemoveDoubles( obj ):
bm = bmesh.from_edit_mesh( obj.data )
bmesh.ops.remove_doubles( bm, verts = bm.verts[:] )
bmesh.update_edit_mesh( obj.data )
#Duplicate the object
def DuplicateObject( obj, scene ):
newObj = obj.copy()
newObj.data = obj.data.copy()
newObj.animation_data_clear()
scene.objects.link( newObj )
return newObj
#Duplicate the mesh and add a data transfert modifier to the copy
def DuplicateObjectAndDataTransfert( obj ):
copy = DuplicateObject( obj, bpy.context.scene )
#Auto smooth is needed as if not, the normals will be lost when the modifier will be applied
copy.data.use_auto_smooth = True
#Create the modifier, keeping mainly the default options
mod = copy.modifiers.new( "Data transfer", 'DATA_TRANSFER' )
mod.object = obj
mod.use_loop_data = True
mod.data_types_loops = {'CUSTOM_NORMAL'}
#The copy is now the selection
obj.select = False
bpy.context.scene.objects.active = copy
#Returns both copy and its modifier
return copy, mod
#Creates cut objects from the selected object and normalize their normal to the original
def CutAndNormalize( cuts ):
obj = bpy.context.object
if MeshObject( obj ) and obj.mode == 'OBJECT':
#Creates a base copy of the original object
copy, mod = InMode( obj, 'OBJECT', lambda: DuplicateObjectAndDataTransfert( obj ) )
#Cuts the copy according to the given cuts
InMode( copy, 'EDIT', lambda: CutMesh( copy, cuts ) )
InMode( copy, 'OBJECT', lambda: SelectAllVertices( copy ) )
#Separates loose parts from the copy
InMode( copy, 'EDIT', lambda: bpy.ops.mesh.separate( type = 'LOOSE' ) )
#Get the objects created from the previous separation
createdObjects = InMode( copy, 'OBJECT', lambda: GetSelectedObjects() )
#And for each of them
for createdObject in createdObjects:
#Activate it
bpy.context.scene.objects.active = createdObject
#Select all...
InMode( createdObject, 'OBJECT', lambda: SelectAllVertices( createdObject ) )
#... in order to remove double vertices created by the cuts
InMode( createdObject, 'EDIT', lambda: RemoveDoubles( createdObject ) )
#And finally apply the data transfer modifier
InMode( createdObject, 'OBJECT', lambda: bpy.ops.object.modifier_apply( modifier = mod.name ) )
print( '---------------' )
scale = 0.4
cuts = []
cuts.extend( [((i * scale, 0, 0), (1, 0, 0)) for i in range( -5, 5, 1 )] )
cuts.extend( [((0, i * scale, 0), (0, 1, 0)) for i in range( -5, 5, 1 )] )
CutAndNormalize( cuts )
Note1:
The result is not totally perfect where the cuts have created very small non quad polygons.
Note2:
I've tried to set the custom normals "manually" by affecting them directly. But I failed to do it. What happened is some per-face normals were wrong. I don't know why... if someone knows, please comment.