diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-07-07 04:19:05 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-07-07 04:25:19 +0300 |
commit | 3f68f8442a531ebf234ac6d01fb35a4a5a0c2213 (patch) | |
tree | dfbe21b25f5cf0e527e3ca79972dca07db1b4a46 /object_fracture_cell/__init__.py | |
parent | 8f4c893499ffc6050d587ab03192e5457eed96f4 (diff) |
Revert changes to 'object_fracture_cell'
This reverts commits:
daaff4199bb8a9bcf90319e48f4444989a3fc42a.
64d89567923df223f50eeeaa2f79f93f23da74f6.
fffaf5d2759d38d4166f608eab8871fcd59a7e11.
f7c91d3382ea19ce4565105c85288044a2d1b833.
These changes removed/added functionality
beyond the scope of porting 2.7x to 2.8x,
where only minor changes were needed.
Diffstat (limited to 'object_fracture_cell/__init__.py')
-rw-r--r-- | object_fracture_cell/__init__.py | 682 |
1 files changed, 413 insertions, 269 deletions
diff --git a/object_fracture_cell/__init__.py b/object_fracture_cell/__init__.py index 794c2fe1..e1fcb41f 100644 --- a/object_fracture_cell/__init__.py +++ b/object_fracture_cell/__init__.py @@ -18,23 +18,20 @@ bl_info = { "name": "Cell Fracture", - "author": "ideasman42, phymec, Sergey Sharybin, Nobuyuki Hirakata", - "version": (1, 0, 2), - "blender": (2, 80, 0), - "location": "View3D > Sidebar > Transform tab", - "description": "Fractured Object, or Cracked Surface", - "warning": "Work in Progress", + "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(operator) - -else: - from . import operator +#if "bpy" in locals(): +# import importlib +# importlib.reload(fracture_cell_setup) import bpy from bpy.props import ( @@ -44,114 +41,244 @@ from bpy.props import ( FloatProperty, FloatVectorProperty, EnumProperty, - BoolVectorProperty, - PointerProperty, ) -from bpy.types import ( - Panel, - PropertyGroup, - ) +from bpy.types import Operator +def main_object(context, obj, level, **kw): + import random -class FRACTURE_PT_Menu(Panel): - bl_idname = 'FRACTURE_PT_Menu' - bl_label = "Fracture Cell" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - bl_category = "Create" - bl_context = 'objectmode' - bl_options = {"DEFAULT_CLOSED"} + # 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'} - def draw(self, context): - # Show pop-upped menu when the button is hit. - layout = self.layout - #layout.label(text="Cell Fracture:") - layout.operator(operator.FRACTURE_OT_Cell.bl_idname, - text="1. Cell Fracture") - layout.operator(operator.FRACTURE_OT_Crack.bl_idname, - text="2. Cell to Crack") - - material_props = context.window_manager.fracture_material_props - layout.separator() - box = layout.box() - col = box.column() - row = col.row(align=True) - row.label(text="Material Preset:") - ''' - row_sub = row.row() - row_sub.prop(material_props, "material_lib_name", text="", - toggle=True, icon="LONGDISPLAY") - ''' - row = box.row() - row.prop(material_props, "material_preset", text="") - - row = box.row() - row.operator(operator.FRACTURE_OT_Material.bl_idname, icon="MATERIAL_DATA", - text="Append Material") - - -class FractureCellProperties(PropertyGroup): # ------------------------------------------------------------------------- # Source Options - source_vert_own: IntProperty( - name="Own Verts", - description="Use own vertices", - min=0, max=2000, - default=100, - ) - source_vert_child: IntProperty( - name="Child Verts", - description="Use child object vertices", - min=0, max=2000, - default=0, - ) - source_particle_own: IntProperty( - name="Own Particles", - description="All particle systems of the source object", - min=0, max=2000, - default=0, - ) - source_particle_child: IntProperty( - name="Child Particles", - description="All particle systems of the child objects", - min=0, max=2000, - default=0, - ) - source_pencil: IntProperty( - name="Annotation Pencil", - description="Annotation Grease Pencil", - min=0, max=2000, - default=0, - ) - source_random: IntProperty( - name="Random", - description="Random seed position", - min=0, max=2000, - default=0, + 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, ) - ''' - # ------------------------------------------------------------------------- - # Transform + source_noise: FloatProperty( name="Noise", description="Randomize point distribution", min=0.0, max=1.0, default=0.0, ) - margin: FloatProperty( - name="Margin", - description="Gaps for the fracture (gives more stable physics)", - min=0.0, max=1.0, - default=0.001, - ) + cell_scale: FloatVectorProperty( name="Scale", description="Scale Cell Shape", @@ -159,51 +286,40 @@ class FractureCellProperties(PropertyGroup): min=0.0, max=1.0, default=(1.0, 1.0, 1.0), ) - pre_simplify : FloatProperty( - name="Simplify Base Mesh", - description="Simplify base mesh before making cell. Lower face size, faster calculation", - default=0.00, - min=0.00, - max=1.00 - ) - use_recenter: BoolProperty( - name="Recenter", - description="Recalculate the center points after splitting", - default=True, - ) - use_island_split: BoolProperty( - name="Split Islands", - description="Split disconnected meshes", - default=True, - ) + # ------------------------------------------------------------------------- # Recursion + recursion: IntProperty( name="Recursion", description="Break shards recursively", - min=0, max=2000, + min=0, max=5000, default=0, ) + recursion_source_limit: IntProperty( - name="Fracture Each", + name="Source Limit", description="Limit the number of input points, 0 for unlimited (applies to recursion only)", - min=2, max=2000, # Oviously, dividing in more than two objects is needed, to avoid no fracture object. + min=0, max=5000, default=8, ) + recursion_clamp: IntProperty( - name="Max Fracture", + 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="Rec Chance", + name="Random Factor", description="Likelihood of recursion", min=0.0, max=1.0, - default=1.00, + default=0.25, ) + recursion_chance_select: EnumProperty( - name="Target", + name="Recurse Over", items=(('RANDOM', "Random", ""), ('SIZE_MIN', "Small", "Recursively subdivide smaller objects"), ('SIZE_MAX', "Big", "Recursively subdivide bigger objects"), @@ -212,77 +328,61 @@ class FractureCellProperties(PropertyGroup): ), default='SIZE_MIN', ) + # ------------------------------------------------------------------------- - # Interior Meshes Options + # Mesh Data Options + use_smooth_faces: BoolProperty( name="Smooth Faces", - description="Smooth Faces of inner side", default=False, ) + use_sharp_edges: BoolProperty( - name="Mark Sharp Edges", + name="Sharp Edges", description="Set sharp edges when disabled", - default=False, + default=True, ) + use_sharp_edges_apply: BoolProperty( - name="Edge Split Modifier", - description="Add edge split modofier for sharp edges", - default=False, + name="Apply Split Edge", + description="Split sharp hard edges", + default=True, ) + use_data_match: BoolProperty( - name="Copy Original Data", + 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="Interior Material Slot", + name="Material", description="Material index for interior faces", default=0, ) + use_interior_vgroup: BoolProperty( - name="Vertex Group", + name="Interior VGroup", description="Create a vertex group for interior verts", default=False, ) + # ------------------------------------------------------------------------- - # Scene Options - use_collection: BoolProperty( - name="Use Collection", - description="Use collection to organize fracture objects", - default=True, - ) - new_collection: BoolProperty( - name="Use New", - description="Make new collection for fracture objects", - default=True, - ) - collection_name: StringProperty( - name="Name", - description="Collection name.", - default="Fracture", - ) - original_hide: BoolProperty( - name="Hide Original", - description="Hide original object after cell fracture.", - default=False, - ) - cell_relocate : BoolProperty( - name="Move Beside Original", - description="Move cells beside the original object.", - default=False, - ) - # ------------------------------------------------------------------------- - # Custom Property Options - use_mass: BoolProperty( - name="Mass", - description="Append mass data on custom properties of cell objects.", - default=False, - ) - mass_name: StringProperty( - name="Property Name", - description="Name for custome properties.", - default="mass", - ) + # Physics Options + mass_mode: EnumProperty( name="Mass Mode", items=(('VOLUME', "Volume", "Objects get part of specified mass based on their volume"), @@ -290,12 +390,55 @@ class FractureCellProperties(PropertyGroup): ), default='VOLUME', ) + mass: FloatProperty( - name="Mass Factor", + 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( @@ -307,7 +450,7 @@ class FractureCellProperties(PropertyGroup): use_debug_redraw: BoolProperty( name="Show Progress Realtime", description="Redraw as fracture is done", - default=False, + default=True, ) use_debug_bool: BoolProperty( @@ -316,109 +459,110 @@ class FractureCellProperties(PropertyGroup): default=False, ) + def execute(self, context): + keywords = self.as_keywords() # ignore=("blah",) -class FractureCrackProperties(PropertyGroup): - modifier_decimate : FloatProperty( - name="Reduce Faces", - description="Apply Decimate Modifier to reduce face number", - default=0.40, - min=0.00, - max=1.00 - ) - modifier_smooth : FloatProperty( - name="Loose | Tight", - description="Smooth Modifier", - default=-0.50, - min=-3.00, - max=3.00 - ) - extrude_scale : FloatProperty( - name="Extrude Blob", - description="Extrude Scale", - default=0.00, - min=0.00, - max=5.00 - ) - extrude_var : FloatProperty( - name="Extrude Random ", - description="Extrude Varriant", - default=0.01, - min=-4.00, - max=4.00 - ) - extrude_num : IntProperty( - name="Extrude Num", - description="Extrude Number", - default=1, - min=0, - max=10 - ) - modifier_wireframe : BoolProperty( - name="Wireframe Modifier", - description="Wireframe Modifier", - default=False - ) + main(context, **keywords) + return {'FINISHED'} -class FractureMaterialProperties(PropertyGroup): - # Note: you can choose the original name in the library blend - # or the prop name - material_preset : EnumProperty( - name="Preset", - description="Material Preset", - items=[ - ('crackit_organic_mud', "Organic Mud", "Mud material"), - ('crackit_mud', "Mud", "Mud material"), - ('crackit_tree_moss', "Tree Moss", "Tree Material"), - ('crackit_tree_dry', "Tree Dry", "Tree Material"), - ('crackit_tree_red', "Tree Red", "Tree Material"), - ('crackit_rock', "Rock", "Rock Material"), - ('crackit_lava', "Lava", "Lava Material"), - ('crackit_wet-paint', "Wet Paint", "Paint Material"), - ('crackit_soap', "Soap", "Soap Material"), - ] - ) - material_lib_name : BoolProperty( - name="Library Name", - description="Use the original Material name from the .blend library\n" - "instead of the one defined in the Preset", - default=True - ) -classes = ( - FractureCellProperties, - FractureCrackProperties, - FractureMaterialProperties, - operator.FRACTURE_OT_Cell, - operator.FRACTURE_OT_Crack, - operator.FRACTURE_OT_Material, - FRACTURE_PT_Menu, - ) + 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(): - from bpy.utils import register_class - for cls in classes: - register_class(cls) - - bpy.types.WindowManager.fracture_cell_props = PointerProperty( - type=FractureCellProperties - ) - bpy.types.WindowManager.fracture_crack_props = PointerProperty( - type=FractureCrackProperties - ) - bpy.types.WindowManager.fracture_material_props = PointerProperty( - type=FractureMaterialProperties - ) + bpy.utils.register_class(FractureCell) + bpy.types.VIEW3D_PT_tools_object.append(menu_func) + def unregister(): - del bpy.types.WindowManager.fracture_material_props - del bpy.types.WindowManager.fracture_crack_props - del bpy.types.WindowManager.fracture_cell_props + bpy.utils.unregister_class(FractureCell) + bpy.types.VIEW3D_PT_tools_object.remove(menu_func) - from bpy.utils import unregister_class - for cls in reversed(classes): - unregister_class(cls) if __name__ == "__main__": - register() - + register() |