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:
authormeta-androcto <meta.androcto1@gmail.com>2019-05-24 09:11:07 +0300
committermeta-androcto <meta.androcto1@gmail.com>2019-05-24 09:11:07 +0300
commitf7c91d3382ea19ce4565105c85288044a2d1b833 (patch)
tree485be78a423618202851da52858daa6069a57e98 /object_fracture_cell
parent9e99e90f08c985cb764ecb3a7bba6ff534d4d874 (diff)
object_fracture_cell/crackit: move to contrib: T63750 T61901
Diffstat (limited to 'object_fracture_cell')
-rw-r--r--object_fracture_cell/__init__.py568
-rw-r--r--object_fracture_cell/fracture_cell_calc.py120
-rw-r--r--object_fracture_cell/fracture_cell_setup.py459
3 files changed, 0 insertions, 1147 deletions
diff --git a/object_fracture_cell/__init__.py b/object_fracture_cell/__init__.py
deleted file mode 100644
index e1fcb41f..00000000
--- a/object_fracture_cell/__init__.py
+++ /dev/null
@@ -1,568 +0,0 @@
-# ##### 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, phymec, Sergey Sharybin",
- "version": (0, 1),
- "blender": (2, 70, 0),
- "location": "Edit panel of Tools tab, in Object mode, 3D View tools",
- "description": "Fractured Object, Bomb, Projectile, Recorder",
- "warning": "",
- "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
- "Scripts/Object/CellFracture",
- "category": "Object"}
-
-
-#if "bpy" in locals():
-# import importlib
-# importlib.reload(fracture_cell_setup)
-
-import bpy
-from bpy.props import (
- StringProperty,
- BoolProperty,
- IntProperty,
- FloatProperty,
- FloatVectorProperty,
- EnumProperty,
- )
-
-from bpy.types import Operator
-
-def main_object(context, 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_source_limit = kw_copy.pop("recursion_source_limit")
- recursion_clamp = kw_copy.pop("recursion_clamp")
- 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")
- use_layer_index = kw_copy.pop("use_layer_index")
- group_name = kw_copy.pop("group_name")
- use_island_split = kw_copy.pop("use_island_split")
- use_debug_bool = kw_copy.pop("use_debug_bool")
- use_interior_vgroup = kw_copy.pop("use_interior_vgroup")
- use_sharp_edges = kw_copy.pop("use_sharp_edges")
- use_sharp_edges_apply = kw_copy.pop("use_sharp_edges_apply")
-
- collection = context.collection
-
- if level != 0:
- kw_copy["source_limit"] = recursion_source_limit
-
- from . import fracture_cell_setup
-
- # not essential but selection is visual distraction.
- obj.select_set(False)
-
- if kw_copy["use_debug_redraw"]:
- obj_display_type_prev = obj.display_type
- obj.display_type = 'WIRE'
-
- objects = fracture_cell_setup.cell_fracture_objects(context, obj, **kw_copy)
- objects = fracture_cell_setup.cell_fracture_boolean(context, obj, objects,
- use_island_split=use_island_split,
- use_interior_hide=(use_interior_vgroup or use_sharp_edges),
- use_debug_bool=use_debug_bool,
- use_debug_redraw=kw_copy["use_debug_redraw"],
- level=level,
- )
-
- # must apply after boolean.
- if use_recenter:
- bpy.ops.object.origin_set({"selected_editable_objects": objects},
- type='ORIGIN_GEOMETRY', center='MEDIAN')
-
- if level == 0:
- for level_sub in range(1, recursion + 1):
-
- objects_recurse_input = [(i, o) for i, o in enumerate(objects)]
-
- if recursion_chance != 1.0:
- from mathutils import Vector
- if recursion_chance_select == 'RANDOM':
- random.shuffle(objects_recurse_input)
- elif recursion_chance_select in {'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 in {'CURSOR_MIN', 'CURSOR_MAX'}:
- c = scene.cursor.location.copy()
- objects_recurse_input.sort(key=lambda ob_pair:
- (ob_pair[1].location - 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(context, obj_cell, level_sub, **kw)
- if use_remove_original:
- collection.objects.unlink(obj_cell)
- del objects[i]
- if recursion_clamp and len(objects) + len(objects_recursive) >= recursion_clamp:
- break
- objects.extend(objects_recursive)
-
- if recursion_clamp and len(objects) > recursion_clamp:
- break
-
- #--------------
- # Level Options
- if level == 0:
- # import pdb; pdb.set_trace()
- if use_interior_vgroup or use_sharp_edges:
- fracture_cell_setup.cell_fracture_interior_handle(objects,
- use_interior_vgroup=use_interior_vgroup,
- use_sharp_edges=use_sharp_edges,
- use_sharp_edges_apply=use_sharp_edges_apply,
- )
-
- #--------------
- # Scene Options
-
- # layer
- layers_new = None
- if use_layer_index != 0:
- layers_new = [False] * 20
- layers_new[use_layer_index - 1] = True
- elif use_layer_next:
- layers_new = [False] * 20
- layers_new[(obj.layers[:].index(True) + 1) % 20] = True
-
- if layers_new is not None:
- for obj_cell in objects:
- obj_cell.layers = layers_new
-
- # group
- if group_name:
- group = bpy.data.collections.get(group_name)
- if group is None:
- group = bpy.data.collections.new(group_name)
- group_objects = group.objects[:]
- for obj_cell in objects:
- if obj_cell not in group_objects:
- group.objects.link(obj_cell)
-
- if kw_copy["use_debug_redraw"]:
- obj.display_type = obj_display_type_prev
-
- # testing only!
- # obj.hide = True
- return objects
-
-
-def main(context, **kw):
- import time
- t = time.time()
- objects_context = context.selected_editable_objects
-
- kw_copy = kw.copy()
-
- # mass
- mass_mode = kw_copy.pop("mass_mode")
- mass = kw_copy.pop("mass")
-
- objects = []
- for obj in objects_context:
- if obj.type == 'MESH':
- objects += main_object(context, obj, 0, **kw_copy)
-
- bpy.ops.object.select_all(action='DESELECT')
- for obj_cell in objects:
- obj_cell.select_set(True)
-
- if mass_mode == 'UNIFORM':
- for obj_cell in objects:
- obj_cell.game.mass = mass
- elif mass_mode == 'VOLUME':
- from mathutils import Vector
- def _get_volume(obj_cell):
- def _getObjectBBMinMax():
- min_co = Vector((1000000.0, 1000000.0, 1000000.0))
- max_co = -min_co
- matrix = obj_cell.matrix_world
- for i in range(0, 8):
- bb_vec = obj_cell.matrix_world * Vector(obj_cell.bound_box[i])
- min_co[0] = min(bb_vec[0], min_co[0])
- min_co[1] = min(bb_vec[1], min_co[1])
- min_co[2] = min(bb_vec[2], min_co[2])
- max_co[0] = max(bb_vec[0], max_co[0])
- max_co[1] = max(bb_vec[1], max_co[1])
- max_co[2] = max(bb_vec[2], max_co[2])
- return (min_co, max_co)
-
- def _getObjectVolume():
- min_co, max_co = _getObjectBBMinMax()
- x = max_co[0] - min_co[0]
- y = max_co[1] - min_co[1]
- z = max_co[2] - min_co[2]
- volume = x * y * z
- return volume
-
- return _getObjectVolume()
-
-
- obj_volume_ls = [_get_volume(obj_cell) for obj_cell in objects]
- obj_volume_tot = sum(obj_volume_ls)
- if obj_volume_tot > 0.0:
- mass_fac = mass / obj_volume_tot
- for i, obj_cell in enumerate(objects):
- obj_cell.game.mass = obj_volume_ls[i] * mass_fac
- else:
- assert(0)
-
- 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 selected mesh objects"
- bl_options = {'PRESET'}
-
- # -------------------------------------------------------------------------
- # Source Options
- source: EnumProperty(
- name="Source",
- items=(('VERT_OWN', "Own Verts", "Use own vertices"),
- ('VERT_CHILD', "Child Verts", "Use child object vertices"),
- ('PARTICLE_OWN', "Own Particles", ("All particle systems of the "
- "source object")),
- ('PARTICLE_CHILD', "Child Particles", ("All particle systems of the "
- "child objects")),
- ('PENCIL', "Grease Pencil", "This object's grease pencil"),
- ),
- options={'ENUM_FLAG'},
- default={'PARTICLE_OWN'},
- )
-
- source_limit: IntProperty(
- name="Source Limit",
- description="Limit the number of input points, 0 for unlimited",
- min=0, max=5000,
- default=100,
- )
-
- source_noise: FloatProperty(
- name="Noise",
- description="Randomize point distribution",
- min=0.0, max=1.0,
- default=0.0,
- )
-
- cell_scale: FloatVectorProperty(
- name="Scale",
- description="Scale Cell Shape",
- size=3,
- min=0.0, max=1.0,
- default=(1.0, 1.0, 1.0),
- )
-
- # -------------------------------------------------------------------------
- # Recursion
-
- recursion: IntProperty(
- name="Recursion",
- description="Break shards recursively",
- min=0, max=5000,
- default=0,
- )
-
- recursion_source_limit: IntProperty(
- name="Source Limit",
- description="Limit the number of input points, 0 for unlimited (applies to recursion only)",
- min=0, max=5000,
- default=8,
- )
-
- recursion_clamp: IntProperty(
- name="Clamp Recursion",
- description="Finish recursion when this number of objects is reached (prevents recursing for extended periods of time), zero disables",
- min=0, max=10000,
- default=250,
- )
-
- recursion_chance: FloatProperty(
- name="Random Factor",
- description="Likelihood of recursion",
- min=0.0, max=1.0,
- default=0.25,
- )
-
- recursion_chance_select: EnumProperty(
- name="Recurse Over",
- items=(('RANDOM', "Random", ""),
- ('SIZE_MIN', "Small", "Recursively subdivide smaller objects"),
- ('SIZE_MAX', "Big", "Recursively subdivide bigger objects"),
- ('CURSOR_MIN', "Cursor Close", "Recursively subdivide objects closer to the cursor"),
- ('CURSOR_MAX', "Cursor Far", "Recursively subdivide objects farther from the cursor"),
- ),
- default='SIZE_MIN',
- )
-
- # -------------------------------------------------------------------------
- # Mesh Data Options
-
- use_smooth_faces: BoolProperty(
- name="Smooth Faces",
- default=False,
- )
-
- use_sharp_edges: BoolProperty(
- name="Sharp Edges",
- description="Set sharp edges when disabled",
- default=True,
- )
-
- use_sharp_edges_apply: BoolProperty(
- name="Apply Split Edge",
- description="Split sharp hard edges",
- 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,
- )
-
- use_interior_vgroup: BoolProperty(
- name="Interior VGroup",
- description="Create a vertex group for interior verts",
- default=False,
- )
-
- # -------------------------------------------------------------------------
- # Physics Options
-
- mass_mode: EnumProperty(
- name="Mass Mode",
- items=(('VOLUME', "Volume", "Objects get part of specified mass based on their volume"),
- ('UNIFORM', "Uniform", "All objects get the specified mass"),
- ),
- default='VOLUME',
- )
-
- mass: FloatProperty(
- name="Mass",
- description="Mass to give created objects",
- min=0.001, max=1000.0,
- default=1.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
- #
- # .. different from object options in that this controls how the objects
- # are setup in the scene.
-
- use_layer_index: IntProperty(
- name="Layer Index",
- description="Layer to add the objects into or 0 for existing",
- default=0,
- min=0, max=20,
- )
-
- use_layer_next: BoolProperty(
- name="Next Layer",
- description="At the object into the next layer (layer index overrides)",
- 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,
- )
-
- use_debug_bool: BoolProperty(
- name="Debug Boolean",
- description="Skip applying the boolean modifier",
- default=False,
- )
-
- 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(text="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()
- rowsub.prop(self, "cell_scale")
-
- box = layout.box()
- col = box.column()
- col.label(text="Recursive Shatter")
- rowsub = col.row(align=True)
- rowsub.prop(self, "recursion")
- rowsub.prop(self, "recursion_source_limit")
- rowsub.prop(self, "recursion_clamp")
- rowsub = col.row()
- rowsub.prop(self, "recursion_chance")
- rowsub.prop(self, "recursion_chance_select", expand=True)
-
- box = layout.box()
- col = box.column()
- col.label(text="Mesh Data")
- rowsub = col.row()
- rowsub.prop(self, "use_smooth_faces")
- rowsub.prop(self, "use_sharp_edges")
- rowsub.prop(self, "use_sharp_edges_apply")
- rowsub.prop(self, "use_data_match")
- rowsub = col.row()
-
- # on same row for even layout but infact are not all that related
- rowsub.prop(self, "material_index")
- rowsub.prop(self, "use_interior_vgroup")
-
- # 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(text="Physics")
- rowsub = col.row(align=True)
- rowsub.prop(self, "mass_mode")
- rowsub.prop(self, "mass")
-
-
- box = layout.box()
- col = box.column()
- col.label(text="Object")
- rowsub = col.row(align=True)
- rowsub.prop(self, "use_recenter")
-
-
- box = layout.box()
- col = box.column()
- col.label(text="Scene")
- rowsub = col.row(align=True)
- rowsub.prop(self, "use_layer_index")
- rowsub.prop(self, "use_layer_next")
- rowsub.prop(self, "group_name")
-
- box = layout.box()
- col = box.column()
- col.label(text="Debug")
- rowsub = col.row(align=True)
- rowsub.prop(self, "use_debug_redraw")
- rowsub.prop(self, "use_debug_points")
- rowsub.prop(self, "use_debug_bool")
-
-
-def menu_func(self, context):
- layout = self.layout
- layout.label(text="Cell Fracture:")
- layout.operator("object.add_fracture_cell_objects",
- text="Cell Fracture")
-
-
-def register():
- bpy.utils.register_class(FractureCell)
- bpy.types.VIEW3D_PT_tools_object.append(menu_func)
-
-
-def unregister():
- bpy.utils.unregister_class(FractureCell)
- bpy.types.VIEW3D_PT_tools_object.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
deleted file mode 100644
index 9e6f0de5..00000000
--- a/object_fracture_cell/fracture_cell_calc.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# ##### 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,
- points_scale=None,
- margin_bounds=0.05,
- margin_cell=0.0):
- from math import sqrt
- import mathutils
- from mathutils import Vector
-
- cells = []
-
- points_sorted_current = [p for p in points]
- plane_indices = []
- vertices = []
-
- if points_scale is not None:
- points_scale = tuple(points_scale)
- if points_scale == (1.0, 1.0, 1.0):
- points_scale = None
-
- # 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, -xmax)),
- Vector((-1.0, 0.0, 0.0, +xmin)),
- Vector((0.0, +1.0, 0.0, -ymax)),
- Vector((0.0, -1.0, 0.0, +ymin)),
- Vector((0.0, 0.0, +1.0, -zmax)),
- Vector((0.0, 0.0, -1.0, +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 points_scale is not None:
- normal_alt = normal.copy()
- normal_alt.x *= points_scale[0]
- normal_alt.y *= points_scale[1]
- normal_alt.z *= points_scale[2]
-
- # rotate plane to new distance
- # should always be positive!! - but abs incase
- scalar = normal_alt.normalized().dot(normal.normalized())
- # assert(scalar >= 0.0)
- nlength *= scalar
- normal = normal_alt
-
- 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]
-
- # for comparisons use length_squared and delay
- # converting to a real length until the end.
- distance_max = 10000000000.0 # a big value!
- for v in vertices:
- distance = v.length_squared
- if distance_max < distance:
- distance_max = distance
- distance_max = sqrt(distance_max) # make real length
- distance_max *= 2.0
-
- if len(vertices) == 0:
- continue
-
- cells.append((point_cell_current, vertices[:]))
- del vertices[:]
-
- return cells
diff --git a/object_fracture_cell/fracture_cell_setup.py b/object_fracture_cell/fracture_cell_setup.py
deleted file mode 100644
index fcafa247..00000000
--- a/object_fracture_cell/fracture_cell_setup.py
+++ /dev/null
@@ -1,459 +0,0 @@
-# ##### 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_OWN', 'PARTICLE_CHILD',
- '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:
- depsgraph = bpy.context.evaluated_depsgraph_get()
- ob_eval = ob.evaluated_get(depsgraph)
- try:
- mesh = ob_eval.to_mesh()
- except:
- mesh = None
-
- if mesh is not None:
- matrix = obj.matrix_world.copy()
- points.extend([matrix * v.co for v in mesh.vertices])
- ob_eval.to_mesh_clear()
-
- def points_from_particles(obj):
- points.extend([p.location.copy()
- for psys in obj.particle_systems
- for p in psys.particles])
-
- # 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_OWN' in source:
- points_from_particles(obj)
-
- if 'PARTICLE_CHILD' in source:
- for obj_child in obj.children:
- points_from_particles(obj_child)
-
- # 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])
-
- print("Found %d points" % len(points))
-
- return points
-
-
-def cell_fracture_objects(context, obj,
- source={'PARTICLE_OWN'},
- source_limit=0,
- source_noise=0.0,
- clean=True,
- # operator options
- use_smooth_faces=False,
- use_data_match=False,
- use_debug_points=False,
- margin=0.0,
- material_index=0,
- use_debug_redraw=False,
- cell_scale=(1.0, 1.0, 1.0),
- ):
-
- from . import fracture_cell_calc
- collection = context.collection
- view_layer = context.view_layer
-
- # -------------------------------------------------------------------------
- # GET POINTS
-
- points = _points_from_object(obj, source)
-
- if not points:
- # print using fallback
- points = _points_from_object(obj, {'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
-
- # end remove doubles
- # ------------------
-
- 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]
-
- 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)
- collection.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,
- cell_scale,
- 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()
-
- # WORKAROUND FOR CONVEX HULL BUG/LIMIT
- # XXX small noise
- import random
- def R():
- return (random.random() - 0.5) * 0.001
- # XXX small noise
-
- for i, co in enumerate(cell_points):
-
- # XXX small noise
- co.x += R()
- co.y += R()
- co.z += R()
- # XXX small noise
-
- bm_vert = bm.verts.new(co)
-
- 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:
- 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 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)
- collection.objects.link(obj_cell)
- # scene.objects.active = obj_cell
- obj_cell.location = center_point
-
- objects.append(obj_cell)
-
- # support for object materials
- if use_data_match:
- for i in range(len(mesh_dst.materials)):
- slot_src = obj.material_slots[i]
- slot_dst = obj_cell.material_slots[i]
-
- slot_dst.link = slot_src.link
- slot_dst.material = slot_src.material
-
- if use_debug_redraw:
- view_layer.update()
- _redraw_yasiamevil()
-
- view_layer.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(context, obj, objects,
- use_debug_bool=False,
- clean=True,
- use_island_split=False,
- use_interior_hide=False,
- use_debug_redraw=False,
- level=0,
- remove_doubles=True
- ):
-
- objects_boolean = []
- collection = context.collection
- scene = context.scene
- view_layer = context.view_layer
- depsgraph = context.evaluated_depsgraph_get()
-
- if use_interior_hide and level == 0:
- # only set for level 0
- obj.data.polygons.foreach_set("hide", [False] * len(obj.data.polygons))
-
- for obj_cell in objects:
- mod = obj_cell.modifiers.new(name="Boolean", type='BOOLEAN')
- mod.object = obj
- mod.operation = 'INTERSECT'
-
- if not use_debug_bool:
-
- if use_interior_hide:
- obj_cell.data.polygons.foreach_set("hide", [True] * len(obj_cell.data.polygons))
-
- obj_cell_eval = obj_cell.evaluated_get(depsgraph)
- mesh_new = bpy.data.meshes.new_from_object(obj_cell_eval)
- 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:
- collection.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
-
- # avoid unneeded bmesh re-conversion
- if mesh_new is not None:
- bm = None
-
- if clean:
- if bm is None: # ok this will always be true for now...
- bm = bmesh.new()
- bm.from_mesh(mesh_new)
- 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()
-
- if remove_doubles:
- if bm is None:
- bm = bmesh.new()
- bm.from_mesh(mesh_new)
- bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.005)
-
- if bm is not None:
- bm.to_mesh(mesh_new)
- bm.free()
-
- del mesh_new
- del mesh_old
-
- if obj_cell is not None:
- objects_boolean.append(obj_cell)
-
- if use_debug_redraw:
- _redraw_yasiamevil()
-
- if (not use_debug_bool) and use_island_split:
- # this is ugly and Im not proud of this - campbell
- for ob in view_layer.objects:
- ob.select_set(True)
- for obj_cell in objects_boolean:
- obj_cell.select_set(True)
-
- bpy.ops.mesh.separate(type='LOOSE')
-
- objects_boolean[:] = [obj_cell for obj_cell in scene.objects if obj_cell.select]
-
- context.view_layer.update()
-
- return objects_boolean
-
-
-def cell_fracture_interior_handle(objects,
- use_interior_vgroup=False,
- use_sharp_edges=False,
- use_sharp_edges_apply=False,
- ):
- """Run after doing _all_ booleans"""
-
- assert(use_interior_vgroup or use_sharp_edges or use_sharp_edges_apply)
-
- for obj_cell in objects:
- mesh = obj_cell.data
- bm = bmesh.new()
- bm.from_mesh(mesh)
-
- if use_interior_vgroup:
- for bm_vert in bm.verts:
- bm_vert.tag = True
- for bm_face in bm.faces:
- if not bm_face.hide:
- for bm_vert in bm_face.verts:
- bm_vert.tag = False
-
- # now add all vgroups
- defvert_lay = bm.verts.layers.deform.verify()
- for bm_vert in bm.verts:
- if bm_vert.tag:
- bm_vert[defvert_lay][0] = 1.0
-
- # add a vgroup
- obj_cell.vertex_groups.new(name="Interior")
-
- if use_sharp_edges:
- mesh.show_edge_sharp = True
- for bm_edge in bm.edges:
- if len({bm_face.hide for bm_face in bm_edge.link_faces}) == 2:
- bm_edge.smooth = False
-
- if use_sharp_edges_apply:
- edges = [edge for edge in bm.edges if edge.smooth is False]
- if edges:
- bm.normal_update()
- bmesh.ops.split_edges(bm, edges=edges)
-
- for bm_face in bm.faces:
- bm_face.hide = False
-
- bm.to_mesh(mesh)
- bm.free()