Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2012-07-04 12:48:33 +0400
committerCampbell Barton <ideasman42@gmail.com>2012-07-04 12:48:33 +0400
commit470cb9590535a92561ebf92f9ae50bb626f9e990 (patch)
tree7a03ba6520304f1d880e295a812a748d36d2e48b /object_fracture_cell
parent846e736aa0b6eb2e06820567ee36a448e06e35cd (diff)
rename addon
Diffstat (limited to 'object_fracture_cell')
-rw-r--r--object_fracture_cell/__init__.py396
-rw-r--r--object_fracture_cell/fracture_cell_calc.py95
-rw-r--r--object_fracture_cell/fracture_cell_setup.py371
3 files changed, 862 insertions, 0 deletions
diff --git a/object_fracture_cell/__init__.py b/object_fracture_cell/__init__.py
new file mode 100644
index 00000000..d284e205
--- /dev/null
+++ b/object_fracture_cell/__init__.py
@@ -0,0 +1,396 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+bl_info = {
+ "name": "Cell Fracture",
+ "author": "ideasman42",
+ "version": (0, 1),
+ "blender": (2, 6, 4),
+ "location": "Search > Fracture Object & Add -> Fracture Helper Objects",
+ "description": "Fractured Object, Bomb, Projectile, Recorder",
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"\
+ "Scripts/Object/Fracture",
+ "tracker_url": "https://projects.blender.org/tracker/index.php?"\
+ "func=detail&aid=21793",
+ "category": "Object"}
+
+
+#if "bpy" in locals():
+# import imp
+# imp.reload(fracture_cell_setup)
+
+import bpy
+from bpy.props import (StringProperty,
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ EnumProperty)
+
+from bpy.types import Operator
+
+def main_object(scene, obj, level, **kw):
+ import random
+
+ # pull out some args
+ kw_copy = kw.copy()
+ use_recenter = kw_copy.pop("use_recenter")
+ use_remove_original = kw_copy.pop("use_remove_original")
+ recursion = kw_copy.pop("recursion")
+ recursion_chance = kw_copy.pop("recursion_chance")
+ recursion_chance_select = kw_copy.pop("recursion_chance_select")
+ use_layer_next = kw_copy.pop("use_layer_next")
+ group_name = kw_copy.pop("group_name")
+ use_island_split = kw_copy.pop("use_island_split")
+
+ from . import fracture_cell_setup
+
+ # not essential but selection is visual distraction.
+ obj.select = False
+
+ if kw_copy["use_debug_redraw"]:
+ obj_draw_type_prev = obj.draw_type
+ obj.draw_type = 'WIRE'
+
+ objects = fracture_cell_setup.cell_fracture_objects(scene, obj, **kw_copy)
+ objects = fracture_cell_setup.cell_fracture_boolean(scene, obj, objects,
+ use_island_split=use_island_split,
+ use_debug_redraw=kw_copy["use_debug_redraw"])
+
+ # todo, split islands.
+
+ # must apply after boolean.
+ if use_recenter:
+ bpy.ops.object.origin_set({"selected_editable_objects": objects},
+ type='ORIGIN_GEOMETRY', center='MEDIAN')
+
+ if level < recursion:
+
+ objects_recurse_input = [(i, o) for i, o in enumerate(objects)]
+
+ if recursion_chance != 1.0:
+
+ if 0:
+ random.shuffle(objects_recurse_input)
+ else:
+ from mathutils import Vector
+ if recursion_chance_select == 'RANDOM':
+ pass
+ elif recursion_chance_select == {'SIZE_MIN', 'SIZE_MAX'}:
+ objects_recurse_input.sort(key=lambda ob_pair:
+ (Vector(ob_pair[1].bound_box[0]) -
+ Vector(ob_pair[1].bound_box[6])).length_squared)
+ if recursion_chance_select == 'SIZE_MAX':
+ objects_recurse_input.reverse()
+ elif recursion_chance_select == {'CURSOR_MIN', 'CURSOR_MAX'}:
+ print(recursion_chance_select)
+ c = scene.cursor_location.copy()
+ objects_recurse_input.sort(key=lambda ob_pair:
+ (ob_pair[1].matrix_world.translation - c).length_squared)
+ if recursion_chance_select == 'CURSOR_MAX':
+ objects_recurse_input.reverse()
+
+ objects_recurse_input[int(recursion_chance * len(objects_recurse_input)):] = []
+ objects_recurse_input.sort()
+
+ # reverse index values so we can remove from original list.
+ objects_recurse_input.reverse()
+
+ objects_recursive = []
+ for i, obj_cell in objects_recurse_input:
+ assert(objects[i] is obj_cell)
+ objects_recursive += main_object(scene, obj_cell, level + 1, **kw)
+ if use_remove_original:
+ scene.objects.unlink(obj_cell)
+ del objects[i]
+ objects.extend(objects_recursive)
+
+ #--------------
+ # Scene Options
+
+ # layer
+ if use_layer_next:
+ layers_new = [False] * 20
+ layers_new[(obj.layers[:].index(True) + 1) % 20] = True
+ for obj_cell in objects:
+ obj_cell.layers = layers_new
+ # group
+ if group_name:
+ group = bpy.data.groups.get(group_name)
+ if group is None:
+ group = bpy.data.groups.new(group_name)
+ for obj_cell in objects:
+ group.objects.link(obj_cell)
+
+ if kw_copy["use_debug_redraw"]:
+ obj.draw_type = obj_draw_type_prev
+
+ # testing only!
+ # obj.hide = True
+ return objects
+
+
+def main(context, **kw):
+ import time
+ t = time.time()
+ scene = context.scene
+ obj = context.active_object
+ objects = main_object(scene, obj, 0, **kw)
+
+ bpy.ops.object.select_all(action='DESELECT')
+ for obj_cell in objects:
+ obj_cell.select = True
+
+ print("Done! %d objects in %.4f sec" % (len(objects), time.time() - t))
+
+
+class FractureCell(Operator):
+ bl_idname = "object.add_fracture_cell_objects"
+ bl_label = "Cell Fracture Mesh"
+ bl_options = {'PRESET'}
+
+ # -------------------------------------------------------------------------
+ # Source Options
+ source = EnumProperty(
+ name="Source",
+ items=(('VERT_OWN', "Own Verts", "Use own vertices"),
+ ('VERT_CHILD', "Child Verts", "Use own vertices"),
+ ('PARTICLE', "Particles", ("All particle systems of the "
+ "source object")),
+ ('PENCIL', "Grease Pencil", "This objects grease pencil"),
+ ),
+ options={'ENUM_FLAG'},
+ default={'PARTICLE', 'VERT_OWN'} # 'VERT_OWN', 'EDGE_OWN', 'FACE_OWN'
+ )
+
+ source_limit = IntProperty(
+ name="Source Limit",
+ description="Limit the number of input points, 0 for unlimited",
+ min=0, max=5000,
+ default=1000,
+ )
+
+ source_noise = FloatProperty(
+ name="Noise",
+ description="Randomize point distrobution",
+ min=0.0, max=1.0,
+ default=0.0,
+ )
+
+ # -------------------------------------------------------------------------
+ # Recursion
+
+ recursion = IntProperty(
+ name="Recursion",
+ description="Break shards resursively",
+ min=0, max=5000,
+ default=0,
+ )
+
+ recursion_chance = FloatProperty(
+ name="Random Factor",
+ description="Likelyhood of recursion",
+ min=0.0, max=1.0,
+ default=1.0,
+ )
+
+ recursion_chance_select = EnumProperty(
+ name="Recurse Over",
+ items=(('RANDOM', "Random", ""),
+ ('SIZE_MIN', "Small", "Recursively subdivide smaller objects"),
+ ('SIZE_MAX', "Big", "Recursively subdivide smaller objects"),
+ ('CURSOR_MIN', "Cursor Close", "Recursively subdivide objects closer to the cursor"),
+ ('CURSOR_MAX', "Cursor Far", "Recursively subdivide objects closer to the cursor"),
+ ),
+ default='SIZE_MIN',
+ )
+
+ # -------------------------------------------------------------------------
+ # Mesh Data Options
+
+ use_smooth_faces = BoolProperty(
+ name="Smooth Faces",
+ default=False,
+ )
+
+ use_smooth_edges = BoolProperty(
+ name="Smooth Edges",
+ description="Set sharp edges whem disabled",
+ default=True,
+ )
+
+ use_data_match = BoolProperty(
+ name="Match Data",
+ description="Match original mesh materials and data layers",
+ default=True,
+ )
+
+ use_island_split = BoolProperty(
+ name="Split Islands",
+ description="Split disconnected meshes",
+ default=True,
+ )
+
+ margin = FloatProperty(
+ name="Margin",
+ description="Gaps for the fracture (gives more stable physics)",
+ min=0.0, max=1.0,
+ default=0.001,
+ )
+
+ material_index = IntProperty(
+ name="Material",
+ description="Material index for interior faces",
+ default=0,
+ )
+
+ # -------------------------------------------------------------------------
+ # Object Options
+
+ use_recenter = BoolProperty(
+ name="Recenter",
+ description="Recalculate the center points after splitting",
+ default=True,
+ )
+
+ use_remove_original = BoolProperty(
+ name="Remove Original",
+ description="Removes the parents used to create the shatter",
+ default=True,
+ )
+
+ # -------------------------------------------------------------------------
+ # Scene Options
+ #
+ # .. dirreferent from object options in that this controls how the objects
+ # are setup in the scene.
+
+ use_layer_next = BoolProperty(
+ name="Next Layer",
+ description="At the object into the next layer",
+ default=True,
+ )
+
+ group_name = StringProperty(
+ name="Group",
+ description="Create objects int a group "
+ "(use existing or create new)",
+ )
+
+ # -------------------------------------------------------------------------
+ # Debug
+ use_debug_points = BoolProperty(
+ name="Debug Points",
+ description="Create mesh data showing the points used for fracture",
+ default=False,
+ )
+
+ use_debug_redraw = BoolProperty(
+ name="Show Progress Realtime",
+ description="Redraw as fracture is done",
+ default=True,
+ )
+
+ def execute(self, context):
+ keywords = self.as_keywords() # ignore=("blah",)
+
+ main(context, **keywords)
+
+ return {'FINISHED'}
+
+
+ def invoke(self, context, event):
+ print(self.recursion_chance_select)
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self, width=600)
+
+ def draw(self, context):
+ layout = self.layout
+ box = layout.box()
+ col = box.column()
+ col.label("Point Source")
+ rowsub = col.row()
+ rowsub.prop(self, "source")
+ rowsub = col.row()
+ rowsub.prop(self, "source_limit")
+ rowsub.prop(self, "source_noise")
+ rowsub = col.row()
+
+ box = layout.box()
+ col = box.column()
+ col.label("Recursive Shatter")
+ rowsub = col.row(align=True)
+ rowsub.prop(self, "recursion")
+ rowsub = col.row()
+ rowsub.prop(self, "recursion_chance")
+ rowsub.prop(self, "recursion_chance_select", expand=True)
+
+ box = layout.box()
+ col = box.column()
+ col.label("Mesh Data")
+ rowsub = col.row()
+ rowsub.prop(self, "use_smooth_faces")
+ rowsub.prop(self, "use_smooth_edges")
+ rowsub.prop(self, "use_data_match")
+ rowsub.prop(self, "material_index")
+ rowsub = col.row()
+ # could be own section, control how we subdiv
+ rowsub.prop(self, "margin")
+ rowsub.prop(self, "use_island_split")
+
+ box = layout.box()
+ col = box.column()
+ col.label("Object")
+ rowsub = col.row(align=True)
+ rowsub.prop(self, "use_recenter")
+
+
+ box = layout.box()
+ col = box.column()
+ col.label("Scene")
+ rowsub = col.row(align=True)
+ rowsub.prop(self, "use_layer_next")
+ rowsub.prop(self, "group_name")
+
+ box = layout.box()
+ col = box.column()
+ col.label("Debug")
+ rowsub = col.row(align=True)
+ rowsub.prop(self, "use_debug_redraw")
+ rowsub.prop(self, "use_debug_points")
+
+#def menu_func(self, context):
+# self.layout.menu("INFO_MT_add_fracture_objects", icon="PLUGIN")
+
+
+def register():
+ bpy.utils.register_class(FractureCell)
+
+ # Add the "add fracture objects" menu to the "Add" menu
+ # bpy.types.INFO_MT_add.append(menu_func)
+
+
+def unregister():
+ bpy.utils.unregister_class(FractureCell)
+
+ # Remove "add fracture objects" menu from the "Add" menu.
+ # bpy.types.INFO_MT_add.remove(menu_func)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/object_fracture_cell/fracture_cell_calc.py b/object_fracture_cell/fracture_cell_calc.py
new file mode 100644
index 00000000..3b9e5a16
--- /dev/null
+++ b/object_fracture_cell/fracture_cell_calc.py
@@ -0,0 +1,95 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# Script copyright (C) Blender Foundation 2012
+
+
+def points_as_bmesh_cells(verts, points,
+ margin_bounds=0.05,
+ margin_cell=0.0):
+ import mathutils
+ from mathutils import Vector
+
+ cells = []
+
+ points_sorted_current = [p for p in points]
+ plane_indices = []
+ vertices = []
+
+ # there are many ways we could get planes - convex hull for eg
+ # but it ends up fastest if we just use bounding box
+ if 1:
+ xa = [v[0] for v in verts]
+ ya = [v[1] for v in verts]
+ za = [v[2] for v in verts]
+
+ xmin, xmax = min(xa) - margin_bounds, max(xa) + margin_bounds
+ ymin, ymax = min(ya) - margin_bounds, max(ya) + margin_bounds
+ zmin, zmax = min(za) - margin_bounds, max(za) + margin_bounds
+ convexPlanes = [
+ Vector((+1.0, 0.0, 0.0, -abs(xmax))),
+ Vector((-1.0, 0.0, 0.0, -abs(xmin))),
+ Vector((0.0, +1.0, 0.0, -abs(ymax))),
+ Vector((0.0, -1.0, 0.0, -abs(ymin))),
+ Vector((0.0, 0.0, +1.0, -abs(zmax))),
+ Vector((0.0, 0.0, -1.0, -abs(zmin))),
+ ]
+
+ for i, point_cell_current in enumerate(points):
+ planes = [None] * len(convexPlanes)
+ for j in range(len(convexPlanes)):
+ planes[j] = convexPlanes[j].copy()
+ planes[j][3] += planes[j].xyz.dot(point_cell_current)
+ distance_max = 10000000000.0 # a big value!
+
+ points_sorted_current.sort(key=lambda p: (p - point_cell_current).length_squared)
+
+ for j in range(1, len(points)):
+ normal = points_sorted_current[j] - point_cell_current
+ nlength = normal.length
+ if nlength > distance_max:
+ break
+
+ plane = normal.normalized()
+ plane.resize_4d()
+ plane[3] = (-nlength / 2.0) + margin_cell
+ planes.append(plane)
+
+ vertices[:], plane_indices[:] = mathutils.geometry.points_in_planes(planes)
+ if len(vertices) == 0:
+ break
+
+ if len(plane_indices) != len(planes):
+ planes[:] = [planes[k] for k in plane_indices]
+
+ distance_max = vertices[0].length
+ for k in range(1, len(vertices)):
+ distance = vertices[k].length
+ if distance_max < distance:
+ distance_max = distance
+ distance_max *= 2.0
+
+ if len(vertices) == 0:
+ continue
+
+ cells.append((point_cell_current, vertices[:]))
+ vertices[:] = []
+
+ return cells
diff --git a/object_fracture_cell/fracture_cell_setup.py b/object_fracture_cell/fracture_cell_setup.py
new file mode 100644
index 00000000..a3365828
--- /dev/null
+++ b/object_fracture_cell/fracture_cell_setup.py
@@ -0,0 +1,371 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# Script copyright (C) Blender Foundation 2012
+
+import bpy
+import bmesh
+
+
+def _redraw_yasiamevil():
+ _redraw_yasiamevil.opr(**_redraw_yasiamevil.arg)
+_redraw_yasiamevil.opr = bpy.ops.wm.redraw_timer
+_redraw_yasiamevil.arg = dict(type='DRAW_WIN_SWAP', iterations=1)
+
+
+
+def _points_from_object(obj, source):
+
+ _source_all = {
+ 'PARTICLE', 'PENCIL',
+ 'VERT_OWN', 'VERT_CHILD',
+ }
+
+ print(source - _source_all)
+ print(source)
+ assert(len(source | _source_all) == len(_source_all))
+ assert(len(source))
+
+ points = []
+
+ def edge_center(mesh, edge):
+ v1, v2 = edge.vertices
+ return (mesh.vertices[v1].co + mesh.vertices[v2].co) / 2.0
+
+ def poly_center(mesh, poly):
+ from mathutils import Vector
+ co = Vector()
+ tot = 0
+ for i in poly.loop_indices:
+ co += mesh.vertices[mesh.loops[i].vertex_index].co
+ tot += 1
+ return co / tot
+
+ def points_from_verts(obj):
+ """Takes points from _any_ object with geometry"""
+ if obj.type == 'MESH':
+ mesh = obj.data
+ matrix = obj.matrix_world.copy()
+ points.extend([matrix * v.co for v in mesh.vertices])
+ else:
+ try:
+ mesh = ob.to_mesh(scene=bpy.context.scene,
+ apply_modifiers=True,
+ settings='PREVIEW')
+ except:
+ mesh = None
+
+ if mesh is not None:
+ matrix = obj.matrix_world.copy()
+ points.extend([matrix * v.co for v in mesh.vertices])
+ bpy.data.meshes.remove(mesh)
+
+ # geom own
+ if 'VERT_OWN' in source:
+ points_from_verts(obj)
+
+ # geom children
+ if 'VERT_CHILD' in source:
+ for obj_child in obj.children:
+ points_from_verts(obj_child)
+
+ # geom particles
+ if 'PARTICLE' in source:
+ points.extend([p.location.copy()
+ for psys in obj.particle_systems
+ for p in psys.particles])
+
+ # grease pencil
+ def get_points(stroke):
+ return [point.co.copy() for point in stroke.points]
+
+ def get_splines(gp):
+ if gp.layers.active:
+ frame = gp.layers.active.active_frame
+ return [get_points(stroke) for stroke in frame.strokes]
+ else:
+ return []
+
+ if 'PENCIL' in source:
+ gp = obj.grease_pencil
+ if gp:
+ points.extend([p for spline in get_splines(gp)
+ for p in spline])
+
+ return points
+
+
+def cell_fracture_objects(scene, obj,
+ source={'PARTICLE'},
+ source_limit=0,
+ source_noise=0.0,
+ clean=True,
+ # operator options
+ use_smooth_faces=False,
+ use_smooth_edges=True,
+ use_data_match=False,
+ use_debug_points=False,
+ margin=0.0,
+ material_index=0,
+ use_debug_redraw=False,
+ ):
+
+ from . import fracture_cell_calc
+
+ # -------------------------------------------------------------------------
+ # GET POINTS
+
+ points = _points_from_object(obj, source)
+
+ if not points:
+ # print using fallback
+ points = _points_from_object(obj, source | {'VERT_OWN'})
+
+ if not points:
+ print("no points found")
+ return []
+
+ # apply optional clamp
+ if source_limit != 0 and source_limit < len(points):
+ import random
+ random.shuffle(points)
+ points[source_limit:] = []
+
+
+ # saddly we cant be sure there are no doubles
+ from mathutils import Vector
+ to_tuple = Vector.to_tuple
+ points = list({to_tuple(p, 4): p for p in points}.values())
+ del to_tuple
+ del Vector
+
+
+ if source_noise > 0.0:
+ from random import random
+ # boundbox approx of overall scale
+ from mathutils import Vector
+ matrix = obj.matrix_world.copy()
+ bb_world = [matrix * Vector(v) for v in obj.bound_box]
+ scalar = source_noise * ((bb_world[0] - bb_world[6]).length / 2.0)
+
+ from mathutils.noise import random_unit_vector
+
+ points[:] = [p + (random_unit_vector() * (scalar * random())) for p in points]
+
+ # end remove doubles
+ # ------------------
+
+ if use_debug_points:
+ bm = bmesh.new()
+ for p in points:
+ bm.verts.new(p)
+ mesh_tmp = bpy.data.meshes.new(name="DebugPoints")
+ bm.to_mesh(mesh_tmp)
+ bm.free()
+ obj_tmp = bpy.data.objects.new(name=mesh_tmp.name, object_data=mesh_tmp)
+ scene.objects.link(obj_tmp)
+ del obj_tmp, mesh_tmp
+
+ mesh = obj.data
+ matrix = obj.matrix_world.copy()
+ verts = [matrix * v.co for v in mesh.vertices]
+
+ cells = fracture_cell_calc.points_as_bmesh_cells(verts, points,
+ margin_cell=margin)
+
+ # some hacks here :S
+ cell_name = obj.name + "_cell"
+
+ objects = []
+
+ for center_point, cell_points in cells:
+
+ # ---------------------------------------------------------------------
+ # BMESH
+
+ # create the convex hulls
+ bm = bmesh.new()
+ for i, co in enumerate(cell_points):
+ bm_vert = bm.verts.new(co)
+ bm_vert.tag = True
+
+ import mathutils
+ bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005)
+ try:
+ bmesh.ops.convex_hull(bm, input=bm.verts)
+ except RuntimeError:
+ import traceback
+ traceback.print_exc()
+
+ if clean:
+ for bm_vert in bm.verts:
+ bm_vert.tag = True
+ for bm_edge in bm.edges:
+ bm_edge.tag = True
+ bm.normal_update()
+ try:
+ bmesh.ops.dissolve_limit(bm, verts=bm.verts, angle_limit=0.001)
+ except RuntimeError:
+ import traceback
+ traceback.print_exc()
+
+ if use_smooth_faces:
+ for bm_face in bm.faces:
+ bm_face.smooth = True
+
+ if use_smooth_edges:
+ for bm_edge in bm.edges:
+ bm_edge.smooth = True
+
+ if material_index != 0:
+ for bm_face in bm.faces:
+ bm_face.material_index = material_index
+
+
+ # ---------------------------------------------------------------------
+ # MESH
+
+ mesh_dst = bpy.data.meshes.new(name=cell_name)
+
+ bm.to_mesh(mesh_dst)
+ bm.free()
+ del bm
+
+ if use_data_match:
+ # match materials and data layers so boolean displays them
+ # currently only materials + data layers, could do others...
+ mesh_src = obj.data
+ for mat in mesh_src.materials:
+ mesh_dst.materials.append(mat)
+ for lay_attr in ("vertex_colors", "uv_textures"):
+ lay_src = getattr(mesh_src, lay_attr)
+ lay_dst = getattr(mesh_dst, lay_attr)
+ for key in lay_src.keys():
+ lay_dst.new(name=key)
+
+ # ---------------------------------------------------------------------
+ # OBJECT
+
+ obj_cell = bpy.data.objects.new(name=cell_name, object_data=mesh_dst)
+ scene.objects.link(obj_cell)
+ # scene.objects.active = obj_cell
+ obj_cell.location = center_point
+
+ objects.append(obj_cell)
+
+ if use_debug_redraw:
+ scene.update()
+ _redraw_yasiamevil()
+
+ scene.update()
+
+
+ # move this elsewhere...
+ for obj_cell in objects:
+ game = obj_cell.game
+ game.physics_type = 'RIGID_BODY'
+ game.use_collision_bounds = True
+ game.collision_bounds_type = 'CONVEX_HULL'
+
+ return objects
+
+
+def cell_fracture_boolean(scene, obj, objects,
+ apply=True,
+ clean=True,
+ use_island_split=False,
+ use_debug_redraw=False,
+ ):
+
+ objects_boolean = []
+
+ for obj_cell in objects:
+ mod = obj_cell.modifiers.new(name="Boolean", type='BOOLEAN')
+ mod.object = obj
+ mod.operation = 'INTERSECT'
+
+ if apply:
+ mesh_new = obj_cell.to_mesh(scene,
+ apply_modifiers=True,
+ settings='PREVIEW')
+ mesh_old = obj_cell.data
+ obj_cell.data = mesh_new
+ obj_cell.modifiers.remove(mod)
+
+ # remove if not valid
+ if not mesh_old.users:
+ bpy.data.meshes.remove(mesh_old)
+ if not mesh_new.vertices:
+ scene.objects.unlink(obj_cell)
+ if not obj_cell.users:
+ bpy.data.objects.remove(obj_cell)
+ obj_cell = None
+ if not mesh_new.users:
+ bpy.data.meshes.remove(mesh_new)
+ mesh_new = None
+
+ if clean and mesh_new is not None:
+ bm = bmesh.new()
+ bm.from_mesh(mesh_new)
+ for bm_vert in bm.verts:
+ bm_vert.tag = True
+ for bm_edge in bm.edges:
+ bm_edge.tag = True
+ bm.normal_update()
+ try:
+ bmesh.ops.dissolve_limit(bm, verts=bm.verts, edges=bm.edges, angle_limit=0.001)
+ except RuntimeError:
+ import traceback
+ traceback.print_exc()
+ bm.to_mesh(mesh_new)
+ bm.free()
+
+ if obj_cell is not None:
+ objects_boolean.append(obj_cell)
+
+ if use_debug_redraw:
+ _redraw_yasiamevil()
+
+ if apply and use_island_split:
+ # this is ugly and Im not proud of this - campbell
+ objects_islands = []
+ for obj_cell in objects_boolean:
+
+ scene.objects.active = obj_cell
+
+ group_island = bpy.data.groups.new(name="Islands")
+ group_island.objects.link(obj_cell)
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.select_all(action='SELECT')
+ bpy.ops.mesh.separate(type='LOOSE')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ objects_islands.extend(group_island.objects[:])
+
+ bpy.data.groups.remove(group_island)
+
+ scene.objects.active = None
+
+ objects_boolean = objects_islands
+
+ scene.update()
+
+ return objects_boolean