diff options
Diffstat (limited to 'add_advanced_objects_menu/add_mesh_aggregate.py')
-rw-r--r-- | add_advanced_objects_menu/add_mesh_aggregate.py | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/add_advanced_objects_menu/add_mesh_aggregate.py b/add_advanced_objects_menu/add_mesh_aggregate.py new file mode 100644 index 00000000..6072cb9c --- /dev/null +++ b/add_advanced_objects_menu/add_mesh_aggregate.py @@ -0,0 +1,338 @@ +# ##### 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 ##### + +# Simple aggregate of particles / meshes +# Copy the selected objects on the active object +# Based on the position of the cursor and a defined volume +# Allows to control growth by using a Build modifier + +bl_info = { + "name": "Aggregate Mesh", + "author": "liero", + "version": (0, 0, 5), + "blender": (2, 7, 0), + "location": "View3D > Tool Shelf", + "description": "Adds geometry to a mesh like in DLA aggregators", + "category": "Object"} + + +import bpy +import bmesh +from random import ( + choice, + gauss, + seed, + ) +from mathutils import Matrix +from bpy.props import ( + BoolProperty, + FloatProperty, + IntProperty, + ) +from bpy.types import Operator + + +def use_random_seed(self): + seed(self.rSeed) + return + + +def rg(n): + return (round(gauss(0, n), 2)) + + +def remover(sel=False): + bpy.ops.object.editmode_toggle() + if sel: + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.remove_doubles(threshold=0.0001) + bpy.ops.object.mode_set() + + +class OBJECT_OT_agregate_mesh(Operator): + bl_idname = "object.agregate_mesh" + bl_label = "Aggregate" + bl_description = ("Adds geometry to a mesh like in DLA aggregators\n" + "Needs at least two selected Mesh objects") + bl_options = {'REGISTER', 'UNDO', 'PRESET'} + + volX = FloatProperty( + name="Volume X", + min=0.1, max=25, + default=3, + description="The cloud around cursor" + ) + volY = FloatProperty( + name="Volume Y", + min=0.1, max=25, + default=3, + description="The cloud around cursor" + ) + volZ = FloatProperty( + name="Volume Z", + min=0.1, max=25, + default=3, + description="The cloud around cursor" + ) + baseSca = FloatProperty( + name="Scale", + min=0.01, max=5, + default=.25, + description="Particle Scale" + ) + varSca = FloatProperty( + name="Var", + min=0, max=1, + default=0, + description="Particle Scale Variation" + ) + rotX = FloatProperty( + name="Rot Var X", + min=0, max=2, + default=0, + description="X Rotation Variation" + ) + rotY = FloatProperty( + name="Rot Var Y", + min=0, max=2, + default=0, + description="Y Rotation Variation" + ) + rotZ = FloatProperty( + name="Rot Var Z", + min=0, max=2, + default=1, + description="Z Rotation Variation" + ) + rSeed = IntProperty( + name="Random seed", + min=0, max=999999, + default=1, + description="Seed to feed random values" + ) + numP = IntProperty( + name="Number", + min=1, + max=9999, soft_max=500, + default=50, + description="Number of particles" + ) + nor = BoolProperty( + name="Normal Oriented", + default=False, + description="Align Z axis with Faces normals" + ) + cent = BoolProperty( + name="Use Face Center", + default=False, + description="Center on Faces" + ) + track = BoolProperty( + name="Cursor Follows", + default=False, + description="Cursor moves as structure grows / more compact results" + ) + anim = BoolProperty( + name="Animatable", + default=False, + description="Sort faces so you can regrow with Build Modifier, materials are lost" + ) + refresh = BoolProperty( + name="Update", + default=False + ) + auto_refresh = BoolProperty( + name="Auto", + description="Auto update spline", + default=False + ) + + def draw(self, context): + layout = self.layout + col = layout.column(align=True) + row = col.row(align=True) + + if self.auto_refresh is False: + self.refresh = False + elif self.auto_refresh is True: + self.refresh = True + + row.prop(self, "auto_refresh", toggle=True, icon="AUTO") + row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH") + + col = layout.column(align=True) + col.separator() + + col = layout.column(align=True) + col.prop(self, "volX", slider=True) + col.prop(self, "volY", slider=True) + col.prop(self, "volZ", slider=True) + + layout.label(text="Particles:") + col = layout.column(align=True) + col.prop(self, "baseSca", slider=True) + col.prop(self, "varSca", slider=True) + + col = layout.column(align=True) + col.prop(self, "rotX", slider=True) + col.prop(self, "rotY", slider=True) + col.prop(self, "rotZ", slider=True) + + col = layout.column(align=True) + col.prop(self, "rSeed", slider=False) + col.prop(self, "numP") + + row = layout.row(align=True) + row.prop(self, "nor") + row.prop(self, "cent") + + row = layout.row(align=True) + row.prop(self, "track") + row.prop(self, "anim") + + @classmethod + def poll(cls, context): + return (len(bpy.context.selected_objects) > 1 and + bpy.context.object.type == 'MESH') + + def invoke(self, context, event): + self.refresh = True + return self.execute(context) + + def execute(self, context): + if not self.refresh: + return {'PASS_THROUGH'} + + scn = bpy.context.scene + obj = bpy.context.active_object + + use_random_seed(self) + + mat = Matrix(( + (1, 0, 0, 0), + (0, 1, 0, 0), + (0, 0, 1, 0), + (0, 0, 0, 1)) + ) + if obj.matrix_world != mat: + self.report({'WARNING'}, + "Please, Apply transformations to Active Object first") + return{'FINISHED'} + + par = [o for o in bpy.context.selected_objects if o.type == 'MESH' and o != obj] + if not par: + return{'FINISHED'} + + bpy.ops.object.mode_set() + bpy.ops.object.select_all(action='DESELECT') + obj.select = True + msv = [] + + for i in range(len(obj.modifiers)): + msv.append(obj.modifiers[i].show_viewport) + obj.modifiers[i].show_viewport = False + + cur = scn.cursor_location + for i in range(self.numP): + + mes = choice(par).data + newobj = bpy.data.objects.new('nuevo', mes) + scn.objects.link(newobj) + origen = (rg(self.volX) + cur[0], rg(self.volY) + cur[1], rg(self.volZ) + cur[2]) + + cpom = obj.closest_point_on_mesh(origen) + + if self.cent: + bm = bmesh.new() + bm.from_mesh(obj.data) + if hasattr(bm.verts, "ensure_lookup_table"): + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + + newobj.location = bm.faces[cpom[3]].calc_center_median() + + bm.free() + else: + newobj.location = cpom[1] + + if self.nor: + newobj.rotation_mode = 'QUATERNION' + newobj.rotation_quaternion = cpom[1].to_track_quat('Z', 'Y') + newobj.rotation_mode = 'XYZ' + newobj.rotation_euler[0] += rg(self.rotX) + newobj.rotation_euler[1] += rg(self.rotY) + newobj.rotation_euler[2] += rg(self.rotZ) + else: + newobj.rotation_euler = (rg(self.rotX), rg(self.rotY), rg(self.rotZ)) + + newobj.scale = [self.baseSca + self.baseSca * rg(self.varSca)] * 3 + + if self.anim: + newobj.select = True + bpy.ops.object.make_single_user(type='SELECTED_OBJECTS', obdata=True) + bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) + + bme = bmesh.new() + bme.from_mesh(obj.data) + + tmp = bmesh.new() + tmp.from_mesh(newobj.data) + + for f in tmp.faces: + # z = len(bme.verts) + for v in f.verts: + bme.verts.new(list(v.co)) + bme.faces.new(bme.verts[-len(f.verts):]) + + bme.to_mesh(obj.data) + remover(True) + # Note: foo.user_clear() is deprecated use do_unlink=True instead + bpy.data.meshes.remove(newobj.data, do_unlink=True) + + else: + scn.objects.active = obj + newobj.select = True + bpy.ops.object.join() + + if self.track: + cur = scn.cursor_location = cpom[1] + + for i in range(len(msv)): + obj.modifiers[i].show_viewport = msv[i] + + for o in par: + o.select = True + + obj.select = True + + if self.auto_refresh is False: + self.refresh = False + + return{'FINISHED'} + + +def register(): + bpy.utils.register_class(OBJECT_OT_agregate_mesh) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_agregate_mesh) + + +if __name__ == '__main__': + register() |