Skip to content
Snippets Groups Projects
tessellate_numpy.py 52.8 KiB
Newer Older
  • Learn to ignore specific revisions
  •         row = col.row(align=True)
            col2 = row.column(align=True)
            col2.prop(self, "gen_modifiers", text="Use Modifiers")
            if len(bpy.data.objects[self.generator].modifiers) == 0:
                col2.enabled = False
                self.gen_modifiers = False
            col2 = row.column(align=True)
            col2.prop(self, "com_modifiers", text="Use Modifiers")
            if len(bpy.data.objects[self.component].modifiers) == 0:
                col2.enabled = False
                self.com_modifiers = False
    
            # On selected faces
            row = col.row(align=True)
            row.prop(self, "bool_selection", text="On selected Faces")
            col.separator()
    
            # Count number of faces
            try:
                polygons = 0
                if self.gen_modifiers:
                    me_temp = bpy.data.objects[self.generator].to_mesh(
                        bpy.context.scene, apply_modifiers=True,
                        settings = 'PREVIEW')
                else: me_temp = bpy.data.objects[self.generator].data
                for p in me_temp.polygons:
                    if not self.bool_selection or p.select:
                        if self.fill_mode == "FAN": polygons += len(p.vertices)
                        else: polygons += 1
    
                if self.com_modifiers:
                    me_temp = bpy.data.objects[self.component].to_mesh(
                        bpy.context.scene, apply_modifiers=True,
                        settings = 'PREVIEW')
                else: me_temp = bpy.data.objects[self.component].data
                polygons *= len(me_temp.polygons)
    
                str_polygons = '{:0,.0f}'.format(polygons)
                if polygons > 200000:
                    col.label(text=str_polygons + " polygons will be created!",
                              icon='ERROR')
                else:
                    col.label(text=str_polygons + " faces will be created!",
                              icon='INFO')
            except:
                pass
            col.separator()
    
            # Fill and Rotation
            row = col.row(align=True)
            row.label(text="Fill Mode:")
            row.separator()
            row.label(text="Rotation:")
            row = col.row(align=True)
    
            # fill
            row.prop(self, "fill_mode", text="", icon='NONE', expand=False,
                     slider=True, toggle=False, icon_only=False, event=False,
                     full_event=False, emboss=True, index=-1)
            row.separator()
    
            # rotation
            row.prop(self, "rotation_mode", text="", icon='NONE', expand=False,
                     slider=True, toggle=False, icon_only=False, event=False,
                     full_event=False, emboss=True, index=-1)
            if self.rotation_mode == 'RANDOM':
                row = col.row(align=True)
                row.prop(self, "random_seed")
            if self.rotation_mode == 'UV':
                uv_error = False
                if self.fill_mode == 'FAN':
                    row = col.row(align=True)
                    row.label(text="UV rotation doesn't work in FAN mode",
                              icon='ERROR')
                    uv_error = True
                if len(bpy.data.objects[self.generator].data.uv_layers) == 0:
                    row = col.row(align=True)
                    row.label(text="'" + bpy.data.objects[self.generator].name + \
                              " doesn't have UV Maps", icon='ERROR')
                    uv_error = True
                if uv_error:
                    row = col.row(align=True)
                    row.label(text="Default rotation will be used instead",
                              icon='INFO')
    
            # component XY
            row = col.row(align=True)
            row.label(text="Component XY:")
            row = col.row(align=True)
            row.prop(self, "mode", text="Component XY", icon='NONE', expand=True,
                     slider=False, toggle=False, icon_only=False, event=False,
                     full_event=False, emboss=True, index=-1)
    
            # component Z
            col.label(text="Component Z:")
            row = col.row(align=True)
            row.prop(self, "scale_mode", text="Scale Mode", icon='NONE',
                     expand=True, slider=False, toggle=False, icon_only=False,
                     event=False, full_event=False, emboss=True, index=-1)
            col.prop(self, "zscale", text="Scale", icon='NONE', expand=False,
                     slider=True, toggle=False, icon_only=False, event=False,
                     full_event=False, emboss=True, index=-1)
            col.prop(self, "offset", text="Offset", icon='NONE', expand=False,
                     slider=True, toggle=False, icon_only=False, event=False,
                     full_event=False, emboss=True, index=-1)
    
            # merge
            col = layout.column(align=True)
            row = col.row(align=True)
            row.prop(self, "merge")
            if self.merge: row.prop(self, "merge_thres")
            row = col.row(align=True)
    
            ### ADVANCED ###
            col = layout.column(align=True)
            tessellate.rotation_mode
    
            col.label(text="Advanced Settings:")
            # vertex group + shape keys
            row = col.row(align=True)
            col2 = row.column(align=True)
            col2.prop(self, "bool_vertex_group")
            if len(bpy.data.objects[self.generator].vertex_groups) == 0:
                col2.enabled = False
                bool_vertex_group = False
            col2 = row.column(align=True)
            col2.prop(self, "bool_shapekeys", text="Use Shape Keys")
            if len(bpy.data.objects[self.generator].vertex_groups) == 0 or \
                    bpy.data.objects[self.component].data.shape_keys == None:
                col2.enabled = False
                bool_shapekeys = False
            elif len(bpy.data.objects[self.generator].vertex_groups) == 0 or \
                    bpy.data.objects[self.component].data.shape_keys != None:
                if len(bpy.data.objects[self.component].data.shape_keys.key_blocks) < 2:
                    col2.enabled = False
                    bool_shapekeys = False
            self.go = True
    
        def execute(self, context):
            self.ob = bpy.context.active_object
            old_material = None
            if(len(self.ob.material_slots) > 0):
                old_material = self.ob.material_slots[0].material
            if not self.go:
                self.generator = self.ob.tissue_tessellate.generator
                self.component = self.ob.tissue_tessellate.component
                self.zscale = self.ob.tissue_tessellate.zscale
                self.scale_mode = self.ob.tissue_tessellate.scale_mode
                self.rotation_mode = self.ob.tissue_tessellate.rotation_mode
                self.offset = self.ob.tissue_tessellate.offset
                self.merge = self.ob.tissue_tessellate.merge
                self.merge_thres = self.ob.tissue_tessellate.merge_thres
                self.gen_modifiers = self.ob.tissue_tessellate.gen_modifiers
                self.com_modifiers = self.ob.tissue_tessellate.com_modifiers
                self.bool_random = self.ob.tissue_tessellate.bool_random
                self.random_seed = self.ob.tissue_tessellate.random_seed
                self.fill_mode = self.ob.tissue_tessellate.fill_mode
                self.bool_vertex_group = self.ob.tissue_tessellate.bool_vertex_group
                self.bool_selection = self.ob.tissue_tessellate.bool_selection
                self.bool_shapekeys = self.ob.tissue_tessellate.bool_shapekeys
    
            if(self.generator == "" or self.component == ""):
                self.report({'ERROR'},
                            "Active object must be Tessellate before Update")
                return {'CANCELLED'}
            if(bpy.data.objects[self.generator].type != 'MESH'):
                self.report({'ERROR'}, "Base object must be a Mesh")
                return {'CANCELLED'}
            if(bpy.data.objects[self.component].type != 'MESH'):
                self.report({'ERROR'}, "Component object must be a Mesh")
                return {'CANCELLED'}
    
            ob0 = bpy.data.objects[self.generator]
            ob1 = bpy.data.objects[self.component]
            me0 = ob0.data
            verts = me0.vertices
    
            temp_ob = tassellate(
                ob0, ob1, self.offset, self.zscale, self.gen_modifiers,
                self.com_modifiers, self.mode, self.scale_mode, self.rotation_mode,
                self.random_seed, self.fill_mode, self.bool_vertex_group,
                self.bool_selection, self.bool_shapekeys)
    
            if temp_ob == 0:
                message = "Zero faces selected in the Base mesh!"
                self.report({'ERROR'}, message)
                return {'CANCELLED'}
    
            # Transfer mesh data
            self.ob.data = temp_ob.data
    
            # Create object in order to transfer vertex group
            scene = bpy.context.scene
            scene.objects.link(temp_ob)
            temp_ob.select = True
            bpy.context.scene.objects.active = temp_ob
            try:
                bpy.ops.object.vertex_group_copy_to_linked()
            except:
                pass
            scene.objects.unlink(temp_ob)
            bpy.data.objects.remove(temp_ob)
            bpy.context.scene.objects.active = self.ob
    
            if self.merge:
                bpy.ops.object.mode_set(mode = 'EDIT')
                bpy.ops.mesh.select_mode(
                    use_extend=False, use_expand=False, type='VERT')
                bpy.ops.mesh.select_non_manifold(
                    extend=False, use_wire=False, use_boundary=True,
                    use_multi_face=False, use_non_contiguous=False, use_verts=False)
                bpy.ops.mesh.remove_doubles(
                    threshold=self.merge_thres, use_unselected=False)
                bpy.ops.object.mode_set(mode = 'OBJECT')
            self.ob = store_parameters(self, self.ob)
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.object.mode_set(mode='OBJECT')
    
            # MATERIALS
            # create materials list
            polygon_materials = [p.material_index for p in ob1.data.polygons] * \
                int(len(self.ob.data.polygons) / len(ob1.data.polygons))
            # assign old material
            component_materials = [slot.material for slot in ob1.material_slots]
            for i in range(len(component_materials)):
                bpy.ops.object.material_slot_add()
                bpy.context.object.material_slots[i].material = \
                    component_materials[i]
            for i in range(len(self.ob.data.polygons)):
                self.ob.data.polygons[i].material_index = polygon_materials[i]
            return {'FINISHED'}
    
        def check(self, context):
            return True
    
        def invoke(self, context, event):
            return context.window_manager.invoke_props_dialog(self)
    
    
    class tessellate_panel(bpy.types.Panel):
        bl_label = "Tessellate"
        bl_category = "Create"
        bl_space_type = "VIEW_3D"
        bl_region_type = "TOOLS"
    
        bl_options = {'DEFAULT_CLOSED'}
    
        #bl_context = "objectmode", "editmode"
    
        def draw(self, context):
            layout = self.layout
            col = layout.column(align=True)
            col.label(text="Add:")
            col.operator("object.tessellate")#, icon="STRANDS")
            #col.enable = False
            #col.operator("object.adaptive_duplifaces", icon="MESH_CUBE")
            col = layout.column(align=True)
            col.label(text="Edit:")
            col.operator("object.settings_tessellate")
            col.operator("object.update_tessellate")
            col = layout.column(align=True)
            col.operator("mesh.rotate_face")
            act = context.active_object
            sel = act #context.selected_objects[0]
    
            for ob1 in context.selected_objects:
                if(ob1.name == act.name or ob1.type != 'MESH'): continue
                sel = ob1
    
    
    class rotate_face(bpy.types.Operator):
        bl_idname = "mesh.rotate_face"
        bl_label = "Rotate Faces"
        bl_description = "Rotate selected faces and update tessellated meshes."
        bl_options = {'REGISTER', 'UNDO'}
    
        @classmethod
        def poll(cls, context):
            return context.mode == 'EDIT_MESH'
    
        def execute(self, context):
            ob = bpy.context.active_object
            me = ob.data
            bpy.ops.object.mode_set(mode='OBJECT')
    
            for p in [f for f in me.polygons if f.select]:
                p.vertices = p.vertices[1:] + p.vertices[:1]
    
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.flip_normals()
            bpy.ops.mesh.flip_normals()
            #me.vertices[0].co[0] = 10
            me.update(calc_edges=True)
    
            #update tessellated meshes
            bpy.ops.object.mode_set(mode='OBJECT')
            for o in [object for object in bpy.data.objects if \
                    object.tissue_tessellate.generator == ob.name]:
                bpy.context.scene.objects.active = o
                bpy.ops.object.update_tessellate()
            bpy.context.scene.objects.active = ob
            bpy.ops.object.mode_set(mode='EDIT')
            return {'FINISHED'}
    
    
    def register():
        bpy.utils.register_class(tissue_tessellate_prop)
        bpy.utils.register_class(tessellate)
        bpy.utils.register_class(update_tessellate)
        bpy.utils.register_class(settings_tessellate)
        bpy.utils.register_class(tessellate_panel)
        bpy.utils.register_class(rotate_face)
    
    
    def unregister():
        bpy.utils.unregister_class(tissue_tessellate_prop)
        bpy.utils.unregister_class(tessellate)
        bpy.utils.unregister_class(update_tessellate)
        bpy.utils.unregister_class(settings_tessellate)
        bpy.utils.unregister_class(tessellate_panel)
        bpy.utils.unregister_class(rotate_face)
    
    
    if __name__ == "__main__":
        register()