Changeset View
Changeset View
Standalone View
Standalone View
add_advanced_objects_menu/mesh_easylattice.py
| Context not available. | |||||
| # | # | ||||
| # ##### END GPL LICENSE BLOCK ##### | # ##### END GPL LICENSE BLOCK ##### | ||||
| # TODO: find a better solution for allowing more than one lattice per scene | |||||
| bl_info = { | bl_info = { | ||||
| "name": "Easy Lattice Object", | "name": "Easy Lattice Object", | ||||
| "author": "Kursad Karatas", | "author": "Kursad Karatas", | ||||
| "version": (0, 5, 1), | "version": (0, 6, 0), | ||||
| "blender": (2, 66, 0), | "blender": (2, 66, 0), | ||||
| "location": "View3D > Easy Lattice", | "location": "View3D > Easy Lattice", | ||||
| "description": "Create a lattice for shape editing", | "description": "Create a lattice for shape editing", | ||||
| Context not available. | |||||
| from bpy.props import ( | from bpy.props import ( | ||||
| EnumProperty, | EnumProperty, | ||||
| IntProperty, | IntProperty, | ||||
| FloatProperty, | |||||
| StringProperty, | StringProperty, | ||||
| ) | ) | ||||
| # Cleanup | def createLattice(obj, props): | ||||
| def modifiersDelete(obj): | |||||
| for mod in obj.modifiers: | |||||
| if mod.name == "latticeeasytemp": | |||||
| try: | |||||
| if mod.object == bpy.data.objects['LatticeEasytTemp']: | |||||
| bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod.name) | |||||
| except: | |||||
| bpy.ops.object.modifier_remove(modifier=mod.name) | |||||
| def modifiersApplyRemove(obj): | |||||
| bpy.ops.object.select_all(action='DESELECT') | |||||
| bpy.ops.object.select_pattern(pattern=obj.name, extend=False) | |||||
| bpy.context.scene.objects.active = obj | |||||
| for mod in obj.modifiers: | |||||
| if mod.name == "latticeeasytemp": | |||||
| if mod.object == bpy.data.objects['LatticeEasytTemp']: | |||||
| bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod.name) | |||||
| def latticeDelete(obj): | |||||
| bpy.ops.object.select_all(action='DESELECT') | |||||
| for ob in bpy.context.scene.objects: | |||||
| if "LatticeEasytTemp" in ob.name: | |||||
| ob.select = True | |||||
| bpy.ops.object.delete(use_global=False) | |||||
| obj.select = True | |||||
| def createLattice(obj, size, pos, props): | |||||
| # Create lattice and object | # Create lattice and object | ||||
| lat = bpy.data.lattices.new('LatticeEasytTemp') | lat = bpy.data.lattices.new('EasyLattice') | ||||
| ob = bpy.data.objects.new('LatticeEasytTemp', lat) | ob = bpy.data.objects.new('EasyLattice', lat) | ||||
| # Take into consideration any selected vertices (default: all verticies) | |||||
| selectedVertices = createVertexGroup(obj) | |||||
| loc, rot, scl = getTransformations(obj) | size, pos = findBBox(obj, selectedVertices) | ||||
| loc, rot = getTransformations(obj) | |||||
| # the position comes from the bbox | # the position comes from the bbox | ||||
| ob.location = pos | ob.location = pos | ||||
| # the size from bbox | # the size from bbox * the incoming scale factor | ||||
| ob.scale = size | ob.scale = size * props[3] | ||||
| # the rotation comes from the combined obj world | # the rotation comes from the combined obj world | ||||
| # matrix which was converted to euler pairs | # matrix which was converted to euler pairs | ||||
| ob.rotation_euler = buildRot_World(obj) | ob.rotation_euler = buildRot_World(obj) | ||||
| ob.show_x_ray = True | ob.show_x_ray = True | ||||
| # Link object to scene | # Link object to scene | ||||
| scn = bpy.context.scene | scn = bpy.context.scene | ||||
| scn.objects.link(ob) | scn.objects.link(ob) | ||||
| Context not available. | |||||
| scn.update() | scn.update() | ||||
| # Set lattice attributes | # Set lattice attributes | ||||
| lat.interpolation_type_u = props[3] | |||||
| lat.interpolation_type_v = props[3] | |||||
| lat.interpolation_type_w = props[3] | |||||
| lat.use_outside = False | |||||
| lat.points_u = props[0] | lat.points_u = props[0] | ||||
| lat.points_v = props[1] | lat.points_v = props[1] | ||||
| lat.points_w = props[2] | lat.points_w = props[2] | ||||
| lat.interpolation_type_u = props[4] | |||||
| lat.interpolation_type_v = props[4] | |||||
| lat.interpolation_type_w = props[4] | |||||
| lat.use_outside = False | |||||
| return ob | return ob | ||||
| def selectedVerts_Grp(obj): | def createVertexGroup(obj): | ||||
| vertices = obj.data.vertices | vertices = obj.data.vertices | ||||
| selverts = [] | selverts = [] | ||||
| if obj.mode == "EDIT": | if obj.mode == "EDIT": | ||||
| bpy.ops.object.editmode_toggle() | bpy.ops.object.editmode_toggle() | ||||
| for grp in obj.vertex_groups: | group = obj.vertex_groups.new("easy_lattice_group") | ||||
| if "templatticegrp" in grp.name: | |||||
| bpy.ops.object.vertex_group_set_active(group=grp.name) | |||||
| bpy.ops.object.vertex_group_remove() | |||||
| tempgroup = obj.vertex_groups.new("templatticegrp") | |||||
| for vert in vertices: | for vert in vertices: | ||||
| if vert.select is True: | if vert.select is True: | ||||
| selverts.append(vert) | selverts.append(vert) | ||||
| tempgroup.add([vert.index], 1.0, "REPLACE") | group.add([vert.index], 1.0, "REPLACE") | ||||
| return selverts | return selverts | ||||
| Context not available. | |||||
| def getTransformations(obj): | def getTransformations(obj): | ||||
| rot = obj.rotation_euler | rot = obj.rotation_euler | ||||
| loc = obj.location | loc = obj.location | ||||
| size = obj.scale | |||||
| return [loc, rot, size] | return [loc, rot] | ||||
| def findBBox(obj, selvertsarray): | def findBBox(obj, selvertsarray): | ||||
| Context not available. | |||||
| minpoint = Vector((minx, miny, minz)) | minpoint = Vector((minx, miny, minz)) | ||||
| maxpoint = Vector((maxx, maxy, maxz)) | maxpoint = Vector((maxx, maxy, maxz)) | ||||
| # middle point has to be calculated based on the real world matrix | # The middle position has to be calculated based on the real world matrix | ||||
| middle = ((minpoint + maxpoint) / 2) | pos = ((minpoint + maxpoint) / 2) | ||||
| minpoint = mat * minpoint # Calculate only based on loc/scale | minpoint = mat * minpoint # Calculate only based on loc/scale | ||||
| maxpoint = mat * maxpoint # Calculate only based on loc/scale | maxpoint = mat * maxpoint # Calculate only based on loc/scale | ||||
| middle = mat_world * middle # the middle has to be calculated based on the real world matrix | pos = mat_world * pos # the middle position has to be calculated based on the real world matrix | ||||
| size = maxpoint - minpoint | size = maxpoint - minpoint | ||||
| size = Vector((abs(size.x), abs(size.y), abs(size.z))) | size = Vector((max(0.1, abs(size.x)), max(0.1, abs(size.y)), max(0.1, abs(size.z)))) # Prevent zero size dimensions | ||||
| return [minpoint, maxpoint, size, middle] | return [size, pos] | ||||
| def buildTrnSclMat(obj): | def buildTrnSclMat(obj): | ||||
| Context not available. | |||||
| obj = bpy.context.object | obj = bpy.context.object | ||||
| if obj.type == "MESH": | if obj.type == "MESH": | ||||
| # set global property for the currently active latticed object | lat = createLattice(obj, lat_props) | ||||
| # removed in __init__ on unregister if created | |||||
| bpy.types.Scene.activelatticeobject = StringProperty( | |||||
| name="currentlatticeobject", | |||||
| default="" | |||||
| ) | |||||
| bpy.types.Scene.activelatticeobject = obj.name | |||||
| modifiersDelete(obj) | modif = obj.modifiers.new("EasyLattice", "LATTICE") | ||||
| selvertsarray = selectedVerts_Grp(obj) | |||||
| bbox = findBBox(obj, selvertsarray) | |||||
| size = bbox[2] | |||||
| pos = bbox[3] | |||||
| latticeDelete(obj) | |||||
| lat = createLattice(obj, size, pos, lat_props) | |||||
| modif = obj.modifiers.new("latticeeasytemp", "LATTICE") | |||||
| modif.object = lat | modif.object = lat | ||||
| modif.vertex_group = "templatticegrp" | modif.vertex_group = "easy_lattice_group" | ||||
| bpy.ops.object.select_all(action='DESELECT') | bpy.ops.object.select_all(action='DESELECT') | ||||
| bpy.ops.object.select_pattern(pattern=lat.name, extend=False) | bpy.ops.object.select_pattern(pattern=lat.name, extend=False) | ||||
| bpy.context.scene.objects.active = lat | bpy.context.scene.objects.active = lat | ||||
| bpy.context.scene.update() | bpy.context.scene.update() | ||||
| bpy.ops.object.mode_set(mode='EDIT') | |||||
| if obj.type == "LATTICE": | |||||
| if bpy.types.Scene.activelatticeobject: | |||||
| name = bpy.types.Scene.activelatticeobject | |||||
| # Are we in edit lattice mode? If so move on to object mode | |||||
| if obj.mode == "EDIT": | |||||
| bpy.ops.object.editmode_toggle() | |||||
| for ob in bpy.context.scene.objects: | |||||
| if ob.name == name: # found the object with the lattice mod | |||||
| object = ob | |||||
| modifiersApplyRemove(object) | |||||
| latticeDelete(obj) | |||||
| return | return | ||||
| Context not available. | |||||
| bl_idname = "object.easy_lattice" | bl_idname = "object.easy_lattice" | ||||
| bl_label = "Easy Lattice Creator" | bl_label = "Easy Lattice Creator" | ||||
| bl_description = ("Create a Lattice modifier ready to edit\n" | bl_description = ("Create a Lattice modifier ready to edit\n" | ||||
| "Needs an existing Active Mesh Object\n" | "Needs an existing Active Mesh Object\n") | ||||
| "Note: Works only with one lattice per scene") | |||||
| lat_u = IntProperty( | lat_u = IntProperty( | ||||
| name="Lattice u", | name="Lattice u", | ||||
| description="Points in u direction", | description="Points in u direction", | ||||
| default=3 | default=3 | ||||
| ) | ) | ||||
| lat_v = IntProperty( | |||||
| name="Lattice v", | |||||
| description="Points in v direction", | |||||
| default=3 | |||||
| ) | |||||
| lat_w = IntProperty( | lat_w = IntProperty( | ||||
| name="Lattice w", | name="Lattice w", | ||||
| description="Points in w direction", | description="Points in w direction", | ||||
| default=3 | default=3 | ||||
| ) | ) | ||||
| lat_m = IntProperty( | lat_scale_factor = FloatProperty( | ||||
| name="Lattice m", | name="Lattice scale factor", | ||||
| description="Points in m direction", | description="Adjustment to the lattice scale", | ||||
| default=3 | default=1, | ||||
| min=0.1, | |||||
| step=1, | |||||
| precision=2 | |||||
| ) | ) | ||||
| lat_types = (('KEY_LINEAR', "Linear", "Linear Interpolation type"), | lat_types = (('KEY_LINEAR', "Linear", "Linear Interpolation type"), | ||||
| ('KEY_CARDINAL', "Cardinal", "Cardinal Interpolation type"), | ('KEY_CARDINAL', "Cardinal", "Cardinal Interpolation type"), | ||||
| ('KEY_CATMULL_ROM', "Catmull-Rom", "Catmull-Rom Interpolation type"), | |||||
| ('KEY_BSPLINE', "BSpline", "Key BSpline Interpolation Type") | ('KEY_BSPLINE', "BSpline", "Key BSpline Interpolation Type") | ||||
| ) | ) | ||||
| lat_type = EnumProperty( | lat_type = EnumProperty( | ||||
| name="Lattice Type", | name="Lattice Type", | ||||
| description="Choose Lattice Type", | description="Choose Lattice Type", | ||||
| items=lat_types, | items=lat_types, | ||||
| default='KEY_LINEAR' | default='KEY_BSPLINE' | ||||
| ) | ) | ||||
| @classmethod | @classmethod | ||||
| Context not available. | |||||
| col = layout.column(align=True) | col = layout.column(align=True) | ||||
| col.prop(self, "lat_u") | col.prop(self, "lat_u") | ||||
| col.prop(self, "lat_v") | |||||
| col.prop(self, "lat_w") | col.prop(self, "lat_w") | ||||
| col.prop(self, "lat_m") | |||||
| layout.prop(self, "lat_scale_factor") | |||||
| layout.prop(self, "lat_type") | layout.prop(self, "lat_type") | ||||
| def execute(self, context): | def execute(self, context): | ||||
| lat_u = self.lat_u | lat_u = self.lat_u | ||||
| lat_v = self.lat_v | |||||
| lat_w = self.lat_w | lat_w = self.lat_w | ||||
| lat_m = self.lat_m | |||||
| lat_scale_factor = self.lat_scale_factor | |||||
| # enum property no need to complicate things | # enum property no need to complicate things | ||||
| lat_type = self.lat_type | lat_type = self.lat_type | ||||
| lat_props = [lat_u, lat_w, lat_m, lat_type] | lat_props = [lat_u, lat_v, lat_w, lat_scale_factor, lat_type] | ||||
| try: | try: | ||||
| main(context, lat_props) | main(context, lat_props) | ||||
| Context not available. | |||||