├── 45_rotate_gesture.py ├── Asset_Flinger_Thumbnail.py ├── AutoMirror_V2-5_2-8.py ├── BlenderDeformTools.py ├── Compact_Properties.py ├── ExtraMaterialList.py ├── Layer_M.py ├── Material_list.py ├── OBJ_&_Thumbnail_for_Asset_Flinger.py ├── README.md ├── Sculpt_status_header.py ├── angle_select_click.py ├── curve_and_array_set.py ├── dup_x.py ├── group_layer.py ├── header_color_change.py ├── ice_tools.py ├── info_header_useful.py ├── isolate_select.py ├── key_copypae_x.py ├── keymap_set.py ├── maskTools_2-79.zip ├── maskTools_2-79 ├── __init__.py ├── maskFromCavity.py ├── maskToAction.py ├── maskToVGroup.py └── vgroupToMask.py ├── maskTools_2-8.zip ├── maskTools_2-8 ├── __init__.py ├── maskFromCavity.py ├── maskToAction.py ├── maskToVGroup.py └── vgroupToMask.py ├── misc ├── UbuntuAmbiance_bookyakunoEdit.xml ├── addon-keymap-menu(can be changed from the menu).py ├── bone_hierarchy_menu.py ├── energy_bk.xml ├── key_20180326.py ├── startup.blend └── userpref.blend ├── multi_ob_bake.py ├── optiloops.py ├── reload_addon.py ├── render_check_list.py ├── rigify_select_pie_menu.py ├── save_all_renderlayers_and_passes_bk_edit.py ├── sharp_knife.py ├── vert_circle_x.py ├── vtools_libraryManager.py ├── w_pie.zip ├── w_pie ├── TranslationDictionary.csv ├── __init__.py ├── add_pie.py ├── misc_pie.py ├── uv_pie.py └── w_pie.py └── wazou_pie_menus_bk_edit.py /45_rotate_gesture.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | 19 | 20 | import bpy 21 | 22 | 23 | 24 | bl_info = {'name':'45 rotate gesture', 25 | 'author':'bookyakuno', 26 | 'version':(0,1), 27 | 'category':'3D View', 28 | 'location':'View3D > cmd + D , Ctrl + Shift + D', 29 | 'description':'45 rotate Gesture'} 30 | 31 | 32 | 33 | class rotate_gesture(bpy.types.Operator): 34 | bl_idname = "object.rotate_gesture" 35 | bl_label = "45 rotate gesture" 36 | bl_options = {'REGISTER', 'UNDO'} 37 | 38 | 39 | 40 | # first_mouse_x = IntProperty() 41 | # first_mouse_y = IntProperty() 42 | # first_mouse_z = IntProperty() 43 | # first_valuex = FloatProperty() 44 | # first_valuey = FloatProperty() 45 | # first_valuez = FloatProperty() 46 | # axis = StringProperty() 47 | # value_fix_x = 0 48 | # value_fix_y = 0 49 | # value_fix_z = 0 50 | # nd = 0 51 | def vdist(self): 52 | area=bpy.context.window.screen.areas[0] 53 | for x in bpy.context.window.screen.areas: 54 | if x.type=='VIEW_3D': area=x 55 | 56 | area.spaces[0].region_3d.view_distance 57 | return area.spaces[0].region_3d.view_distance 58 | 59 | def modal(self, context, event): 60 | 61 | # 説明 62 | context.area.header_text_set('Mouse wheel Up/Down or + - key = 45, Shift +wheel = -45, ZXCY = & AXIS, Shift + ZXCY = -45 & AXIS') 63 | 64 | 65 | ################################################################ 66 | 67 | ################################################################ 68 | # # # # # # # # 69 | 70 | if event.type == 'D' and event.value=='PRESS': 71 | bpy.ops.transform.rotate(value=0.785398, constraint_orientation='GLOBAL') #編集 72 | 73 | 74 | elif event.type == 'WHEELUPMOUSE' and event.shift and event.value=='PRESS': 75 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(True, False, False), constraint_orientation='GLOBAL') #編集 76 | elif event.type == 'WHEELDOWNMOUSE' and event.shift and event.value=='PRESS': 77 | 78 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(True, False, False), constraint_orientation='GLOBAL') #編集 79 | 80 | elif event.type == 'WHEELUPMOUSE' and event.alt and event.value=='PRESS': 81 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 82 | elif event.type == 'WHEELDOWNMOUSE' and event.alt and event.value=='PRESS': 83 | 84 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 85 | 86 | elif event.type == 'WHEELUPMOUSE' and event.alt and event.value=='PRESS': 87 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 88 | elif event.type == 'WHEELDOWNMOUSE' and event.alt and event.value=='PRESS': 89 | 90 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 91 | 92 | 93 | elif event.type == 'WHEELUPMOUSE' and event.oskey and event.value=='PRESS': 94 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(False, False, True), constraint_orientation='GLOBAL') #編集 95 | elif event.type == 'WHEELDOWNMOUSE' and event.oskey and event.value=='PRESS': 96 | 97 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(False, False, True), constraint_orientation='GLOBAL') #編集 98 | 99 | 100 | 101 | 102 | elif event.type == 'WHEELUPMOUSE': 103 | 104 | bpy.ops.transform.rotate(value=0.785398, constraint_orientation='GLOBAL') #編集 105 | elif event.type == 'WHEELDOWNMOUSE': 106 | 107 | bpy.ops.transform.rotate(value=-0.785398, constraint_orientation='GLOBAL') #編集 108 | 109 | 110 | elif event.type == 'NUMPAD_PLUS' and event.value=='PRESS': 111 | bpy.ops.transform.rotate(value=-0.785398, constraint_orientation='GLOBAL') #編集 112 | 113 | elif event.type == 'NUMPAD_MINUS' and event.value=='PRESS': 114 | bpy.ops.transform.rotate(value=-0.785398, constraint_orientation='GLOBAL') #編集 115 | 116 | 117 | 118 | elif event.type == 'X' and event.shift and event.value=='PRESS': 119 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(True, False, False), constraint_orientation='GLOBAL') #編集 120 | elif event.type == 'X' and event.value=='PRESS': 121 | 122 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(True, False, False), constraint_orientation='GLOBAL') #編集 123 | 124 | elif event.type == 'Y' and event.shift and event.value=='PRESS': 125 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 126 | elif event.type == 'Y' and event.value=='PRESS': 127 | 128 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 129 | 130 | elif event.type == 'C' and event.shift and event.value=='PRESS': 131 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 132 | elif event.type == 'C' and event.value=='PRESS': 133 | 134 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(False, True, False), constraint_orientation='GLOBAL') #編集 135 | 136 | elif event.type == 'Z' and event.shift and event.value=='PRESS': 137 | bpy.ops.transform.rotate(value=-0.785398,constraint_axis=(False, False, True), constraint_orientation='GLOBAL') #編集 138 | elif event.type == 'Z' and event.value=='PRESS': 139 | 140 | bpy.ops.transform.rotate(value=0.785398,constraint_axis=(False, False, True), constraint_orientation='GLOBAL') #編集 141 | 142 | 143 | 144 | 145 | 146 | 147 | elif event.type == 'LEFTMOUSE': 148 | context.area.header_text_set() 149 | return {'FINISHED'} 150 | 151 | elif event.type == 'LEFTMOUSE': 152 | context.area.header_text_set() 153 | return {'FINISHED'} 154 | 155 | 156 | elif event.type in {'RIGHTMOUSE', 'ESC'}: 157 | context.area.header_text_set() 158 | # return {'CANCELLED'} 159 | return {'FINISHED'} 160 | 161 | 162 | # # # # # # # # 163 | ################################################################ 164 | 165 | ################################################################ 166 | 167 | 168 | return {'RUNNING_MODAL'} 169 | 170 | def invoke(self, context, event): 171 | if context.object: 172 | 173 | 174 | self.first_mouse_x = event.mouse_x 175 | self.first_value = context.object.location.x 176 | args = (self, context) 177 | 178 | 179 | 180 | cArrID=-1 181 | n=-1 182 | nrf=False 183 | 184 | 185 | 186 | 187 | args = (self, context) 188 | 189 | self.id=int(cArrID) 190 | context.window_manager.modal_handler_add(self) 191 | return {'RUNNING_MODAL'} 192 | else: 193 | self.report({'WARNING'}, "No active object, could not finish") 194 | return {'CANCELLED'} 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | addon_keymaps = [] 203 | 204 | def register(): 205 | bpy.utils.register_module(__name__) 206 | 207 | #addon_keymaps = [] #put on out of register() 208 | wm = bpy.context.window_manager 209 | km = wm.keyconfigs.addon.keymaps.new('3D View', space_type='VIEW_3D', region_type='WINDOW', modal=False) 210 | 211 | # kmi = km.keymap_items.new(rotate_gesture.bl_idname, 'D', 'PRESS', shift=True, ctrl=True) 212 | kmi = km.keymap_items.new(rotate_gesture.bl_idname, 'D', 'PRESS', oskey=True) 213 | addon_keymaps.append((km, kmi)) 214 | kmi = km.keymap_items.new(rotate_gesture.bl_idname, 'D', 'PRESS', shift=True, ctrl=True) 215 | addon_keymaps.append((km, kmi)) 216 | 217 | def unregister(): 218 | bpy.utils.unregister_module(__name__) 219 | # handle the keymap 220 | for km, kmi in addon_keymaps: 221 | km.keymap_items.remove(kmi) 222 | addon_keymaps.clear() 223 | -------------------------------------------------------------------------------- /Asset_Flinger_Thumbnail.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Asset Flinger Thumbnail", 3 | "author": "bookyakuno", 4 | "version": (1, 1), 5 | "blender": (2, 76, 0), 6 | "location": "『 object.asset_flinger_thumbnail 』", 7 | "description": "create thumbnail for Asset Flinger addon ", 8 | "warning": "", 9 | "category": "Mesh"} 10 | 11 | # 参考 12 | # Auto Save Render 13 | # game engine - How to take pictures from the GE? - Blender Stack Exchange 14 | #http://blender.stackexchange.com/questions/27253/how-to-take-pictures-from-the-ge 15 | 16 | 17 | 18 | import bpy 19 | from bpy.props import BoolProperty, EnumProperty 20 | from bpy.app.handlers import persistent 21 | from os.path import dirname, exists, join 22 | from bpy.path import basename 23 | from os import mkdir, listdir 24 | from re import findall 25 | 26 | 27 | import subprocess, os, bpy 28 | from bpy.types import Operator, AddonPreferences, Panel 29 | from bpy.props import StringProperty, IntProperty, BoolProperty, EnumProperty 30 | from sys import platform as _platform 31 | import bpy.utils.previews 32 | 33 | 34 | 35 | class ExampleAddonPreferences(AddonPreferences): 36 | bl_idname = __name__ 37 | 38 | filepath_x = StringProperty( 39 | name="Your Library", 40 | subtype='FILE_PATH', 41 | ) 42 | 43 | def draw(self, context): 44 | layout = self.layout 45 | # layout.label(text="This is a preferences view for our addon") 46 | layout.prop(self, "filepath_x") 47 | 48 | 49 | 50 | class OBJECT_OT_addon_prefs_example(Operator): 51 | """Display example preferences""" 52 | bl_idname = "object.addon_prefs_example" 53 | bl_label = "Addon Preferences Example" 54 | bl_options = {'REGISTER', 'UNDO'} 55 | 56 | def execute(self, context): 57 | user_preferences = context.user_preferences 58 | addon_prefs = user_preferences.addons[__name__].preferences 59 | 60 | info = ("Path: %s, Number: %d, Boolean %r" % 61 | (addon_prefs.filepath, addon_prefs.number, addon_prefs.boolean)) 62 | 63 | self.report({'INFO'}, info) 64 | print(info) 65 | 66 | return {'FINISHED'} 67 | 68 | 69 | # Registration 70 | def register(): 71 | bpy.utils.register_class(OBJECT_OT_addon_prefs_example) 72 | bpy.utils.register_class(ExampleAddonPreferences) 73 | 74 | 75 | def unregister(): 76 | bpy.utils.unregister_class(OBJECT_OT_addon_prefs_example) 77 | bpy.utils.unregister_class(ExampleAddonPreferences) 78 | 79 | 80 | 81 | 82 | # =============================================================== 83 | 84 | # =============================================================== 85 | 86 | 87 | # =============================================================== 88 | 89 | # =============================================================== 90 | 91 | 92 | 93 | 94 | def main(context): 95 | for ob in context.scene.objects: 96 | print(ob) 97 | 98 | 99 | class save_thumbnail(bpy.types.Operator): 100 | """Tooltip""" 101 | bl_idname = "object.save_thumbnail" 102 | bl_label = "save thumbnail" 103 | 104 | @classmethod 105 | def poll(cls, context): 106 | return context.active_object is not None 107 | 108 | def execute(self, context): 109 | main(context) 110 | 111 | 112 | 113 | 114 | 115 | # # # # # # # # 116 | ################################################################ 117 | 118 | ################################################################ 119 | old_path = bpy.context.scene.render.filepath 120 | old_fileformat = bpy.context.scene.render.image_settings.file_format 121 | old_extension = bpy.context.scene.render.use_file_extension 122 | old_x = bpy.context.scene.render.resolution_x 123 | old_y = bpy.context.scene.render.resolution_y 124 | old_percentage = bpy.context.scene.render.resolution_percentage 125 | old_aspect_x = bpy.context.scene.render.pixel_aspect_x 126 | old_aspect_y = bpy.context.scene.render.pixel_aspect_y 127 | 128 | 129 | # # # # # # # # 130 | ################################################################ 131 | 132 | ################################################################ 133 | # path to the folder 134 | file_path = bpy.data.filepath 135 | file_name = bpy.path.display_name_from_filepath(file_path) 136 | file_ext = '.blend' 137 | file_dir = file_path.replace(file_name+file_ext, '') 138 | 139 | mainScreen = bpy.context.screen 140 | 141 | #current scene 142 | scene = mainScreen.scene 143 | #set render settings 144 | scene.render.resolution_x = 128 145 | scene.render.resolution_y = 128 146 | scene.render.resolution_percentage = 100 147 | 148 | 149 | 150 | #render from view (set view_context = False for the camera render) 151 | bpy.ops.render.opengl(view_context = True) 152 | 153 | 154 | 155 | 156 | 157 | # # # # # # # # 158 | ################################################################ 159 | 160 | ################################################################ 161 | rndr = scene.render 162 | original_format = rndr.image_settings.file_format 163 | 164 | format = rndr.image_settings.file_format = scene.auto_save_format 165 | if format == 'OPEN_EXR_MULTILAYER': extension = '.exr' 166 | if format == 'JPEG': extension = '.jpg' 167 | if format == 'PNG': extension = '.png' 168 | blendname = basename(bpy.data.filepath).rpartition('.')[0] 169 | 170 | 171 | # self.filepath_z = str(addon_prefs.filepath_x) # Set path for instant meshes 172 | # 173 | # if self.filepath_z == "": 174 | # print("Path to 'instant Meshes' not specified. Terminating...") 175 | # return {'CANCELLED'} 176 | 177 | # else: 178 | # filepath = dirname(bpy.data.filepath) + str(addon_prefs.filepath) #'/auto_saves' 179 | # filepath = os.path.basename(context.user_preferences.addons["save_thumbnail"].preferences.filepath_x) 180 | 181 | addon_preferences = bpy.context.user_preferences.addons[__name__].preferences 182 | filepath = dirname(bpy.data.filepath) + addon_preferences.filepath_x 183 | 184 | 185 | 186 | 187 | 188 | # user_preferences = context.user_preferences 189 | # addon_prefs = user_preferences.addons[__name__].preferences 190 | # 191 | # self.filepath_x = str(addon_prefs.filepath_x) # Set path for instant meshes 192 | # 193 | # info = ("Path: %s" % (addon_prefs.filepath_x)) 194 | # 195 | # if self.filepath_x == "": 196 | # print("Path to 'instant Meshes' not specified. Terminating...") 197 | # return {'CANCELLED'} 198 | 199 | 200 | 201 | 202 | 203 | if not exists(filepath): 204 | mkdir(filepath) 205 | 206 | if scene.auto_save_subfolders: 207 | filepath = join(filepath, blendname) 208 | if not exists(filepath): 209 | mkdir(filepath) 210 | 211 | 212 | # # # # # # # # 213 | ################################################################ 214 | 215 | ################################################################ 216 | 217 | 218 | #imagefiles starting with the blendname 219 | files = [f for f in listdir(filepath) \ 220 | if f.startswith(blendname) \ 221 | and f.lower().endswith(('.png', '.jpg', '.jpeg', '.exr'))] 222 | 223 | highest = 0 224 | if files: 225 | for f in files: 226 | #find last numbers in the filename after the blendname 227 | suffix = findall('\d+', f.split(blendname)[-1]) 228 | if suffix: 229 | if int(suffix[-1]) > highest: 230 | highest = int(suffix[-1]) 231 | 232 | 233 | ############################################################### 234 | 235 | ################################################################ 236 | # # # # # # # # 237 | 238 | 239 | active_object = bpy.context.active_object 240 | name = active_object.name 241 | 242 | #save and load the render (you can't keep the render result) 243 | #save_name = name + ".png" 244 | # save_name = join(filepath, blendname) + '_' + str(highest+1).zfill(3) + extension 245 | #save_name = scene.name+".png" 246 | 247 | #改良前 save_name = join(filepath, blendname) + name + ".png" 248 | # save_name = join(filepath) + name + ".png" 249 | save_name = join(filepath) + name + ".png" 250 | 251 | 252 | image = bpy.data.images['Render Result'] 253 | if not image: 254 | print('Auto Save: Render Result not found. Image not saved') 255 | return 256 | 257 | print('Auto_Save:', save_name) 258 | image.save_render(save_name, scene=None) 259 | 260 | rndr.image_settings.file_format = original_format 261 | 262 | 263 | 264 | # # # # # # # # 265 | ################################################################ 266 | 267 | 268 | 269 | # restore old settings 270 | bpy.context.scene.render.filepath = old_path 271 | bpy.context.scene.render.image_settings.file_format = old_fileformat 272 | bpy.context.scene.render.use_file_extension = old_extension 273 | bpy.context.scene.render.resolution_x = old_x 274 | bpy.context.scene.render.resolution_y = old_y 275 | bpy.context.scene.render.resolution_percentage = old_percentage 276 | bpy.context.scene.render.pixel_aspect_x = old_aspect_x 277 | bpy.context.scene.render.pixel_aspect_y = old_aspect_y 278 | 279 | 280 | ################################################################ 281 | # # # # # # # # 282 | 283 | 284 | 285 | return {'FINISHED'} 286 | 287 | 288 | 289 | # # # # # # # # 290 | ################################################################ 291 | 292 | ################################################################ 293 | # # # # # # # # 294 | 295 | 296 | 297 | class asset_flinger_thumbnail(bpy.types.Operator): 298 | """Tooltip""" 299 | bl_idname = "object.asset_flinger_thumbnail" 300 | bl_label = "asset_flinger_thumbnail" 301 | 302 | @classmethod 303 | def poll(cls, context): 304 | return context.active_object is not None 305 | 306 | def execute(self, context): 307 | main(context) 308 | 309 | # old_shadingvariable = bpy.context.scene.object.shadingvariable 310 | #ソリッド表示にします 311 | bpy.ops.object.shadingvariable(variable="SOLID") 312 | 313 | #matcapを赤いものに設定 好きに設定して下さい 314 | bpy.context.space_data.matcap_icon = '12' 315 | 316 | #レンダリングするもののみ表示 これを消すとアウトライン付きになります 317 | bpy.context.space_data.show_only_render = True 318 | 319 | #平行投影/透視投影 平行投影にする 320 | bpy.ops.view3d.view_persportho() 321 | 322 | #サムネイル作成を実行する 323 | bpy.ops.object.save_thumbnail() 324 | 325 | 326 | #平行投影/透視投影 透視投影に戻す 327 | bpy.ops.view3d.view_persportho() 328 | 329 | #レンダリングするもののみ表示 表示を戻す 330 | bpy.context.space_data.show_only_render = False 331 | 332 | #instantmesher 333 | #bpy.ops.instantmesher 334 | #matcapを設定 よく使う元のmatcapに戻す 335 | bpy.context.space_data.matcap_icon = '06' 336 | 337 | 338 | #xx bpy.context.scene.object.shadingvariable = old_shadingvariable 339 | 340 | 341 | 342 | 343 | 344 | return {'FINISHED'} 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | # store keymaps here to access after registration 353 | addon_keymaps = [] 354 | 355 | def register(): 356 | bpy.utils.register_module(__name__) 357 | # handle the keymap 358 | #addon_keymaps = [] #put on out of register() 359 | wm = bpy.context.window_manager 360 | km = wm.keyconfigs.addon.keymaps.new(name = '3D View', space_type = 'VIEW_3D') 361 | 362 | kmi = km.keymap_items.new(asset_flinger_thumbnail.bl_idname, 'D', 'PRESS', shift=True, ctrl=True, oskey=True) 363 | addon_keymaps.append((km, kmi)) 364 | 365 | def unregister(): 366 | bpy.utils.unregister_module(__name__) 367 | # handle the keymap 368 | for km, kmi in addon_keymaps: 369 | km.keymap_items.remove(kmi) 370 | addon_keymaps.clear() 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | # 382 | # 383 | # 384 | # 385 | # 386 | # def register(): 387 | # bpy.utils.register_class(save_thumbnail) 388 | # bpy.utils.register_class(asset_flinger_thumbnail) 389 | # bpy.utils.register_class(InstantMesherPreferences) 390 | # 391 | # 392 | # def unregister(): 393 | # bpy.utils.unregister_class(save_thumbnail) 394 | # bpy.utils.unregister_class(asset_flinger_thumbnail) 395 | # bpy.utils.unregister_class(InstantMesherPreferences) 396 | # 397 | # 398 | # if __name__ == "__main__": 399 | # register() 400 | # 401 | # # test call 402 | # bpy.ops.object.save_thumbnail() 403 | 404 | -------------------------------------------------------------------------------- /BlenderDeformTools.py: -------------------------------------------------------------------------------- 1 | # BlenderDeformTools/BlenderDeformTools.py at master · snowlt23/BlenderDeformTools · GitHub 2 | # https://github.com/snowlt23/BlenderDeformTools/blob/master/BlenderDeformTools.py 3 | 4 | 5 | import bpy 6 | import bmesh 7 | 8 | bl_info = { 9 | "name": "BlenderDeformTools bk.edit", 10 | "author": "shsnow23,bookyakuno", 11 | "version": (0, 2), 12 | "blender": (2, 7, 6), 13 | "location": "", 14 | "description": "", 15 | "warning": "", 16 | "wiki_url": "", 17 | "tracker_url": "", 18 | "category": "Sculpt" 19 | } 20 | 21 | 22 | 23 | 24 | class MaskToVertexGroup_x(bpy.types.Operator): 25 | '''Mask To Vertex Group''' 26 | bl_idname = "mesh.masktovgroup_x" 27 | bl_label = "Mask To Vertex Group_x" 28 | bl_options = {'REGISTER'} 29 | 30 | @classmethod 31 | 32 | def poll(cls, context): 33 | 34 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 35 | 36 | def execute(self, context): 37 | 38 | dynatopoEnabled = False 39 | 40 | if context.active_object.mode == 'SCULPT' : 41 | 42 | if context.sculpt_object.use_dynamic_topology_sculpting : 43 | 44 | dynatopoEnabled = True 45 | 46 | bpy.ops.sculpt.dynamic_topology_toggle() 47 | 48 | #print(context.active_object.use_dynamic_topology_sculpting) 49 | 50 | bmeshContainer = bmesh.new() # New bmesh container 51 | 52 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 53 | 54 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 55 | 56 | newVertexGroup = context.sculpt_object.vertex_groups.new(name = "Mask") # Create an empty vgroup 57 | 58 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 59 | 60 | for x in bmeshContainer.verts: # itterate from bmesh.verts 61 | 62 | if x[mask] > 0 : # if x BMVert has mask weight 63 | 64 | maskWeight = x[mask] # assign float variable for weight from mask layer 65 | 66 | newVertexGroup.add([x.index], maskWeight, "REPLACE") # add it to vgroup, set mask weight 67 | else : 68 | 69 | newVertexGroup.add([x.index], 0, "REPLACE") 70 | 71 | bmeshContainer.free() 72 | 73 | if dynatopoEnabled : 74 | 75 | bpy.ops.sculpt.dynamic_topology_toggle() 76 | 77 | #print("Mask Converted to Vertex Group") 78 | bpy.ops.object.mode_set(mode='EDIT') 79 | 80 | 81 | return {'FINISHED'} 82 | 83 | 84 | 85 | 86 | def mask_to_vertex_group(): 87 | bpy.ops.object.mode_set(mode='SCULPT') 88 | bpy.ops.paint.hide_show(action='HIDE', area='MASKED') 89 | bpy.ops.object.mode_set(mode='EDIT') 90 | bpy.ops.mesh.reveal() 91 | bpy.ops.object.vertex_group_assign_new() 92 | 93 | class MaskToVGOperator(bpy.types.Operator): 94 | bl_idname = "wm.mask_to_vg_operator" 95 | bl_label = "MaskToVertexGroup" 96 | 97 | def execute(self, context): 98 | mask_to_vertex_group() 99 | return {'FINISHED'} 100 | 101 | class DeformOperator(bpy.types.Operator): 102 | bl_idname = "wm.deform_operator" 103 | bl_label = "DeformOperator" 104 | 105 | def execute(self, context): 106 | mask_to_vertex_group() 107 | bpy.ops.object.vertex_group_select() 108 | saved_location = bpy.context.scene.cursor_location.copy() 109 | bpy.ops.view3d.snap_cursor_to_selected() 110 | bpy.ops.object.mode_set(mode='SCULPT') 111 | bpy.ops.mesh.masktovgroup_x() 112 | bpy.ops.object.mode_set(mode='EDIT') 113 | 114 | 115 | bm = bmesh.from_edit_mesh(bpy.context.active_object.data) 116 | selected_verts = [i.co for i in bm.verts if i.select] 117 | 118 | top = None 119 | bottom = None 120 | left = None 121 | right = None 122 | front = None 123 | back = None 124 | for v in selected_verts: 125 | if top == None: 126 | top = v[2] 127 | elif top < v[2]: 128 | top = v[2] 129 | 130 | if bottom == None: 131 | bottom = v[2] 132 | elif bottom > v[2]: 133 | bottom = v[2] 134 | 135 | if left == None: 136 | left = v[1] 137 | elif left > v[1]: 138 | left = v[1] 139 | 140 | if right == None: 141 | right = v[1] 142 | elif right < v[1]: 143 | right = v[1] 144 | 145 | if front == None: 146 | front = v[0] 147 | elif front < v[0]: 148 | front = v[0] 149 | 150 | if back == None: 151 | back = v[0] 152 | elif back > v[0]: 153 | back = v[0] 154 | 155 | bpy.ops.mesh.select_all(action='DESELECT') 156 | 157 | lattice = bpy.data.lattices.new("Lattice") 158 | lattice_ob = bpy.data.objects.new("Lattice", lattice) 159 | 160 | x_scale = (front - back) / (lattice.points[5].co[0] - lattice.points[4].co[0]) 161 | y_scale = (right - left) / (lattice.points[7].co[1] - lattice.points[5].co[1]) 162 | z_scale = (top - bottom) / (lattice.points[5].co[2] - lattice.points[1].co[2]) 163 | 164 | lattice_ob.scale = (x_scale, y_scale, z_scale) 165 | lattice_ob.location = ((front+back) / 2, (right+left) / 2, (top+bottom) / 2) 166 | 167 | scene = bpy.context.scene 168 | 169 | lattice_mod = scene.objects.active.modifiers.new("Lattice", 'LATTICE') 170 | lattice_mod.object = lattice_ob 171 | lattice_mod.vertex_group = bpy.context.object.vertex_groups.active.name 172 | 173 | scene.objects.link(lattice_ob) 174 | scene.update() 175 | 176 | for o in bpy.context.scene.objects: 177 | o.select = False 178 | lattice_ob.select = True 179 | bpy.context.scene.objects.active = lattice_ob 180 | bpy.ops.object.mode_set(mode='OBJECT') 181 | bpy.ops.object.editmode_toggle() 182 | bpy.ops.view3d.snap_selected_to_cursor(use_offset=False) 183 | bpy.ops.object.mode_set(mode='EDIT') 184 | bpy.ops.lattice.select_all(action='SELECT') 185 | bpy.context.scene.cursor_location = saved_location 186 | 187 | 188 | return {'FINISHED'} 189 | 190 | class DeformTools(bpy.types.Panel): 191 | bl_idname = "OBJECT_PT_deform_tools" 192 | bl_label = "DeformTools" 193 | bl_category = "Sculpt" 194 | bl_space_type = "VIEW_3D" 195 | bl_region_type = "TOOLS" 196 | 197 | def draw(self, context): 198 | layout = self.layout 199 | row_mask = layout.row() 200 | row_mask.operator("wm.mask_to_vg_operator", text="Mask to VertexGroup") 201 | row_deform = layout.row() 202 | row_deform.operator("wm.deform_operator", text="Create DeformBox") 203 | 204 | def register(): 205 | bpy.utils.register_class(MaskToVertexGroup_x) 206 | bpy.utils.register_class(MaskToVGOperator) 207 | bpy.utils.register_class(DeformOperator) 208 | bpy.utils.register_class(DeformTools) 209 | 210 | def unregister(): 211 | bpy.utils.unregister_class(MaskToVertexGroup_x) 212 | bpy.utils.unregister_class(MaskToVGOperator) 213 | bpy.utils.unregister_class(DeformOperator) 214 | bpy.utils.unregister_class(DeformTools) 215 | 216 | if __name__ == "__main__": 217 | register() 218 | -------------------------------------------------------------------------------- /Compact_Properties.py: -------------------------------------------------------------------------------- 1 | # 3D Navigation_x TOOLBAR v1.2 - 3Dview Addon - Blender 2.5x 2 | # 3 | # THIS SCRIPT IS LICENSED UNDER GPL, 4 | # please read the license block. 5 | # 6 | # ##### BEGIN GPL LICENSE BLOCK ##### 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # as published by the Free Software Foundation; either version 2 11 | # of the License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software Foundation, 20 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 | # 22 | # ##### END GPL LICENSE BLOCK ##### 23 | 24 | bl_info = { 25 | "name": "Compact Properties", 26 | "author": "bookyakuno", 27 | "version": (1,2), 28 | "blender": (2, 77), 29 | "location": "Cmd + Ctrl + 3, Shift + Ctrl + 3", 30 | "description": "Simple Panel", 31 | "warning": "", 32 | "wiki_url": "", 33 | "tracker_url": "", 34 | "category": "3D View"} 35 | import bpy 36 | ################################################################ 37 | from bl_ui.properties_data_modifier import DATA_PT_modifiers 38 | # 39 | # 40 | # import bpy 41 | # from bpy.types import Menu 42 | # 43 | # import os 44 | # from bpy.types import ( 45 | # Panel, 46 | # Menu, 47 | # Operator, 48 | # UIList, 49 | # ) 50 | # from rna_prop_ui import PropertyPanel 51 | # from bl_ui.properties_data_modifier import DATA_PT_modifiers 52 | # from bpy.props import * 53 | ################################################################ 54 | class compact_prop(bpy.types.Operator): 55 | bl_idname = "object.compact_prop" 56 | bl_label = "Compact Properties" 57 | def execute(self, context): 58 | return {'FINISHED'} 59 | def invoke(self, context, event): 60 | dpi_value = bpy.context.user_preferences.system.dpi 61 | return context.window_manager.invoke_props_dialog(self, width=dpi_value*6, height=300) 62 | def draw(self, context): 63 | mp = DATA_PT_modifiers(context) 64 | ob = context.object 65 | layout = self.layout 66 | row = layout.row() 67 | # if context.active_object is None: 68 | # row.alignment = 'CENTER' 69 | # row.label("No Object!", icon = 'INFO') 70 | # return 71 | ################################################################ 72 | col = layout.column(align=True) 73 | # col.label(text="Hello World!!") 74 | view = context.space_data 75 | scene = context.scene 76 | obj = context.object 77 | obj_type = obj.type 78 | ################################################################ 79 | ################################################################ 80 | ### Amaranth Toolset のフレームオンシェード(displayWireframe) 81 | row = col.row(align=True) 82 | row.operator("object.amth_wire_toggle" , 83 | icon="MOD_WIREFRAME", text="Wire").clear = False 84 | row.operator("object.amth_wire_toggle" , 85 | icon="X", text="Clear").clear = True 86 | row = col.row(align=True) 87 | row.operator("mesh.presel", text="PreSel" ,icon="LOOPSEL") 88 | row.operator("presel.stop", text="PreSel" ,icon="X") 89 | ################################################################ 90 | ################################################################ 91 | ### その他いろいろ 92 | col = layout.column(align=True) 93 | layout.separator() 94 | 95 | row = layout.row() 96 | ### 透視/並行投影 97 | row.operator("view3d.view_persportho", icon="OUTLINER_OB_CAMERA", text="") 98 | ### ワールドの背景 99 | row.prop(view, "show_world", text="World.",icon="WORLD") 100 | ### レンズ 101 | view = context.space_data 102 | row.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews) 103 | row.prop(view, "lens",icon="SCENE") 104 | ### 描画タイプ 105 | obj = context.object 106 | row = layout.row() 107 | row.prop(obj, "draw_type", text="",icon="TEXTURE_SHADED") 108 | # col.prop(view, "show_only_render") 109 | row = layout.row() 110 | ### X-Ray 111 | row.prop(obj, "show_x_ray", text="X-Ray.",icon="VISIBLE_IPO_ON") 112 | ### バックフェースカーリング 113 | row.prop(view, "show_backface_culling", text="B.cul",icon="FACESEL") 114 | ### ワイヤーフレーム表示 115 | row.prop(obj, "show_wire", text="Wire.",icon="OUTLINER_OB_LATTICE") 116 | ### AO 117 | rd = scene.render 118 | ### AO 119 | col = layout.column(align=True) 120 | fx_settings = view.fx_settings 121 | # if fx_settings.use_ssao: 122 | # ssao_settings = fx_settings.ssao 123 | # subcol = col.column(align=True) 124 | # subcol.prop(ssao_settings, "factor") 125 | # subcol.prop(ssao_settings, "distance_max") 126 | # subcol.prop(ssao_settings, "attenuation") 127 | # subcol.prop(ssao_settings, "samples") 128 | # subcol.prop(ssao_settings, "color") 129 | # 130 | # if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: 131 | row = col.row(align=True) 132 | row.prop(fx_settings, "use_ssao", text="AO",icon="PINNED") 133 | ### Matcap 134 | row.prop(view, "use_matcap",icon="COLOR_RED") 135 | ### 被写界深度 136 | row = col.row(align=True) 137 | if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: 138 | row.active = view.region_3d.view_perspective == 'CAMERA' 139 | row.prop(fx_settings, "use_dof", text="dof",icon="FORCE_HARMONIC") 140 | ### Matcap アイコン 141 | if view.use_matcap: 142 | row = col.row(align=True) 143 | row.template_icon_view(view, "matcap_icon") 144 | ################################################################ 145 | 146 | ################################################################ 147 | 148 | addon_keymaps = [] 149 | def register(): 150 | bpy.utils.register_module(__name__) 151 | wm = bpy.context.window_manager 152 | km = wm.keyconfigs.addon.keymaps.new(name = '3D View', space_type = 'VIEW_3D') 153 | 154 | # compact_prop 155 | kmi = km.keymap_items.new(compact_prop.bl_idname, 'THREE', 'PRESS', shift=True, ctrl=True) 156 | kmi = km.keymap_items.new(compact_prop.bl_idname, 'THREE', 'PRESS', oskey=True, ctrl=True) 157 | addon_keymaps.append((km, kmi)) 158 | 159 | def unregister(): 160 | bpy.utils.unregister_module(__name__) 161 | # handle the keymap 162 | for km, kmi in addon_keymaps: 163 | km.keymap_items.remove(kmi) 164 | addon_keymaps.clear() 165 | 166 | 167 | ################################################################ 168 | ################################################################ 169 | # 170 | # def register(): 171 | # bpy.utils.register_module(__name__) 172 | # def unregister(): 173 | # bpy.utils.unregister_module(__name__) 174 | # if __name__ == "__main__": 175 | # register() 176 | -------------------------------------------------------------------------------- /Material_list.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "material List", 3 | 'description': '"material List from Hard Ops addon."', 4 | 'author': 'bookyakuno', 5 | 'version': (1,1), 6 | 'blender': (2, 76, 0), 7 | 'warning': "", 8 | 'location': 'View3D > Ctrl + Shift + F', 9 | 'category': 'Material' 10 | } 11 | 12 | 13 | import bpy 14 | import bmesh 15 | # import os 16 | # from bpy.types import Panel 17 | # 18 | # from bpy.props import IntProperty, FloatProperty, BoolProperty, StringProperty, EnumProperty, PointerProperty 19 | from bpy.props import ( 20 | StringProperty, 21 | BoolProperty, 22 | EnumProperty, 23 | PointerProperty, 24 | ) 25 | 26 | from bpy.props import * 27 | from bpy.types import Menu, Operator, Panel, UIList 28 | from bpy.app.handlers import persistent 29 | 30 | 31 | 32 | set_material_name_z = StringProperty( 33 | name="New Material name", 34 | description="What Base name pattern to use for a new created Material\n" 35 | "It is appended by an automatic numeric pattern depending\n" 36 | "on the number of Scene's materials containing the Base", 37 | default="Material_New", 38 | maxlen=128, 39 | ) 40 | 41 | 42 | 43 | 44 | 45 | 46 | def c_need_of_viewport_colors(): 47 | # check the context where using Viewport color and friends are needed 48 | # Cycles and BI are supported 49 | if c_render_engine("Cycles"): 50 | if c_context_use_nodes() and c_context_mat_preview() == 'SOLID': 51 | return True 52 | elif c_context_mat_preview() in ('SOLID', 'TEXTURED', 'MATERIAL'): 53 | return True 54 | elif (c_render_engine("BI") and not c_context_use_nodes()): 55 | return True 56 | 57 | return False 58 | 59 | 60 | 61 | 62 | 63 | class VIEW3D_MT_select_material_xx(bpy.types.Menu): 64 | bl_label = "Select by Material" 65 | bl_options = {"REGISTER","UNDO"} 66 | 67 | def draw(self, context): 68 | layout = self.layout 69 | layout.operator_context = 'INVOKE_REGION_WIN' 70 | 71 | ob = context.object 72 | layout.label 73 | if ob.mode == 'OBJECT': 74 | bpy.ops.object.select_all(action='DESELECT') #編集 75 | #show all used materials in entire blend file 76 | for material_name, material in bpy.data.materials.items(): 77 | if material.users > 0: 78 | layout.operator("view3d.select_material_by_name", 79 | text=material_name, 80 | icon='MATERIAL_DATA', 81 | ).matname = material_name 82 | 83 | elif ob.mode == 'EDIT': 84 | bpy.ops.mesh.select_all(action='DESELECT')#編集 85 | #show only the materials on this object 86 | mats = ob.material_slots.keys() 87 | for m in mats: 88 | layout.operator("view3d.select_material_by_name", 89 | text=m, 90 | icon='MATERIAL_DATA').matname = m 91 | 92 | 93 | 94 | 95 | 96 | #Apply Material 97 | class ApplyMaterial(bpy.types.Operator): 98 | bl_idname = "object.apply_material_z" 99 | bl_label = "Apply material" 100 | bl_options = {"REGISTER","UNDO"} 101 | 102 | mat_to_assign = bpy.props.StringProperty(default="") 103 | 104 | def execute(self, context): 105 | 106 | if context.object.mode == 'EDIT': 107 | obj = context.object 108 | bm = bmesh.from_edit_mesh(obj.data) 109 | 110 | 111 | selected_face = [f for f in bm.faces if f.select] # si des faces sont sélectionnées, elles sont stockées dans la liste "selected_faces" 112 | 113 | mat_name = [mat.name for mat in bpy.context.object.material_slots if len(bpy.context.object.material_slots)] # pour tout les material_slots, on stock les noms des mat de chaque slots dans la liste "mat_name" 114 | 115 | 116 | if self.mat_to_assign in mat_name: # on test si le nom du mat sélectionné dans le menu est présent dans la liste "mat_name" (donc, si un des slots possède le materiau du même nom). Si oui: 117 | context.object.active_material_index = mat_name.index(self.mat_to_assign) # on definit le slot portant le nom du comme comme étant le slot actif 118 | bpy.ops.object.material_slot_assign() # on assigne le matériau à la sélection 119 | else: # sinon 120 | bpy.ops.object.material_slot_add() # on ajout un slot 121 | bpy.context.object.active_material = bpy.data.materials[self.mat_to_assign] # on lui assigne le materiau choisi 122 | bpy.ops.object.material_slot_assign() # on assigne le matériau à la sélection 123 | 124 | return {'FINISHED'} 125 | 126 | elif context.object.mode == 'OBJECT': 127 | 128 | obj_list = [obj.name for obj in context.selected_objects] 129 | 130 | for obj in obj_list: 131 | bpy.ops.object.select_all(action='DESELECT') 132 | bpy.data.objects[obj].select = True 133 | bpy.context.scene.objects.active = bpy.data.objects[obj] 134 | bpy.context.object.active_material_index = 0 135 | 136 | if self.mat_to_assign == bpy.data.materials: 137 | bpy.context.active_object.active_material = bpy.data.materials[mat_name] 138 | 139 | else: 140 | if not len(bpy.context.object.material_slots): 141 | bpy.ops.object.material_slot_add() 142 | 143 | bpy.context.active_object.active_material = bpy.data.materials[self.mat_to_assign] 144 | 145 | for obj in obj_list: 146 | bpy.data.objects[obj].select = True 147 | 148 | return {'FINISHED'} 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | #Apply Material 157 | class new_mat(bpy.types.Operator): 158 | bl_idname = "object.new_mat" 159 | bl_label = "New Material" 160 | bl_options = {"REGISTER","UNDO"} 161 | 162 | def execute(self, context): 163 | 164 | 165 | ob = bpy.context.active_object 166 | 167 | # Get material 168 | # mat = bpy.data.materials.get("_cmnmat_") 169 | # if mat is None: 170 | # create material 171 | mat = bpy.data.materials.new(name="Material") 172 | 173 | # Assign it to object 174 | if ob.data.materials: 175 | # assign to 1st material slot 176 | ob.data.materials[0] = mat 177 | else: 178 | # no slots 179 | ob.data.materials.append(mat) 180 | 181 | if context.scene.render.engine == 'CYCLES': 182 | bpy.context.object.active_material.use_nodes = True 183 | 184 | return {'FINISHED'} 185 | 186 | 187 | # Material 188 | class MaterialListMenu_z(bpy.types.Menu): 189 | bl_idname = "object.material_list_menu_z" 190 | bl_label = "Material_list_xz" 191 | 192 | def draw(self, context): 193 | layout = self.layout 194 | col = layout.column(align=True) 195 | ################################################################ 196 | col.operator("object.new_mat") 197 | col.separator() 198 | 199 | if len(bpy.data.materials): 200 | for mat in bpy.data.materials: 201 | name = mat.name 202 | try: 203 | icon_val = layout.icon(mat) 204 | except: 205 | icon_val = 1 206 | print ("WARNING [Mat Panel]: Could not get icon value for %s" % name) 207 | 208 | op = col.operator("object.apply_material_z", text=name, icon_value=icon_val) 209 | op.mat_to_assign = name 210 | else: 211 | col.label("No data materials") 212 | 213 | col.separator() 214 | 215 | 216 | 217 | ################################################################ 218 | 219 | 220 | 221 | 222 | # 223 | # ===================================================== 224 | # ===================================================== 225 | # ===================================================== 226 | # ===================================================== 227 | # 228 | class ExtraMaterialList_PT_z(Panel): 229 | bl_space_type = "PROPERTIES" 230 | bl_region_type = "WINDOW" 231 | bl_context = "material" 232 | bl_label = "mat List" 233 | def draw(self, context): 234 | layout = self.layout 235 | cs = context.scene 236 | sdata = context.space_data 237 | props = cs.extra_material_list 238 | #--- Object materials 239 | layout.template_list( 240 | "extra_material_list.material_list", "", 241 | bpy.data, "materials", 242 | props, "material_id", 243 | rows = len(bpy.data.materials) 244 | ) 245 | split = layout.split(percentage=0.7) 246 | split.operator("material.del_mat",text="del_active_mat",icon="CANCEL") 247 | split.operator("material.del_0_mat",icon="X") 248 | 249 | 250 | 251 | 252 | # ===================================================== 253 | # ===================================================== 254 | 255 | 256 | class del_mat(Operator): 257 | bl_idname = "material.del_mat" 258 | bl_label = "del mat" 259 | bl_description = "Perfect Delete Material in Project" 260 | bl_options = {"REGISTER","UNDO"} 261 | 262 | def execute(self, context): 263 | for material in bpy.context.active_object.data.materials: 264 | material.user_clear() 265 | bpy.data.materials.remove(material) 266 | 267 | return{'FINISHED'} 268 | 269 | class del_0_mat(Operator): 270 | bl_idname = "material.del_0_mat" 271 | bl_label = "del 0 user mat" 272 | bl_description = "Clean 0 user Material in Project" 273 | bl_options = {"REGISTER","UNDO"} 274 | 275 | def execute(self, context): 276 | for material in bpy.data.materials: 277 | if not material.users: 278 | bpy.data.materials.remove(material) 279 | return {'FINISHED'} 280 | 281 | 282 | 283 | 284 | # 285 | # ===================================================== 286 | # ===================================================== 287 | # 288 | 289 | def register(): 290 | bpy.utils.register_module(__name__) 291 | 292 | wm = bpy.context.window_manager 293 | kc = wm.keyconfigs.addon 294 | if kc: 295 | km = kc.keymaps.new(name='3D View', space_type='VIEW_3D') 296 | kmi = km.keymap_items.new('wm.call_menu', 'F', 'PRESS', ctrl = True) 297 | kmi.properties.name = "object.material_list_menu_z" 298 | 299 | def unregister(): 300 | bpy.utils.unregister_module(__name__) 301 | 302 | wm = bpy.context.window_manager 303 | kc = wm.keyconfigs.addon 304 | if kc: 305 | km = kc.keymaps['3D View'] 306 | for kmi in km.keymap_items: 307 | if kmi.idname == 'wm.call_menu': 308 | if kmi.properties.name == "object.material_list_menu_z": 309 | km.keymap_items.remove(kmi) 310 | break 311 | 312 | if __name__ == "__main__": 313 | register() 314 | -------------------------------------------------------------------------------- /angle_select_click.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | bl_info = { 19 | "name": "Angle select click", 20 | "author": "bookyakuno", 21 | "version": (1,3), 22 | "location": "Property panel > Mesh Display", 23 | "description": "Select face by angle.", 24 | "warning": "", 25 | "category": "Mesh"} 26 | 27 | import bpy 28 | import bmesh 29 | 30 | from bpy.types import Operator, AddonPreferences 31 | 32 | 33 | 34 | # 翻訳辞書 35 | translation_dict = { 36 | "en_US": { 37 | ("*", "Delete Face By Right Click"): 38 | "Delete Face By Right Click", 39 | }, 40 | "ja_JP": { 41 | ("*", "Select face by angle."): 42 | "面を角度によって選択します", 43 | } 44 | } 45 | 46 | 47 | 48 | 49 | 50 | class KeymapSetMenuPrefsz(bpy.types.AddonPreferences): 51 | 52 | bl_idname = __name__ 53 | 54 | bpy.types.Scene.angle_select_click_threshold = bpy.props.FloatProperty(default= 30, min= 0.01, max= 180, description="Angle") 55 | 56 | def draw(self, context): 57 | layout = self.layout 58 | 59 | layout.label( 60 | text="- Keymap -") 61 | layout.label( 62 | text="( if LEFT select mouse, ACTIONMOUSE = RIGHTMOUSE)") 63 | layout.label( 64 | text="Ctrl + ACTIONMOUSE >> Angle select") 65 | layout.label( 66 | text="Ctrl + Shift + ACTIONMOUSE >> Angle select multiple") 67 | layout.label( 68 | text="alt + Y >> Angle select") 69 | layout.label( 70 | text="alt + shift + Y >> Angle select multiple") 71 | 72 | layout.label( 73 | text="") 74 | layout.label( 75 | text="- Link -") 76 | row = layout.row() 77 | 78 | row.operator("wm.url_open", text="Download : github").url = "https://github.com/bookyakuno/-Blender-/blob/master/angle_select_click.py" 79 | row.operator("wm.url_open", text="Donation $3 : gumroad").url = "https://gumroad.com/l/LXbX" 80 | 81 | 82 | 83 | 84 | 85 | 86 | class angle_select_click(bpy.types.Operator): 87 | bl_idname = "object.angle_select_click" 88 | bl_label = "angle_select_click" 89 | bl_options = {'REGISTER', 'UNDO'} 90 | 91 | def execute(self, context): 92 | obj = context.object 93 | bm = bmesh.from_edit_mesh(obj.data) 94 | 95 | 96 | angle_select_click_angle = bpy.context.scene.angle_select_click_threshold/180 97 | 98 | 99 | 100 | # 非表示を頂点グループにバックアップ 101 | bpy.ops.mesh.select_all(action='DESELECT') 102 | bpy.ops.mesh.reveal() 103 | bpy.ops.object.vertex_group_assign_new() 104 | bpy.context.object.vertex_groups.active.name = "hide_vgroups" 105 | 106 | # 角度選択 107 | bpy.ops.view3d.select('INVOKE_DEFAULT') 108 | bpy.ops.mesh.select_similar(type='NORMAL', compare='EQUAL', threshold=angle_select_click_angle) 109 | 110 | # リンクするもののみ選択 111 | bpy.ops.mesh.hide(unselected=True) #選択以外非表示 112 | bpy.ops.mesh.select_all(action='DESELECT') #選択解除 113 | bpy.ops.view3d.select('INVOKE_DEFAULT') #マウス下選択 114 | bpy.ops.mesh.select_linked(delimit={'NORMAL'}) #リンク選択 115 | bpy.ops.object.vertex_group_assign_new() 116 | bpy.context.object.vertex_groups.active.name = "angle_vgroups" 117 | 118 | # bpy.ops.mesh.select_all(action='INVERT') 119 | bpy.ops.mesh.reveal() 120 | bpy.ops.mesh.select_all(action='DESELECT') #選択解除 121 | # bpy.ops.mesh.select_all(action='INVERT') 122 | 123 | bpy.ops.object.vertex_group_set_active(group='hide_vgroups') 124 | bpy.ops.object.vertex_group_select() 125 | 126 | 127 | bpy.ops.object.vertex_group_remove() 128 | bpy.ops.mesh.hide() #選択非表示 129 | 130 | bpy.ops.object.vertex_group_set_active(group='angle_vgroups') 131 | bpy.ops.object.vertex_group_select() 132 | bpy.ops.object.vertex_group_remove() 133 | bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') 134 | bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') 135 | 136 | 137 | 138 | return {'FINISHED'} 139 | 140 | 141 | 142 | class angle_select_click_extend(bpy.types.Operator): 143 | bl_idname = "object.angle_select_click_extend" 144 | bl_label = "angle_select_click_extend" 145 | bl_options = {'REGISTER', 'UNDO'} 146 | 147 | 148 | def execute(self, context): 149 | obj = context.object 150 | bm = bmesh.from_edit_mesh(obj.data) 151 | 152 | 153 | angle_select_click_angle = bpy.context.scene.angle_select_click_threshold/180 154 | 155 | 156 | 157 | # 表示状態を保存 158 | bpy.ops.object.vertex_group_assign_new() 159 | bpy.context.object.vertex_groups.active.name = "old_select_vgroups" 160 | 161 | # 非表示を頂点グループにバックアップ 162 | bpy.ops.mesh.select_all(action='DESELECT') 163 | bpy.ops.mesh.reveal() 164 | bpy.ops.object.vertex_group_assign_new() 165 | bpy.context.object.vertex_groups.active.name = "hide_vgroups" 166 | 167 | # 角度選択 168 | bpy.ops.view3d.select('INVOKE_DEFAULT') 169 | bpy.ops.mesh.select_similar(type='NORMAL', compare='EQUAL', threshold=angle_select_click_angle) 170 | 171 | # リンクするもののみ選択 172 | bpy.ops.mesh.hide(unselected=True) #選択以外非表示 173 | bpy.ops.mesh.select_all(action='DESELECT') #選択解除 174 | bpy.ops.view3d.select('INVOKE_DEFAULT') #マウス下選択 175 | bpy.ops.mesh.select_linked(delimit={'NORMAL'}) #リンク選択 176 | bpy.ops.object.vertex_group_assign_new() 177 | bpy.context.object.vertex_groups.active.name = "angle_vgroups" 178 | 179 | # bpy.ops.mesh.select_all(action='INVERT') 180 | bpy.ops.mesh.reveal() 181 | bpy.ops.mesh.select_all(action='DESELECT') #選択解除 182 | # bpy.ops.mesh.select_all(action='INVERT') 183 | 184 | bpy.ops.object.vertex_group_set_active(group='hide_vgroups') 185 | bpy.ops.object.vertex_group_select() 186 | bpy.ops.object.vertex_group_remove() 187 | # bpy.ops.object.vertex_group_remove() 188 | bpy.ops.mesh.hide() #選択非表示 189 | 190 | bpy.ops.object.vertex_group_set_active(group='angle_vgroups') 191 | bpy.ops.object.vertex_group_select() 192 | bpy.ops.object.vertex_group_remove() 193 | 194 | bpy.ops.object.vertex_group_set_active(group='old_select_vgroups') 195 | bpy.ops.object.vertex_group_select() 196 | bpy.ops.object.vertex_group_remove() 197 | bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') 198 | bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') 199 | 200 | 201 | 202 | 203 | return {'FINISHED'} 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | # 213 | # class angle_select_click_extend(bpy.types.Operator): 214 | # bl_idname = "object.angle_select_click_extend" 215 | # bl_label = "angle_select_click_extend" 216 | # bl_options = {'REGISTER', 'UNDO'} 217 | # 218 | # def execute(self, context): 219 | # obj = context.object 220 | # bm = bmesh.from_edit_mesh(obj.data) 221 | # 222 | # 223 | # angle_select_click_angle = bpy.context.scene.angle_select_click_threshold/180 224 | # # print(angle_select_click_angle) 225 | # 226 | # bpy.ops.object.vertex_group_assign_new() 227 | # bpy.ops.mesh.hide() #選択非表示 228 | # bpy.ops.view3d.select('INVOKE_DEFAULT',extend=True) 229 | # bpy.ops.mesh.select_similar(type='NORMAL', compare='EQUAL', threshold=angle_select_click_angle) 230 | # 231 | # bpy.ops.mesh.hide(unselected=True) #選択以外非表示 232 | # bpy.ops.mesh.select_all(action='DESELECT') #選択解除 233 | # bpy.ops.view3d.select('INVOKE_DEFAULT',extend=True) #マウス下選択 234 | # bpy.ops.mesh.select_linked(delimit={'NORMAL'}) #リンク選択 235 | # bpy.ops.mesh.select_all(action='INVERT') 236 | # bpy.ops.mesh.reveal() 237 | # bpy.ops.mesh.select_all(action='INVERT') 238 | # 239 | # 240 | # selected_faces = [f for f in bm.faces if f.select] 241 | # 242 | # for f in selected_faces : 243 | # if selected_faces: 244 | # f.select=True 245 | # 246 | # del(selected_faces[:]) 247 | # 248 | # # bpy.ops.object.vertex_group_deselect() 249 | # bpy.ops.object.vertex_group_select() 250 | # bpy.ops.object.vertex_group_remove() 251 | # 252 | # return {'FINISHED'} 253 | 254 | 255 | # ヘッダーに項目追加 256 | def angle_select_click_threshold_menu(self, context): 257 | 258 | layout = self.layout 259 | scene = context.scene 260 | 261 | # row = layout.row(align=True) 262 | layout.label(text="angle select click:", icon='LAMP_HEMI') 263 | layout.prop(context.scene, "angle_select_click_threshold", text="Angle") 264 | 265 | 266 | 267 | addon_keymaps = [] 268 | def register(): 269 | bpy.utils.register_module(__name__) 270 | wm = bpy.context.window_manager 271 | 272 | km = wm.keyconfigs.addon.keymaps.new(name = 'Mesh') 273 | kmi = km.keymap_items.new(angle_select_click.bl_idname, 'Y', 'PRESS', alt=True) 274 | addon_keymaps.append((km, kmi)) 275 | 276 | kmi = km.keymap_items.new(angle_select_click_extend.bl_idname, 'Y', 'PRESS', alt=True,shift=True) 277 | addon_keymaps.append((km, kmi)) 278 | 279 | kmi = km.keymap_items.new(angle_select_click.bl_idname, 'ACTIONMOUSE', 'PRESS', ctrl=True) 280 | addon_keymaps.append((km, kmi)) 281 | 282 | kmi = km.keymap_items.new(angle_select_click_extend.bl_idname, 'ACTIONMOUSE', 'PRESS', ctrl=True,shift=True) 283 | addon_keymaps.append((km, kmi)) 284 | 285 | 286 | 287 | # メニューに項目追加 288 | bpy.types.VIEW3D_PT_view3d_meshdisplay.append(angle_select_click_threshold_menu) 289 | bpy.app.translations.register(__name__, translation_dict) # 辞書の登録 290 | 291 | 292 | def unregister(): 293 | bpy.utils.unregister_module(__name__) 294 | for km, kmi in addon_keymaps: 295 | km.keymap_items.remove(kmi) 296 | addon_keymaps.clear() 297 | 298 | bpy.app.translations.unregister(__name__) # 辞書の削除 299 | 300 | bpy.types.VIEW3D_PT_view3d_meshdisplay.remove(angle_select_click_threshold_menu) 301 | 302 | 303 | if __name__ == '__main__': 304 | register() 305 | -------------------------------------------------------------------------------- /curve_and_array_set.py: -------------------------------------------------------------------------------- 1 | 2 | bl_info = { 3 | "name": "Curve & Array Set", 4 | "author": "bookyakuno", 5 | "version": (1.0), 6 | "blender": (2, 76, 0), 7 | 'location': 'View3D > Tool Shelf > Create > Curve & Array Set', 8 | "description": "Curve & Array Modifier Setting. 1.Curves → 2.object select ", 9 | "category": "3D View", 10 | } 11 | 12 | 13 | 14 | 15 | 16 | 17 | import bpy 18 | 19 | 20 | def main(context): 21 | for ob in context.scene.objects: 22 | print(ob) 23 | 24 | 25 | class curve_and_array_set(bpy.types.Operator): 26 | """Tooltip""" 27 | bl_idname = "object.curve_and_array_set" 28 | bl_label = "Curve & Array Set" 29 | 30 | @classmethod 31 | def poll(cls, context): 32 | return context.active_object is not None 33 | 34 | 35 | 36 | def execute(self, context): 37 | main(context) 38 | 39 | # アクティブオブジェクトの定義 40 | active = bpy.context.active_object 41 | 42 | # アクティブオブジェクトの名前を定義 43 | name = active.name 44 | 45 | # "cv_" + アクティブオブジェクト名に定義 46 | objname = "cv_" + name 47 | 48 | 49 | # 一度、アクティブの選択を解除し、リネームする 50 | active.select = False 51 | for obj in bpy.context.selected_objects: 52 | obj.name = objname 53 | 54 | # 再度、アクティブを選択 55 | active.select = True 56 | 57 | 58 | # ーーーーーーーーーーーーーーーーーーーーーーーーー 59 | # ーーーーーーーーーーーーーーーーーーーーーーーーー 60 | # モディファイアを設定ーーーーーーーーーーーーーーーーーーーーーーーーー 61 | 62 | # 配列複製モディファイアを追加 63 | bpy.ops.object.modifier_add(type='ARRAY') 64 | 65 | # 適合する種類 …… カーブ 66 | bpy.context.object.modifiers["Array"].fit_type = 'FIT_CURVE' 67 | 68 | # カーブオブジェクトを設定 …… カーブ 69 | bpy.context.object.modifiers["Array"].curve = bpy.data.objects[objname] 70 | 71 | # カーブモディファイアを追加 72 | bpy.ops.object.modifier_add(type='CURVE') 73 | 74 | # オブジェクトを設定 75 | bpy.context.object.modifiers["Curve"].object = bpy.data.objects[objname] 76 | 77 | return {'FINISHED'} 78 | 79 | 80 | 81 | 82 | # 終了 ーーーーーーーーーーーーーーーーーーーーーーーーー 83 | # ーーーーーーーーーーーーーーーーーーーーーーーーー 84 | # ーーーーーーーーーーーーーーーーーーーーーーーーー 85 | 86 | 87 | 88 | 89 | 90 | 91 | class curve_and_array_set_Panel(bpy.types.Panel): 92 | """ """ 93 | bl_label = "Curve & Array Set" 94 | bl_idname = "curve_and_array_set_" 95 | bl_space_type = 'VIEW_3D' 96 | bl_region_type = 'TOOLS' 97 | bl_category = "Create" 98 | bl_context = "objectmode" 99 | 100 | 101 | 102 | def draw(self, context): 103 | 104 | layout = self.layout 105 | 106 | row = layout.row() 107 | layout.operator("object.curve_and_array_set" , icon="PARTICLE_POINT") 108 | 109 | 110 | 111 | 112 | 113 | def register(): 114 | bpy.utils.register_class(curve_and_array_set) 115 | bpy.utils.register_class(curve_and_array_set_Panel) 116 | 117 | 118 | def unregister(): 119 | bpy.utils.unregister_class(curve_and_array_set) 120 | bpy.utils.unregister_class(curve_and_array_set_Panel) 121 | 122 | 123 | if __name__ == "__main__": 124 | register() 125 | -------------------------------------------------------------------------------- /dup_x.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | 19 | bl_info = { 20 | "name": "dup_x", 21 | "author": "bookyakuno", 22 | "version": (1,1), 23 | "location": "like a zbrush add parts", 24 | "description": "Shift + cmd + T", 25 | "warning": "", 26 | "category": "Object"} 27 | 28 | import bpy 29 | from bpy.props import IntProperty, FloatProperty 30 | 31 | 32 | class dup_x_modal(bpy.types.Operator): 33 | bl_idname = "object.dup_x_modal" 34 | bl_label = "dup_x_modal" 35 | 36 | first_mouse_y = IntProperty() 37 | first_value = FloatProperty() 38 | 39 | def modal(self, context, event): 40 | if event.type == 'MOUSEMOVE': 41 | delta = self.first_mouse_y - event.mouse_y 42 | context.object.scale.x = self.first_value + delta * 0.001 43 | context.object.scale.y = self.first_value + delta * 0.001 44 | context.object.scale.z = self.first_value + delta * 0.001 45 | 46 | elif event.type == 'LEFTMOUSE': 47 | return {'FINISHED'} 48 | 49 | elif event.type in {'RIGHTMOUSE', 'ESC'}: 50 | context.object.scale.x = self.first_value 51 | context.object.scale.y = self.first_value 52 | context.object.scale.z = self.first_value 53 | 54 | return {'CANCELLED'} 55 | 56 | return {'RUNNING_MODAL'} 57 | 58 | def invoke(self, context, event): 59 | if context.object: 60 | self.first_mouse_y = event.mouse_y 61 | self.first_value = context.object.scale.x 62 | self.first_value = context.object.scale.y 63 | self.first_value = context.object.scale.z 64 | 65 | context.window_manager.modal_handler_add(self) 66 | return {'RUNNING_MODAL'} 67 | else: 68 | self.report({'WARNING'}, "No active object, could not finish") 69 | return {'CANCELLED'} 70 | 71 | 72 | class dup_x(bpy.types.Macro): 73 | bl_idname = "object.dup_x" 74 | bl_label = "dup_x" 75 | bl_options = {'REGISTER','UNDO'} 76 | 77 | @classmethod 78 | def poll(cls, context): 79 | return context.active_object is not None 80 | 81 | 82 | class dup_x_01(bpy.types.Operator): 83 | bl_idname = "object.dup_x_01" 84 | bl_label = "dup_x_01" 85 | 86 | def execute(self, context): 87 | snap_dx = bpy.context.scene.tool_settings.use_snap 88 | snape_dx = bpy.context.scene.tool_settings.snap_element 89 | snapt_dx = bpy.context.scene.tool_settings.snap_target 90 | snapr_dx = bpy.context.scene.tool_settings.use_snap_align_rotation 91 | 92 | bpy.ops.object.duplicate_move_linked() 93 | 94 | bpy.context.scene.tool_settings.use_snap = True 95 | bpy.context.scene.tool_settings.use_snap_align_rotation = True 96 | bpy.context.scene.tool_settings.snap_element = 'FACE' 97 | bpy.context.scene.tool_settings.snap_target = 'MEDIAN' 98 | bpy.context.scene.tool_settings.use_snap_project = False 99 | 100 | 101 | return {'FINISHED'} 102 | 103 | 104 | class dup_x_02(bpy.types.Operator): 105 | bl_idname = "object.dup_x_02" 106 | bl_label = "dup_x_02" 107 | 108 | def execute(self, context): 109 | bpy.context.scene.tool_settings.use_snap = False 110 | 111 | return {'FINISHED'} 112 | 113 | class dup_x_03(bpy.types.Operator): 114 | bl_idname = "object.dup_x_03" 115 | bl_label = "dup_x_03" 116 | 117 | @classmethod 118 | def poll(cls, context): 119 | return context.active_object is not None 120 | 121 | def execute(self, context): 122 | 123 | return {'FINISHED'} 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | class dup_x_04(bpy.types.Operator): 132 | bl_idname = "object.dup_x_04" 133 | bl_label = "dup_x_04" 134 | 135 | def execute(self, context): 136 | bpy.ops.transform.resize("INVOKE_DEFAULT") 137 | 138 | return {'FINISHED'} 139 | 140 | 141 | 142 | 143 | class dup_x_05(bpy.types.Operator): 144 | bl_idname = "object.dup_x_05" 145 | bl_label = "dup_x_05" 146 | 147 | def execute(self, context): 148 | bpy.ops.transform.rotate("INVOKE_DEFAULT",constraint_orientation='NORMAL',constraint_axis=(False, False, True)) 149 | 150 | return {'FINISHED'} 151 | 152 | 153 | class dup_x_06(bpy.types.Operator): 154 | bl_idname = "object.dup_x_06" 155 | bl_label = "dup_x_06" 156 | 157 | def execute(self, context): 158 | bpy.ops.transform.translate(value=(0.1, 0, 0), constraint_axis=(True, False, False), constraint_orientation='GLOBAL',) 159 | 160 | return {'FINISHED'} 161 | 162 | class dup_x_reset(bpy.types.Operator): 163 | bl_idname = "object.dup_x_reset" 164 | bl_label = "dup_x_reset" 165 | 166 | def execute(self, context): 167 | bpy.context.scene.tool_settings.use_snap = snap_dx 168 | bpy.context.scene.tool_settings.snap_element = snape_dx 169 | bpy.context.scene.tool_settings.snap_target = snapt_dx 170 | bpy.context.scene.tool_settings.use_snap_align_rotation = snapr_dx 171 | 172 | return {'FINISHED'} 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | # 188 | # addon_keymaps = [] 189 | # def register(): 190 | # bpy.utils.register_class(dup_x_modal) 191 | # bpy.utils.register_class(dup_x) 192 | # bpy.utils.register_class(dup_x_01) 193 | # bpy.utils.register_class(dup_x_02) 194 | # bpy.utils.register_class(dup_x_03) 195 | # bpy.utils.register_class(dup_x_04) 196 | # bpy.utils.register_class(dup_x_05) 197 | # bpy.utils.register_class(dup_x_06) 198 | # bpy.utils.register_class(dup_x_reset) 199 | # 200 | # bpy.utils.register_module(__name__) 201 | # wm = bpy.context.window_manager 202 | 203 | 204 | 205 | 206 | # store keymaps here to access after registration 207 | addon_keymaps = [] 208 | def register(): 209 | bpy.utils.register_module(__name__) 210 | # ヘッダーメニューに項目追加 211 | 212 | 213 | wm = bpy.context.window_manager 214 | 215 | km = wm.keyconfigs.addon.keymaps.new(name = 'Object Mode', space_type = 'EMPTY') 216 | kmi = km.keymap_items.new(dup_x.bl_idname, 'T', 'PRESS', shift=True, oskey=True) 217 | addon_keymaps.append((km, kmi)) 218 | 219 | 220 | # マクロ登録 221 | dup_x.define('OBJECT_OT_dup_x_01') 222 | dup_x.define('TRANSFORM_OT_translate') 223 | dup_x.define('OBJECT_OT_dup_x_02') 224 | # dup_x.define('OBJECT_OT_modal_operator') 225 | # dup_x.define('OBJECT_OT_dup_x_02') 226 | dup_x.define('OBJECT_OT_dup_x_03') 227 | dup_x.define('OBJECT_OT_dup_x_modal') 228 | dup_x.define('OBJECT_OT_dup_x_05') 229 | # dup_x.define('OBJECT_OT_dup_x_06') 230 | # dup_x.define('OBJECT_OT_dup_x_04') 231 | # dup_x.define('OBJECT_OT_dup_x_reset') 232 | 233 | 234 | def unregister(): 235 | bpy.utils.unregister_class(dup_x_modal) 236 | bpy.utils.unregister_class(dup_x) 237 | bpy.utils.unregister_class(dup_x_01) 238 | bpy.utils.unregister_class(dup_x_02) 239 | bpy.utils.unregister_class(dup_x_03) 240 | bpy.utils.unregister_class(dup_x_04) 241 | bpy.utils.unregister_class(dup_x_05) 242 | bpy.utils.unregister_class(dup_x_06) 243 | bpy.utils.unregister_class(dup_x_reset) 244 | 245 | bpy.utils.unregister_module(__name__) 246 | # handle the keymap 247 | for km, kmi in addon_keymaps: 248 | km.keymap_items.remove(kmi) 249 | addon_keymaps.clear() 250 | 251 | if __name__ == "__main__": 252 | register() 253 | -------------------------------------------------------------------------------- /group_layer.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | 19 | bl_info = { 20 | "name": "group_layer", 21 | "author": "bookyakuno", 22 | "version": (1,1), 23 | "location": "Outliner header", 24 | "description": "Outliner group like layer.", 25 | "warning": "", 26 | "category": "outliner"} 27 | 28 | 29 | import bpy 30 | 31 | class root_group_z(bpy.types.Operator): 32 | bl_idname = "object.root_group_z" 33 | bl_label = "root_group_z" 34 | bl_description = "Add object with no group to '_root'." 35 | 36 | def execute(self, context): 37 | 38 | 39 | 40 | x0 = bpy.context.scene.layers[0] 41 | x1 = bpy.context.scene.layers[1] 42 | x2 = bpy.context.scene.layers[2] 43 | x3 = bpy.context.scene.layers[3] 44 | x4 = bpy.context.scene.layers[4] 45 | x5 = bpy.context.scene.layers[5] 46 | x6 = bpy.context.scene.layers[6] 47 | x7 = bpy.context.scene.layers[7] 48 | x8 = bpy.context.scene.layers[8] 49 | x9 = bpy.context.scene.layers[9] 50 | x10 = bpy.context.scene.layers[10] 51 | x11 = bpy.context.scene.layers[11] 52 | x12 = bpy.context.scene.layers[12] 53 | x13 = bpy.context.scene.layers[13] 54 | x14 = bpy.context.scene.layers[14] 55 | x15 = bpy.context.scene.layers[15] 56 | x16 = bpy.context.scene.layers[16] 57 | x17 = bpy.context.scene.layers[17] 58 | x18 = bpy.context.scene.layers[18] 59 | x19 = bpy.context.scene.layers[19] 60 | #x20 = bpy.context.scene.layers[20] 61 | 62 | 63 | bpy.context.scene.layers[0] = True 64 | bpy.context.scene.layers[1] = True 65 | bpy.context.scene.layers[2] = True 66 | bpy.context.scene.layers[3] = True 67 | bpy.context.scene.layers[4] = True 68 | bpy.context.scene.layers[5] = True 69 | bpy.context.scene.layers[6] = True 70 | bpy.context.scene.layers[7] = True 71 | bpy.context.scene.layers[8] = True 72 | bpy.context.scene.layers[9] = True 73 | bpy.context.scene.layers[10] = True 74 | bpy.context.scene.layers[11] = True 75 | bpy.context.scene.layers[12] = True 76 | bpy.context.scene.layers[13] = True 77 | bpy.context.scene.layers[14] = True 78 | bpy.context.scene.layers[15] = True 79 | bpy.context.scene.layers[16] = True 80 | bpy.context.scene.layers[17] = True 81 | bpy.context.scene.layers[18] = True 82 | bpy.context.scene.layers[19] = True 83 | #bpy.context.scene.layers[20] = True 84 | 85 | 86 | for ob in bpy.context.scene.objects: 87 | ob.select = True 88 | 89 | for group in bpy.data.groups: 90 | for object in group.objects: 91 | # print(object.name) 92 | # o = bpy.data.objects 93 | # o.select = True 94 | ee = object 95 | ee.select = False 96 | 97 | 98 | for o in bpy.context.selected_objects: 99 | bpy.data.groups["_root"].objects.link(o) 100 | 101 | 102 | bpy.context.scene.layers[0] = x0 103 | bpy.context.scene.layers[1] = x1 104 | bpy.context.scene.layers[2] = x2 105 | bpy.context.scene.layers[3] = x3 106 | bpy.context.scene.layers[4] = x4 107 | bpy.context.scene.layers[5] = x5 108 | bpy.context.scene.layers[6] = x6 109 | bpy.context.scene.layers[7] = x7 110 | bpy.context.scene.layers[8] = x8 111 | bpy.context.scene.layers[9] = x9 112 | bpy.context.scene.layers[10] = x10 113 | bpy.context.scene.layers[11] = x11 114 | bpy.context.scene.layers[12] = x12 115 | bpy.context.scene.layers[13] = x13 116 | bpy.context.scene.layers[14] = x14 117 | bpy.context.scene.layers[15] = x15 118 | bpy.context.scene.layers[16] = x16 119 | bpy.context.scene.layers[17] = x17 120 | bpy.context.scene.layers[18] = x18 121 | bpy.context.scene.layers[19] = x19 122 | #bpy.context.scene.layers[20] = x20 123 | 124 | 125 | return {'FINISHED'} 126 | 127 | 128 | class new_group_z(bpy.types.Operator): 129 | bl_idname = "object.new_group_z" 130 | bl_label = "new_group_z" 131 | bl_description = "all remove and Create new group." 132 | 133 | def execute(self, context): 134 | 135 | 136 | x0 = bpy.context.scene.layers[0] 137 | x1 = bpy.context.scene.layers[1] 138 | x2 = bpy.context.scene.layers[2] 139 | x3 = bpy.context.scene.layers[3] 140 | x4 = bpy.context.scene.layers[4] 141 | x5 = bpy.context.scene.layers[5] 142 | x6 = bpy.context.scene.layers[6] 143 | x7 = bpy.context.scene.layers[7] 144 | x8 = bpy.context.scene.layers[8] 145 | x9 = bpy.context.scene.layers[9] 146 | x10 = bpy.context.scene.layers[10] 147 | x11 = bpy.context.scene.layers[11] 148 | x12 = bpy.context.scene.layers[12] 149 | x13 = bpy.context.scene.layers[13] 150 | x14 = bpy.context.scene.layers[14] 151 | x15 = bpy.context.scene.layers[15] 152 | x16 = bpy.context.scene.layers[16] 153 | x17 = bpy.context.scene.layers[17] 154 | x18 = bpy.context.scene.layers[18] 155 | x19 = bpy.context.scene.layers[19] 156 | #x20 = bpy.context.scene.layers[20] 157 | 158 | 159 | bpy.context.scene.layers[0] = True 160 | bpy.context.scene.layers[1] = True 161 | bpy.context.scene.layers[2] = True 162 | bpy.context.scene.layers[3] = True 163 | bpy.context.scene.layers[4] = True 164 | bpy.context.scene.layers[5] = True 165 | bpy.context.scene.layers[6] = True 166 | bpy.context.scene.layers[7] = True 167 | bpy.context.scene.layers[8] = True 168 | bpy.context.scene.layers[9] = True 169 | bpy.context.scene.layers[10] = True 170 | bpy.context.scene.layers[11] = True 171 | bpy.context.scene.layers[12] = True 172 | bpy.context.scene.layers[13] = True 173 | bpy.context.scene.layers[14] = True 174 | bpy.context.scene.layers[15] = True 175 | bpy.context.scene.layers[16] = True 176 | bpy.context.scene.layers[17] = True 177 | bpy.context.scene.layers[18] = True 178 | bpy.context.scene.layers[19] = True 179 | #bpy.context.scene.layers[20] = True 180 | 181 | bpy.ops.group.objects_remove_all() 182 | # bpy.ops.group.objects_add_active(group='z_') 183 | bpy.ops.group.create(name="z_") 184 | 185 | 186 | bpy.context.scene.layers[0] = x0 187 | bpy.context.scene.layers[1] = x1 188 | bpy.context.scene.layers[2] = x2 189 | bpy.context.scene.layers[3] = x3 190 | bpy.context.scene.layers[4] = x4 191 | bpy.context.scene.layers[5] = x5 192 | bpy.context.scene.layers[6] = x6 193 | bpy.context.scene.layers[7] = x7 194 | bpy.context.scene.layers[8] = x8 195 | bpy.context.scene.layers[9] = x9 196 | bpy.context.scene.layers[10] = x10 197 | bpy.context.scene.layers[11] = x11 198 | bpy.context.scene.layers[12] = x12 199 | bpy.context.scene.layers[13] = x13 200 | bpy.context.scene.layers[14] = x14 201 | bpy.context.scene.layers[15] = x15 202 | bpy.context.scene.layers[16] = x16 203 | bpy.context.scene.layers[17] = x17 204 | bpy.context.scene.layers[18] = x18 205 | bpy.context.scene.layers[19] = x19 206 | #bpy.context.scene.layers[20] = x20 207 | 208 | 209 | 210 | 211 | return {'FINISHED'} 212 | 213 | class all_remove_group_z(bpy.types.Operator): 214 | bl_idname = "object.all_remove_group_z" 215 | bl_label = "all_remove_group_z" 216 | bl_description = "all remove group.('object nothing group' data leave!! Better 'RMB > Delete Group')" 217 | 218 | def execute(self, context): 219 | 220 | 221 | x0 = bpy.context.scene.layers[0] 222 | x1 = bpy.context.scene.layers[1] 223 | x2 = bpy.context.scene.layers[2] 224 | x3 = bpy.context.scene.layers[3] 225 | x4 = bpy.context.scene.layers[4] 226 | x5 = bpy.context.scene.layers[5] 227 | x6 = bpy.context.scene.layers[6] 228 | x7 = bpy.context.scene.layers[7] 229 | x8 = bpy.context.scene.layers[8] 230 | x9 = bpy.context.scene.layers[9] 231 | x10 = bpy.context.scene.layers[10] 232 | x11 = bpy.context.scene.layers[11] 233 | x12 = bpy.context.scene.layers[12] 234 | x13 = bpy.context.scene.layers[13] 235 | x14 = bpy.context.scene.layers[14] 236 | x15 = bpy.context.scene.layers[15] 237 | x16 = bpy.context.scene.layers[16] 238 | x17 = bpy.context.scene.layers[17] 239 | x18 = bpy.context.scene.layers[18] 240 | x19 = bpy.context.scene.layers[19] 241 | #x20 = bpy.context.scene.layers[20] 242 | 243 | 244 | bpy.context.scene.layers[0] = True 245 | bpy.context.scene.layers[1] = True 246 | bpy.context.scene.layers[2] = True 247 | bpy.context.scene.layers[3] = True 248 | bpy.context.scene.layers[4] = True 249 | bpy.context.scene.layers[5] = True 250 | bpy.context.scene.layers[6] = True 251 | bpy.context.scene.layers[7] = True 252 | bpy.context.scene.layers[8] = True 253 | bpy.context.scene.layers[9] = True 254 | bpy.context.scene.layers[10] = True 255 | bpy.context.scene.layers[11] = True 256 | bpy.context.scene.layers[12] = True 257 | bpy.context.scene.layers[13] = True 258 | bpy.context.scene.layers[14] = True 259 | bpy.context.scene.layers[15] = True 260 | bpy.context.scene.layers[16] = True 261 | bpy.context.scene.layers[17] = True 262 | bpy.context.scene.layers[18] = True 263 | bpy.context.scene.layers[19] = True 264 | #bpy.context.scene.layers[20] = True 265 | 266 | bpy.ops.group.objects_remove_all() 267 | # bpy.ops.group.objects_add_active(group='z_') 268 | # bpy.ops.group.create(name="z_") 269 | 270 | 271 | bpy.context.scene.layers[0] = x0 272 | bpy.context.scene.layers[1] = x1 273 | bpy.context.scene.layers[2] = x2 274 | bpy.context.scene.layers[3] = x3 275 | bpy.context.scene.layers[4] = x4 276 | bpy.context.scene.layers[5] = x5 277 | bpy.context.scene.layers[6] = x6 278 | bpy.context.scene.layers[7] = x7 279 | bpy.context.scene.layers[8] = x8 280 | bpy.context.scene.layers[9] = x9 281 | bpy.context.scene.layers[10] = x10 282 | bpy.context.scene.layers[11] = x11 283 | bpy.context.scene.layers[12] = x12 284 | bpy.context.scene.layers[13] = x13 285 | bpy.context.scene.layers[14] = x14 286 | bpy.context.scene.layers[15] = x15 287 | bpy.context.scene.layers[16] = x16 288 | bpy.context.scene.layers[17] = x17 289 | bpy.context.scene.layers[18] = x18 290 | bpy.context.scene.layers[19] = x19 291 | #bpy.context.scene.layers[20] = x20 292 | 293 | 294 | 295 | 296 | return {'FINISHED'} 297 | 298 | 299 | class move_group_z(bpy.types.Operator): 300 | bl_idname = "object.move_group_z" 301 | bl_label = "move_group_z" 302 | bl_description = "move to active group.(all remove and move to active object group)" 303 | 304 | def execute(self, context): 305 | # アクティブオブジェクトの定義 306 | active = bpy.context.active_object 307 | # 一度、アクティブの選択を解除し、リネームする 308 | active.select = False 309 | 310 | bpy.ops.group.objects_remove_all() 311 | # bpy.ops.object.group_link() 312 | # 再度、アクティブを選択 313 | active.select = True 314 | bpy.ops.group.objects_add_active() 315 | 316 | 317 | 318 | return {'FINISHED'} 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | def group_layer_menu(self, context): 328 | 329 | space = context.space_data 330 | layout = self.layout 331 | # layout.menu("OUTLINER_MT_view", text="",icon="COLLAPSEMENU") 332 | # layout.menu("OUTLINER_MT_search", text="",icon="FILTER") 333 | 334 | 335 | if bpy.context.space_data.display_mode == 'GROUPS': 336 | row = layout.row() 337 | row = layout.row(align=True) 338 | 339 | # row.operator("group.objects_remove", text="", icon='X') 340 | row.operator("object.all_remove_group_z", text="", icon='CANCEL') 341 | # row.operator("object.group_link", text="", icon='ZOOMIN') 342 | row.operator("object.move_group_z", text="", icon='EXPORT') 343 | row.operator("object.new_group_z", text="", icon='NEW') 344 | row.operator("object.root_group_z", text="", icon='FILE_BACKUP') 345 | 346 | if space.display_mode == 'DATABLOCKS': 347 | layout.menu("OUTLINER_MT_edit_datablocks") 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | # 356 | # class move_group_z_01(bpy.types.Operator): 357 | # bl_idname = "object.move_group_z_01" 358 | # bl_label = "move_group_z_01" 359 | # 360 | # def execute(self, context): 361 | # bpy.ops.group.objects_remove_all() 362 | # 363 | # return {'FINISHED'} 364 | # 365 | # class move_group_z_02(bpy.types.Operator): 366 | # bl_idname = "object.move_group_z_02" 367 | # bl_label = "move_group_z_02" 368 | # 369 | # def execute(self, context): 370 | # bpy.ops.object.group_link() 371 | # 372 | # 373 | # return {'FINISHED'} 374 | # 375 | # class move_group_z_03(bpy.types.Operator): 376 | # bl_idname = "object.move_group_z_03" 377 | # bl_label = "move_group_z_03" 378 | # 379 | # def execute(self, context): 380 | # bpy.ops.group.objects_add_active() 381 | # 382 | # return {'FINISHED'} 383 | # 384 | # 385 | # 386 | # 387 | # 388 | # 389 | # 390 | # class move_group_z(bpy.types.Macro): 391 | # bl_idname = "object.move_group_z" 392 | # bl_label = "move_group_z" 393 | # bl_options = {'REGISTER','UNDO'} 394 | # 395 | # @classmethod 396 | # def poll(cls, context): 397 | # return context.active_object is not None 398 | # 399 | # 400 | 401 | 402 | 403 | 404 | 405 | 406 | def register(): 407 | # bpy.utils.register_class(root_group_z) 408 | # bpy.utils.register_class(new_group_z) 409 | # bpy.utils.register_class(move_group_z) 410 | 411 | bpy.utils.register_module(__name__) 412 | bpy.types.OUTLINER_HT_header.prepend(group_layer_menu) 413 | 414 | # # マクロ登録 415 | # move_group_z.define('OBJECT_OT_move_group_z_01') 416 | # move_group_z.define('OBJECT_OT_move_group_z_02') 417 | # move_group_z.define('OBJECT_OT_move_group_z_03') 418 | 419 | 420 | def unregister(): 421 | # bpy.utils.unregister_class(root_group_z) 422 | # bpy.utils.unregister_class(new_group_z) 423 | # bpy.utils.unregister_class(move_group_z) 424 | 425 | 426 | bpy.utils.unregister_module(__name__) 427 | 428 | bpy.types.INFO_HT_header.remove(group_layer_menu) 429 | 430 | 431 | if __name__ == '__main__': 432 | register() 433 | -------------------------------------------------------------------------------- /header_color_change.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.app.handlers import persistent 3 | 4 | bl_info = { 5 | "name" : "header_color_change", 6 | "author" : "Bookyakuno", 7 | "version" : (1, 0, 0), 8 | "blender" : (2, 80, 0), 9 | "location" : "UI", 10 | "description" : "If the automatic keyframe feature is enabled, turn the header color red", 11 | "category" : "UI" 12 | } 13 | 14 | @persistent 15 | def LoadPost_header_col(scn): 16 | handle_handlers_draw_header_col() 17 | 18 | def handle_handlers_draw_header_col(): 19 | if TEST_prefset not in bpy.app.handlers.depsgraph_update_post: 20 | bpy.app.handlers.depsgraph_update_post.append(TEST_prefset) 21 | 22 | 23 | def TEST_prefset(scene): 24 | prefs = bpy.context.preferences 25 | 26 | if scene.tool_settings.use_keyframe_insert_auto == True: 27 | prefs.themes[0].topbar.space.header = (0.4, 0.000000, 0.000000, 1.000000) 28 | 29 | else: 30 | prefs.themes[0].topbar.space.header = (0.137255, 0.137255, 0.137255, 1.000000) 31 | 32 | 33 | def register(): 34 | bpy.app.handlers.load_post.append(LoadPost_header_col) 35 | 36 | def unregister(): 37 | bpy.app.handlers.load_post.remove(LoadPost_header_col) 38 | 39 | 40 | if __name__ == "__main__": 41 | register() 42 | -------------------------------------------------------------------------------- /isolate_select.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or 2 | # modify it under the terms of the GNU General Public License 3 | # as published by the Free Software Foundation; either version 2 4 | # of the License, or (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License 12 | # along with this program; if not, write to the Free Software Foundation, 13 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 | 15 | bl_info = { 16 | "name": "Isolate Select", 17 | "author": "bookyakuno", 18 | "version": (1, 1, 0), 19 | "blender": (2, 79), 20 | "location": "3D View Q key", 21 | "description": "Repeat local view as long as there are selected objects & Non zoom", 22 | "category": "3D View", 23 | } 24 | 25 | 26 | import bpy, mathutils 27 | import os, csv 28 | import collections 29 | 30 | 31 | 32 | 33 | class isolate_select(bpy.types.Operator): 34 | bl_idname = "view3d.isolate_select" 35 | bl_label = "Isolate Select" 36 | bl_description = "Repeat local view as long as there are selected objects & Non zoom" 37 | bl_options = {'REGISTER'} 38 | 39 | def execute(self, context): 40 | 41 | 42 | 43 | if (context.space_data.local_view): 44 | # ローカルビューの場合 45 | 46 | # ====== ====== Srt オブジェクト数を見る Srt ====== ====== 47 | # ====== ====== Srt オブジェクト数を見る Srt ====== ====== 48 | # ====== ====== Srt オブジェクト数を見る Srt ====== ====== 49 | # 一度オブジェクトモードに戻って、 50 | # 選択状態の保存、 51 | # 全選択、 52 | # オブジェクト数の情報を得る 53 | # 元の選択状態に戻す 54 | # 55 | # 56 | # 57 | 58 | 59 | if context.mode =='OBJECT': # オブジェクトモードモードの場合 60 | # self.report(type={'INFO'}, message="OB") 61 | 62 | 63 | ff = bpy.context.selected_objects 64 | bpy.ops.object.select_all(action='SELECT') 65 | ww = len (context.selected_objects ) 66 | bpy.ops.object.select_all(action='DESELECT') 67 | for obj in ff: 68 | obj.select = True 69 | 70 | elif context.mode =='SCULPT': # スカルプトモードの場合 71 | 72 | bpy.ops.sculpt.sculptmode_toggle() 73 | 74 | ff = bpy.context.selected_objects 75 | bpy.ops.object.select_all(action='SELECT') 76 | ww = len (context.selected_objects ) 77 | 78 | bpy.ops.object.select_all(action='DESELECT') 79 | for obj in ff: 80 | obj.select = True 81 | 82 | # スカルプトモードに戻る 83 | bpy.ops.sculpt.sculptmode_toggle() 84 | 85 | elif context.mode =='PAINT_WEIGHT': # ウェイトペイントモードの場合 86 | 87 | bpy.ops.paint.weight_paint_toggle() 88 | 89 | ff = bpy.context.selected_objects 90 | bpy.ops.object.select_all(action='SELECT') 91 | ww = len (context.selected_objects ) 92 | 93 | bpy.ops.object.select_all(action='DESELECT') 94 | for obj in ff: 95 | obj.select = True 96 | 97 | # ウェイトペイントモードに戻る 98 | bpy.ops.paint.weight_paint_toggle() 99 | 100 | elif context.mode =='POSE': # ポーズモードの場合 101 | 102 | bpy.ops.object.posemode_toggle() 103 | 104 | ff = bpy.context.selected_objects 105 | bpy.ops.object.select_all(action='SELECT') 106 | ww = len (context.selected_objects ) 107 | 108 | bpy.ops.object.select_all(action='DESELECT') 109 | for obj in ff: 110 | obj.select = True 111 | 112 | # ポーズモードに戻る 113 | bpy.ops.object.posemode_toggle() 114 | 115 | elif context.mode =='PAINT_TEXTURE': # テクスチャペイントモードの場合 116 | 117 | bpy.ops.paint.texture_paint_toggle() 118 | 119 | ff = bpy.context.selected_objects 120 | bpy.ops.object.select_all(action='SELECT') 121 | ww = len (context.selected_objects ) 122 | 123 | bpy.ops.object.select_all(action='DESELECT') 124 | for obj in ff: 125 | obj.select = True 126 | 127 | # テクスチャペイントモードに戻る 128 | bpy.ops.paint.texture_paint_toggle() 129 | 130 | elif context.mode =='PAINT_VERTEX': # 頂点ペイントモードの場合 131 | 132 | bpy.ops.paint.vertex_paint_toggle() 133 | 134 | ff = bpy.context.selected_objects 135 | bpy.ops.object.select_all(action='SELECT') 136 | ww = len (context.selected_objects ) 137 | 138 | bpy.ops.object.select_all(action='DESELECT') 139 | for obj in ff: 140 | obj.select = True 141 | 142 | # 頂点ペイントモードに戻る 143 | bpy.ops.paint.vertex_paint_toggle() 144 | 145 | 146 | elif context.mode == 'EDIT_MESH' or 'EDIT_CURVE' or 'EDIT_SURFACE' or 'EDIT_METABALL' or 'EDIT_ARMATURE': 147 | # 各種編集モードの場合 148 | # self.report(type={'INFO'}, message="misc_Edit") 149 | 150 | # 編集モードを抜ける 151 | bpy.ops.object.editmode_toggle() 152 | 153 | ff = bpy.context.selected_objects 154 | bpy.ops.object.select_all(action='SELECT') 155 | 156 | ww = len (context.selected_objects ) 157 | bpy.ops.object.select_all(action='DESELECT') 158 | 159 | for obj in ff: 160 | obj.select = True 161 | 162 | # 編集モードに戻す 163 | bpy.ops.object.editmode_toggle() 164 | 165 | 166 | 167 | else: # それ以外の場合 168 | 169 | ff = bpy.context.selected_objects 170 | bpy.ops.object.select_all(action='SELECT') 171 | ww = len (context.selected_objects ) 172 | 173 | bpy.ops.object.select_all(action='DESELECT') 174 | for obj in ff: 175 | obj.select = True 176 | 177 | 178 | aax = len (context.selected_objects ) 179 | 180 | 181 | # ====== ====== End オブジェクト数を見る End ====== ====== 182 | # ====== ====== End オブジェクト数を見る End ====== ====== 183 | # ====== ====== End オブジェクト数を見る End ====== ====== 184 | 185 | 186 | 187 | 188 | # ====== ====== Srt オブジェクト数を測る Srt ====== ====== 189 | # ====== ====== Srt オブジェクト数を測る Srt ====== ====== 190 | # ====== ====== Srt オブジェクト数を測る Srt ====== ====== 191 | 192 | 193 | 194 | if len (context.selected_objects ) == 0: 195 | # 選択物が なにもない場合、ローカルビューを終了する 196 | bpy.ops.view3d.local_view_ex_ops() 197 | # self.report(type={'INFO'}, message="0") 198 | 199 | elif ww == 1: 200 | # 選択物が 1つしかない場合、ローカルビューを終了する 201 | 202 | # self.report(type={'INFO'}, message="1") 203 | bpy.ops.view3d.local_view_ex_ops() 204 | 205 | elif len (context.selected_objects ) == ww: 206 | # 選択物が 同じ の場合、ローカルビューを終了する 207 | 208 | # self.report(type={'INFO'}, message="1") 209 | bpy.ops.view3d.local_view_ex_ops() 210 | 211 | 212 | 213 | 214 | # else: 215 | elif len (context.selected_objects ) < ww: 216 | # 選択物が 少ない 場合、ローカルビューを実行する 217 | 218 | 219 | if context.mode =='EDIT_MESH': 220 | # self.report(type={'INFO'}, message="EDIT") 221 | 222 | bpy.ops.object.editmode_toggle() 223 | bpy.ops.view3d.local_view_ex_ops() 224 | bpy.ops.object.editmode_toggle() 225 | 226 | else: 227 | # self.report(type={'INFO'}, message="Repeat") 228 | 229 | aa = bpy.context.selected_objects 230 | 231 | bpy.ops.view3d.local_view_ex_ops() 232 | bpy.ops.object.select_all(action='DESELECT') 233 | for obj in aa: 234 | obj.select = True 235 | bpy.ops.view3d.local_view_ex_ops() 236 | 237 | else: 238 | 239 | # if context.mode =='EDIT_MESH': 240 | 241 | if context.mode =='OBJECT': # オブジェクトモードモードの場合 242 | # self.report(type={'INFO'}, message="OB") 243 | bpy.ops.view3d.local_view_ex_ops() 244 | 245 | elif context.mode == 'EDIT_MESH' or 'EDIT_CURVE' or 'EDIT_SURFACE' or 'EDIT_METABALL' or 'EDIT_ARMATURE': 246 | # self.report(type={'INFO'}, message="elsezzz") 247 | bpy.ops.object.editmode_toggle() 248 | 249 | bpy.ops.view3d.local_view_ex_ops() 250 | bpy.ops.object.editmode_toggle() 251 | 252 | else: 253 | bpy.ops.view3d.local_view_ex_ops() 254 | 255 | 256 | return {'FINISHED'} 257 | 258 | 259 | # ===================================================== 260 | 261 | # ===================================================== 262 | 263 | 264 | 265 | 266 | class LocalViewEx_ops(bpy.types.Operator): #ローカルビューを非ズームで実行する 267 | bl_idname = "view3d.local_view_ex_ops" 268 | bl_label = "Global / local view (non-zoom)" 269 | bl_description = "Displays only selected objects and centered point of view doesn\'t (zoom)" 270 | # bl_options = {'REGISTER'} 271 | 272 | def execute(self, context): 273 | 274 | 275 | pre_smooth_view = context.user_preferences.view.smooth_view 276 | context.user_preferences.view.smooth_view = 0 277 | pre_view_distance = context.region_data.view_distance 278 | pre_view_location = context.region_data.view_location.copy() 279 | pre_view_rotation = context.region_data.view_rotation.copy() 280 | pre_cursor_location = context.space_data.cursor_location.copy() 281 | bpy.ops.view3d.localview() 282 | # if (context.space_data.local_view): 283 | # # self.report(type={'INFO'}, message="Local") 284 | # else: 285 | # self.report(type={'INFO'}, message="Global") 286 | context.space_data.cursor_location = pre_cursor_location 287 | context.region_data.view_distance = pre_view_distance 288 | context.region_data.view_location = pre_view_location 289 | context.region_data.view_rotation = pre_view_rotation 290 | context.user_preferences.view.smooth_view = pre_smooth_view 291 | return {'FINISHED'} 292 | 293 | # ===================================================== 294 | 295 | # ===================================================== 296 | 297 | 298 | 299 | 300 | addon_keymaps = [] 301 | def register(): 302 | bpy.utils.register_module(__name__) 303 | wm = bpy.context.window_manager 304 | 305 | km = wm.keyconfigs.addon.keymaps.new(name = '3D View Generic', space_type = 'VIEW_3D') 306 | kmi = km.keymap_items.new(isolate_select.bl_idname, 'Q', 'PRESS') 307 | addon_keymaps.append((km, kmi)) 308 | 309 | 310 | def unregister(): 311 | bpy.utils.unregister_module(__name__) 312 | for km, kmi in addon_keymaps: 313 | km.keymap_items.remove(kmi) 314 | addon_keymaps.clear() 315 | -------------------------------------------------------------------------------- /maskTools_2-79.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bookyakuno/-Blender-/baa2945d72379f2cf4b6da5ae20a7453dfdb0856/maskTools_2-79.zip -------------------------------------------------------------------------------- /maskTools_2-79/__init__.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Mask Tools", 3 | "author": "Stanislav Blinov,Yigit Savtur,Bookyakuno (2.8Update)", 4 | "version": (0, 37,0), 5 | "blender": (2, 79,0), 6 | "location": "3d View > Tool shelf (T) > Sculpt", 7 | "description": "Tools for Converting Sculpt Masks to Vertex groups", 8 | "warning": "", 9 | "wiki_url": "", 10 | "tracker_url": "", 11 | "category": "Sculpt"} 12 | 13 | 14 | 15 | import bpy 16 | 17 | from .maskToVGroup import * 18 | from .vgroupToMask import * 19 | from .maskFromCavity import * 20 | from .maskToAction import * 21 | 22 | 23 | 24 | 25 | from mathutils import Vector 26 | 27 | import bmesh 28 | import bpy 29 | import collections 30 | import mathutils 31 | import math 32 | from bpy_extras import view3d_utils 33 | from bpy.types import ( 34 | Operator, 35 | Menu, 36 | Panel, 37 | PropertyGroup, 38 | AddonPreferences, 39 | ) 40 | from bpy.props import ( 41 | BoolProperty, 42 | EnumProperty, 43 | FloatProperty, 44 | IntProperty, 45 | PointerProperty, 46 | StringProperty, 47 | ) 48 | 49 | 50 | 51 | 52 | 53 | 54 | class MASKTOOLS_AddonPreferences(bpy.types.AddonPreferences): 55 | bl_idname = __name__ 56 | 57 | def draw(self, context): 58 | layout = self.layout 59 | 60 | col = layout.column(align=True) 61 | row = col.row(align=True) 62 | row.label(text="– Deselect", icon='MOD_MASK') 63 | row.label(text="LEFT MOUSE : DoubleClick + Ctrl + Shift",icon="MOUSE_LMB") 64 | 65 | col = layout.column(align=True) 66 | row = col.row(align=True) 67 | row.label(text="– Invert", icon='PIVOT_MEDIAN') 68 | row.label(text="RIGHT MOUSE : DoubleClick + Ctrl + Shift",icon="MOUSE_RMB") 69 | 70 | col = layout.column(align=True) 71 | row = col.row(align=True) 72 | row.label(text="– Invert", icon='PIVOT_MEDIAN') 73 | row.label(text="LEFT MOUSE : DoubleClick + Ctrl + alt",icon="MOUSE_LMB") 74 | 75 | col = layout.column(align=True) 76 | row = col.row(align=True) 77 | row.label(text="– Smooth", icon='MOD_SMOOTH') 78 | row.label(text="LEFT MOUSE : DoubleClick + Shift",icon="MOUSE_LMB") 79 | 80 | col = layout.column(align=True) 81 | row = col.row(align=True) 82 | row.label(text="– Sharp", icon='IMAGE_ALPHA') 83 | row.label(text="RIGHT MOUSE : DoubleClick + Shift",icon="MOUSE_RMB") 84 | 85 | col = layout.column(align=True) 86 | row = col.row(align=True) 87 | row.label(text="– Fat", icon='ZOOMIN') 88 | row.label(text="LEFT MOUSE : DoubleClick + Alt",icon="MOUSE_LMB") 89 | 90 | col = layout.column(align=True) 91 | row = col.row(align=True) 92 | row.label(text="– Less", icon='ZOOMOUT') 93 | row.label(text="RIGHT MOUSE : DoubleClick + Alt",icon="MOUSE_RMB") 94 | col = layout.column(align=True) 95 | row = col.row(align=True) 96 | row.label(text="– Remove", icon='X') 97 | row.label(text="BACKSPACE") 98 | 99 | 100 | 101 | def execute(self,context): 102 | return {'FINISHED'} 103 | 104 | 105 | 106 | 107 | 108 | class MaskToolsPanel(Panel): 109 | """Creates a Mask Tool Box in the Viewport Tool Panel""" 110 | # bl_category = "Sculpt" 111 | # bl_idname = "MESH_OT_masktools" 112 | # bl_space_type = 'VIEW_3D' 113 | # bl_region_type = 'UI' 114 | # bl_label = "Mask Tools" 115 | bl_category = "Sculpt" 116 | bl_label = "Mask Tools" 117 | bl_idname = "MESH_OT_masktools" 118 | bl_space_type = 'VIEW_3D' 119 | bl_region_type = 'TOOLS' 120 | 121 | 122 | 123 | def draw(self, context): 124 | layout = self.layout 125 | 126 | ############################################################### 127 | row = layout.row(align = True) 128 | row.label(text = "Vertex Group :", icon = 'GROUP_VERTEX') 129 | row = layout.row(align = True) 130 | row.label(text = "Save Mask to VGroup") 131 | 132 | row = layout.row() 133 | row.scale_y = 1.3 134 | row.operator("mesh.masktovgroup", text = "Create VGroup", icon = 'GROUP_VERTEX') 135 | row = layout.row(align = True) 136 | row.operator("mesh.masktovgroup_append", text = "Add VGroup", icon = 'EXPORT') 137 | row.operator("mesh.masktovgroup_remove", text = "Difference VGroup", icon = 'UNLINKED') 138 | 139 | space = layout.row() 140 | 141 | ############################################################### 142 | row = layout.row(align = True) 143 | row.label(text = "Mask :", icon = 'MOD_MASK') 144 | row = layout.row(align = True) 145 | row.label(text = "Import VGroup to Mask ") 146 | 147 | 148 | 149 | row = layout.row(align = True) 150 | row.scale_y = 1.3 151 | row.operator("mesh.vgrouptomask_append", text = "Add", icon = 'IMPORT') 152 | row.operator("mesh.vgrouptomask_remove", text = "Difference", icon = 'UNLINKED') 153 | row = layout.row() 154 | row.operator("mesh.vgrouptomask", text = "New Mask", icon='NONE') 155 | 156 | space = layout.row() 157 | 158 | row = layout.row(align = True) 159 | row.label(text = "Mask Smooth/Sharp :", icon = 'MOD_SMOOTH') 160 | 161 | row = layout.row(align = True) 162 | # row.label(text = "Mask Smooth", icon = 'MOD_MASK') 163 | row.scale_y = 1.3 164 | row.operator("mesh.mask_smooth_all", text = "Smooth", icon = 'SMOOTH') 165 | row.operator("mesh.mask_sharp", text = "Sharp", icon = 'IMAGE_ALPHA') 166 | 167 | row = layout.row(align = False) 168 | row.prop(bpy.context.scene,"mask_smooth_strength", text = "Mask Smooth Strength", icon='MOD_MASK',slider = True) 169 | 170 | 171 | space = layout.row() 172 | 173 | 174 | 175 | ############################################################### 176 | row = layout.row(align = True) 177 | row.label(text = "Mask Fat/Less :", icon = 'ZOOMIN') 178 | row = layout.row(align = True) 179 | row.scale_y = 1.3 180 | row.operator("mesh.mask_fat", text = "Mask Fat", icon = 'ZOOMIN') 181 | row.operator("mesh.mask_less", text = "Mask Less", icon = 'ZOOMOUT') 182 | 183 | row = layout.row(align = True) 184 | row.prop(bpy.context.scene,"mask_fat_repeat", text = "Mask Fat Repeat", icon='MOD_MASK',slider = True) 185 | row.prop(bpy.context.scene,"mask_less_repeat", text = "Mask Less Repeat", icon='MOD_MASK',slider = True) 186 | 187 | space = layout.row() 188 | 189 | ############################################################### 190 | row = layout.row(align = True) 191 | row.label(text = "Mask Edge/Cavity :", icon = 'EDGESEL') 192 | 193 | 194 | row = layout.row(align = True) 195 | # row.label(text = "Mask by Edges :", icon = 'MOD_MASK') 196 | row.scale_y = 1.3 197 | row.operator("mesh.mask_from_edges", text = "Mask by Edges", icon = 'EDGESEL') 198 | 199 | row = layout.row(align = True) 200 | row.prop(bpy.context.scene,"mask_edge_angle", text = "Edge Angle",icon='MOD_MASK',slider = True) 201 | row.prop(bpy.context.scene,"mask_edge_strength", text = "Mask Strength", icon='MOD_MASK',slider = True) 202 | 203 | space = layout.row() 204 | space = layout.row() 205 | 206 | row = layout.row(align = True) 207 | # row.label(text = "Mask by Cavity:", icon = 'MOD_MASK') 208 | row.scale_y = 1.3 209 | row.operator("mesh.mask_from_cavity", text = "Mask by Cavity", icon = 'STYLUS_PRESSURE') 210 | 211 | row = layout.row(align = True) 212 | row.prop(bpy.context.scene,"mask_cavity_angle", text = "Cavity Angle",icon='MOD_MASK',slider = True) 213 | row.prop(bpy.context.scene,"mask_cavity_strength", text = "Mask Strength", icon='MOD_MASK',slider = True) 214 | 215 | space = layout.row() 216 | space = layout.row() 217 | 218 | 219 | 220 | ############################################################### 221 | row = layout.row(align = True) 222 | row.label(text = "Mask Misc :", icon = 'FORCE_VORTEX') 223 | 224 | space = layout.row() 225 | row = layout.row(align = True) 226 | row.operator("mesh.mask_sharp_thick", text = "Mask Sharp (Thick)", icon = 'NONE') 227 | row = layout.row(align = True) 228 | maskCavity = layout.row(align = False) 229 | maskCavity.prop(bpy.context.scene,"mask_sharp_thick", text = "Mask Sharp Thick Strength", icon='MOD_MASK',slider = True) 230 | 231 | space = layout.row() 232 | row = layout.row(align = True) 233 | row.operator("mesh.mask_duplicate", text = "Mask Duplicate") 234 | # space = layout.row() 235 | # row = layout.row(align = True) 236 | # row.operator("mesh.mask_lattice", text = "Mask Lattice") 237 | space = layout.row() 238 | row = layout.row(align = True) 239 | row.operator("mesh.mask_polygon_remove", text = "Mask Polygon Remove") 240 | 241 | 242 | 243 | 244 | space = layout.row() 245 | space = layout.row() 246 | space = layout.row() 247 | row = layout.row(align = True) 248 | row.operator("mesh.maskmod_displace", icon = 'MOD_DISPLACE') 249 | row = layout.row(align = True) 250 | row = layout.row(align = False) 251 | row.prop(bpy.context.scene,"maskmod_displace_apply", icon='MOD_MASK') 252 | row.prop(bpy.context.scene,"maskmod_displace_strength", icon='MOD_MASK',slider = True) 253 | 254 | space = layout.row() 255 | row = layout.row(align = True) 256 | row.operator("mesh.maskmod_smooth", icon = 'MOD_SMOOTH') 257 | row = layout.row(align = True) 258 | row = layout.row(align = False) 259 | row.prop(bpy.context.scene,"maskmod_smooth_strength", icon='MOD_MASK',slider = True) 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | classes = { 269 | MASKTOOLS_AddonPreferences, 270 | MaskToolsPanel, 271 | # MASKTOOLS_OT_AddHotkey, 272 | 273 | MaskToVertexGroup, 274 | MaskToVertexGroupAppend, 275 | MaskToVertexGroupRemove, 276 | 277 | VertexGroupToMask, 278 | VertexGroupToMaskAppend, 279 | VertexGroupToMaskRemove, 280 | 281 | MaskFromCavity, 282 | MaskFromEdges, 283 | MaskSmoothAll, 284 | MaskFat, 285 | MaskLess, 286 | MaskSharp, 287 | MaskSharpThick, 288 | MaskLattice, 289 | MaskDuplicate, 290 | MaskArmture, 291 | MaskPolygonRemove, 292 | 293 | 294 | MaskModSmooth, 295 | MaskModDisplace, 296 | } 297 | 298 | addon_keymaps = [] 299 | 300 | 301 | 302 | 303 | ################################################################ 304 | # # # # # # # # プロパティの指定に必要なもの 305 | def kmi_props_setattr(kmi_props, attr, value): 306 | try: 307 | setattr(kmi_props, attr, value) 308 | except AttributeError: 309 | print("Warning: property '%s' not found in keymap item '%s'" % 310 | (attr, kmi_props.__class__.__name__)) 311 | except Exception as e: 312 | print("Warning: %r" % e) 313 | 314 | ################################################################ 315 | 316 | 317 | 318 | 319 | def register(): 320 | 321 | for cls in classes: 322 | bpy.utils.register_class(cls) 323 | 324 | 325 | 326 | 327 | 328 | wm = bpy.context.window_manager 329 | #kc = wm.keyconfigs.user # for adding hotkeys independent from addon 330 | #km = kc.keymaps['Screen'] 331 | kc = wm.keyconfigs.addon # for hotkeys within an addon 332 | 333 | wm = bpy.context.window_manager 334 | keynew = wm.keyconfigs.addon.keymaps.new 335 | 336 | 337 | 338 | 339 | ################################################################ 340 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 341 | kmi = km.keymap_items.new('paint.mask_lasso_gesture', 'RIGHTMOUSE', 'PRESS',ctrl=True,shift=True) 342 | kmi_props_setattr(kmi.properties, 'mode','VALUE') 343 | kmi_props_setattr(kmi.properties, "value", 0.0) 344 | kmi.active = True 345 | addon_keymaps.append((km, kmi)) 346 | 347 | ################################################################ 348 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 349 | kmi = km.keymap_items.new('paint.mask_lasso_gesture', 'LEFTMOUSE', 'PRESS',ctrl=True,shift=True) 350 | kmi_props_setattr(kmi.properties, 'mode','VALUE') 351 | kmi_props_setattr(kmi.properties, "value", 1.0) 352 | kmi.active = True 353 | addon_keymaps.append((km, kmi)) 354 | 355 | 356 | ################################################################ 357 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 358 | kmi = km.keymap_items.new('paint.mask_flood_fill', 'RIGHTMOUSE', 'DOUBLE_CLICK', ctrl=True,shift=True) 359 | kmi_props_setattr(kmi.properties, "mode",'INVERT') 360 | kmi.active = True 361 | addon_keymaps.append((km, kmi)) 362 | ################################################################ 363 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 364 | kmi = km.keymap_items.new('paint.mask_flood_fill', 'LEFTMOUSE', 'DOUBLE_CLICK', ctrl=True,alt=True) 365 | kmi_props_setattr(kmi.properties, "mode",'INVERT') 366 | kmi.active = True 367 | addon_keymaps.append((km, kmi)) 368 | 369 | 370 | ################################################################ 371 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 372 | kmi = km.keymap_items.new('paint.mask_flood_fill', 'LEFTMOUSE', 'DOUBLE_CLICK', ctrl=True,shift=True) 373 | kmi_props_setattr(kmi.properties, 'mode','VALUE') 374 | kmi_props_setattr(kmi.properties, "value", 0.0) 375 | kmi.active = True 376 | addon_keymaps.append((km, kmi)) 377 | 378 | 379 | ################################################################ 380 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 381 | kmi = km.keymap_items.new('mesh.mask_smooth_all', 'LEFTMOUSE', 'DOUBLE_CLICK', shift=True) 382 | kmi.active = True 383 | addon_keymaps.append((km, kmi)) 384 | ################################################################ 385 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 386 | kmi = km.keymap_items.new('mesh.mask_sharp', 'RIGHTMOUSE', 'DOUBLE_CLICK', shift=True) 387 | kmi.active = True 388 | addon_keymaps.append((km, kmi)) 389 | 390 | ################################################################ 391 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 392 | kmi = km.keymap_items.new('mesh.mask_fat', 'LEFTMOUSE', 'DOUBLE_CLICK', alt=True) 393 | kmi.active = True 394 | addon_keymaps.append((km, kmi)) 395 | ################################################################ 396 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 397 | kmi = km.keymap_items.new('mesh.mask_less', 'RIGHTMOUSE', 'DOUBLE_CLICK', alt=True) 398 | kmi.active = True 399 | addon_keymaps.append((km, kmi)) 400 | 401 | ################################################################ 402 | km = keynew('Sculpt', space_type='EMPTY', region_type='WINDOW', modal=False) 403 | kmi = km.keymap_items.new('mesh.mask_polygon_remove', 'BACK_SPACE', 'PRESS') 404 | kmi.active = True 405 | addon_keymaps.append((km, kmi)) 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | # add_hotkey() 416 | 417 | def unregister(): 418 | for cls in classes: 419 | bpy.utils.unregister_class(cls) 420 | 421 | for km, kmi in addon_keymaps: 422 | km.keymap_items.remove(kmi) 423 | addon_keymaps.clear() 424 | # remove_hotkey() 425 | 426 | 427 | if __name__ == "__main__": 428 | register() 429 | -------------------------------------------------------------------------------- /maskTools_2-79/maskToAction.py: -------------------------------------------------------------------------------- 1 | 2 | from mathutils import Vector 3 | 4 | import bmesh 5 | import bpy 6 | import collections 7 | import mathutils 8 | import math 9 | from bpy_extras import view3d_utils 10 | from bpy.types import ( 11 | Operator, 12 | Menu, 13 | Panel, 14 | PropertyGroup, 15 | AddonPreferences, 16 | ) 17 | from bpy.props import ( 18 | BoolProperty, 19 | EnumProperty, 20 | FloatProperty, 21 | IntProperty, 22 | PointerProperty, 23 | StringProperty, 24 | ) 25 | 26 | 27 | # CREATE NEW 28 | class MaskModSmooth(bpy.types.Operator): 29 | '''Mask Smooth Surface''' 30 | bl_idname = "mesh.maskmod_smooth" 31 | bl_label = "Mask Smooth Surface" 32 | bl_options = {'REGISTER', 'UNDO'} 33 | 34 | @classmethod 35 | 36 | def poll(cls, context): 37 | 38 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 39 | 40 | bpy.types.Scene.maskmod_smooth_strength = bpy.props.IntProperty(name = "Smooth strength", default = 10, min=-100, max=100) 41 | 42 | def execute(self, context): 43 | maskmod_smooth_strength = context.scene.maskmod_smooth_strength # update property from user input 44 | 45 | 46 | dynatopoEnabled = False 47 | 48 | if context.active_object.mode == 'SCULPT' : 49 | 50 | bpy.ops.mesh.masktovgroup() 51 | bpy.ops.mesh.masktovgroup_append() 52 | bpy.ops.sculpt.sculptmode_toggle() 53 | bpy.ops.object.modifier_add(type='SMOOTH') 54 | bpy.context.object.modifiers["Smooth"].iterations = maskmod_smooth_strength 55 | bpy.context.object.modifiers["Smooth"].vertex_group = "Mask" 56 | bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Smooth") 57 | 58 | bpy.ops.sculpt.sculptmode_toggle() 59 | # bpy.ops.mesh.vgrouptomask_append() 60 | bpy.ops.object.vertex_group_remove(all=False, all_unlocked=False) 61 | 62 | 63 | if dynatopoEnabled : 64 | bpy.ops.sculpt.dynamic_topology_toggle() 65 | return {'FINISHED'} 66 | 67 | # CREATE NEW 68 | class MaskModDisplace(bpy.types.Operator): 69 | '''Mask Smooth Surface''' 70 | bl_idname = "mesh.maskmod_displace" 71 | bl_label = "Mask Displace Surface" 72 | bl_options = {'REGISTER', 'UNDO'} 73 | 74 | 75 | 76 | 77 | @classmethod 78 | 79 | def poll(cls, context): 80 | 81 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 82 | 83 | bpy.types.Scene.maskmod_displace_strength = bpy.props.FloatProperty(name = "Displace strength", default = 0.2, min=-100, max=100) 84 | bpy.types.Scene.maskmod_displace_apply = bpy.props.BoolProperty(name = "Displace Apply", default = True) 85 | 86 | # bpy.types.Scene.maskmod_displace_apply: bpy.props.BoolProperty( 87 | # name="maskmod_displace_apply", 88 | # default=True, 89 | # description="maskmod_displace_apply" 90 | # ) 91 | 92 | 93 | 94 | def execute(self, context): 95 | maskmod_displace_strength = context.scene.maskmod_displace_strength # update property from user input 96 | maskmod_displace_apply = context.scene.maskmod_displace_apply # update property from user input 97 | 98 | 99 | dynatopoEnabled = False 100 | 101 | if context.active_object.mode == 'SCULPT' : 102 | 103 | bpy.ops.mesh.masktovgroup() 104 | bpy.ops.mesh.masktovgroup_append() 105 | bpy.ops.sculpt.sculptmode_toggle() 106 | bpy.ops.object.modifier_add(type='DISPLACE') 107 | # bpy.context.object.modifiers["Displace"].name = "Displace_mask" 108 | 109 | bpy.context.object.modifiers["Displace"].strength = maskmod_displace_strength 110 | bpy.context.object.modifiers["Displace"].vertex_group = "Mask" 111 | if maskmod_displace_apply == True: 112 | bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Displace") 113 | bpy.ops.object.vertex_group_remove(all=False, all_unlocked=False) 114 | 115 | bpy.ops.sculpt.sculptmode_toggle() 116 | # bpy.ops.mesh.vgrouptomask_append() 117 | 118 | 119 | if dynatopoEnabled : 120 | bpy.ops.sculpt.dynamic_topology_toggle() 121 | return {'FINISHED'} 122 | 123 | 124 | 125 | 126 | 127 | 128 | # @classmethod 129 | # 130 | # def poll(cls, context): 131 | # 132 | # return context.active_object is not None and context.active_object.mode == 'SCULPT' 133 | # 134 | # bpy.types.Scene.maskmod_displace_strength = bpy.props.FloatProperty(name = "Displace strength", default = 0.2, min=-100, max=100) 135 | # bpy.types.Scene.maskmod_displace_apply = bpy.props.BoolProperty(name = "Displace Apply", default = True) 136 | # 137 | # def execute(self, context): 138 | # maskmod_displace_strength = context.scene.maskmod_displace_strength # update property from user input 139 | # maskmod_displace_apply = context.scene.maskmod_displace_apply # update property from user input 140 | # 141 | # 142 | # dynatopoEnabled = False 143 | # 144 | # if context.active_object.mode == 'SCULPT' : 145 | # bpy.ops.sculpt.sculptmode_toggle() 146 | # # DISPLACE 147 | # bpy.ops.object.modifier_add(type='DISPLACE') 148 | # bpy.context.object.modifiers["Displace"].vertex_group = "Mask" 149 | # bpy.context.object.modifiers["Displace"].strength = maskmod_displace_strength 150 | # # DISPLACE end 151 | # 152 | # bpy.ops.sculpt.sculptmode_toggle() 153 | # bpy.ops.mesh.masktovgroup() 154 | # bpy.ops.mesh.masktovgroup_append() 155 | # 156 | # if bpy.types.Scene.maskmod_displace_apply == True: 157 | # bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Displace") 158 | # bpy.ops.object.vertex_group_remove(all=False, all_unlocked=False) 159 | # 160 | # 161 | # if dynatopoEnabled : 162 | # bpy.ops.sculpt.dynamic_topology_toggle() 163 | # return {'FINISHED'} 164 | # 165 | 166 | 167 | 168 | 169 | 170 | def register(): 171 | 172 | bpy.types.Scene.maskmod_smooth_strength = MaskModSmooth.maskmod_smooth_strength 173 | bpy.types.Scene.maskmod_displace_strength = MaskModDisplace.maskmod_displace_strength 174 | bpy.types.Scene.maskmod_displace_apply = MaskModDisplace.maskmod_displace_apply 175 | 176 | bpy.utils.register_module(__name__) 177 | 178 | 179 | def unregister(): 180 | 181 | bpy.types.Scene.maskmod_smooth_strength 182 | bpy.types.Scene.maskmod_displace_strength 183 | bpy.types.Scene.maskmod_displace_apply 184 | 185 | bpy.utils.unregister_module(__name__) 186 | 187 | 188 | if __name__ == "__main__": 189 | register() 190 | -------------------------------------------------------------------------------- /maskTools_2-79/maskToVGroup.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import bmesh 3 | 4 | # CREATE NEW 5 | class MaskToVertexGroup(bpy.types.Operator): 6 | '''Mask To Vertex Group''' 7 | bl_idname = "mesh.masktovgroup" 8 | bl_label = "Mask To Vertex Group" 9 | bl_options = {'REGISTER'} 10 | 11 | @classmethod 12 | 13 | def poll(cls, context): 14 | 15 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 16 | 17 | def execute(self, context): 18 | 19 | dynatopoEnabled = False 20 | 21 | if context.active_object.mode == 'SCULPT' : 22 | 23 | if context.sculpt_object.use_dynamic_topology_sculpting : 24 | 25 | dynatopoEnabled = True 26 | 27 | bpy.ops.sculpt.dynamic_topology_toggle() 28 | 29 | #print(context.active_object.use_dynamic_topology_sculpting) 30 | 31 | bmeshContainer = bmesh.new() # New bmesh container 32 | 33 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 34 | 35 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 36 | 37 | newVertexGroup = context.sculpt_object.vertex_groups.new(name = "Mask") # Create an empty vgroup 38 | 39 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 40 | 41 | for x in bmeshContainer.verts: # itterate from bmesh.verts 42 | 43 | if x[mask] > 0 : # if x BMVert has mask weight 44 | 45 | maskWeight = x[mask] # assign float variable for weight from mask layer 46 | 47 | newVertexGroup.add([x.index], maskWeight, "REPLACE") # add it to vgroup, set mask weight 48 | else : 49 | 50 | newVertexGroup.add([x.index], 0, "REPLACE") 51 | 52 | bmeshContainer.free() 53 | 54 | if dynatopoEnabled : 55 | 56 | bpy.ops.sculpt.dynamic_topology_toggle() 57 | 58 | #print("Mask Converted to Vertex Group") 59 | 60 | return {'FINISHED'} 61 | 62 | 63 | # APPEND 64 | class MaskToVertexGroupAppend(bpy.types.Operator): 65 | '''Append Mask To Vertex Group''' 66 | bl_idname = "mesh.masktovgroup_append" 67 | bl_label = "Append Mask To Vertex Group" 68 | bl_options = {'REGISTER'} 69 | 70 | @classmethod 71 | 72 | def poll(cls, context): 73 | 74 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 75 | 76 | def execute(self, context): 77 | 78 | dynatopoEnabled = False 79 | 80 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 81 | 82 | vGroupLocked = context.sculpt_object.vertex_groups.active.lock_weight 83 | 84 | if vGroupLocked == False : 85 | 86 | if context.sculpt_object.use_dynamic_topology_sculpting : 87 | 88 | dynatopoEnabled = True 89 | 90 | bpy.ops.sculpt.dynamic_topology_toggle() 91 | 92 | bmeshContainer = bmesh.new() # New bmesh container 93 | 94 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 95 | 96 | activeVertexGroup = context.sculpt_object.vertex_groups.active # Set active vgroup 97 | 98 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 99 | 100 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 101 | 102 | for x in bmeshContainer.verts: # itterate from bmesh.verts 103 | 104 | if x[mask] > 0 : # if x BMVERT has mask weight 105 | 106 | maskWeight = x[mask] # assign float variable for weight from mask layer 107 | 108 | activeVertexGroup.add([x.index],maskWeight,"ADD") # add it to vgroup, set mask weight 109 | 110 | bmeshContainer.free() 111 | 112 | if dynatopoEnabled : 113 | 114 | bpy.ops.sculpt.dynamic_topology_toggle() 115 | 116 | #print("Mask Added to Vertex Group") 117 | 118 | return {'FINISHED'} 119 | 120 | # REMOVE 121 | class MaskToVertexGroupRemove(bpy.types.Operator): 122 | '''Remove Mask From Vertex Group''' 123 | bl_idname = "mesh.masktovgroup_remove" 124 | bl_label = "Remove Mask From Vertex Group" 125 | bl_options = {'REGISTER'} 126 | 127 | @classmethod 128 | 129 | def poll(cls, context): 130 | 131 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 132 | 133 | def execute(self, context): 134 | 135 | dynatopoEnabled = False 136 | 137 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 138 | 139 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 140 | 141 | if vGroupLocked == False : 142 | 143 | if context.sculpt_object.use_dynamic_topology_sculpting : 144 | 145 | dynatopoEnabled = True 146 | 147 | bpy.ops.sculpt.dynamic_topology_toggle() 148 | 149 | bmeshContainer = bmesh.new() # New bmesh container 150 | 151 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 152 | 153 | activeVertexGroup = context.sculpt_object.vertex_groups.active # Set active vgroup 154 | 155 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 156 | 157 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 158 | 159 | for x in bmeshContainer.verts: # itterate from bmesh.verts 160 | 161 | if x[mask] > 0 : # if x BMVert has mask weight 162 | 163 | maskWeight = x[mask] # assign float variable for weight from mask layer 164 | 165 | activeVertexGroup.add([x.index], maskWeight,"SUBTRACT") # add it to vgroup, set mask weight 166 | 167 | 168 | bmeshContainer.free() 169 | 170 | if dynatopoEnabled : 171 | 172 | bpy.ops.sculpt.dynamic_topology_toggle() 173 | 174 | #print("Mask Removed from Vertex Group") 175 | 176 | return {'FINISHED'} 177 | 178 | # 179 | # def register(): 180 | # bpy.utils.register_module(__name__) 181 | # 182 | # 183 | # 184 | # def unregister(): 185 | # bpy.utils.unregister_module(__name__) 186 | # 187 | # 188 | # if __name__ == "__main__": 189 | # register() 190 | # 191 | # 192 | -------------------------------------------------------------------------------- /maskTools_2-79/vgroupToMask.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import bmesh 3 | 4 | # CREATE NEW 5 | class VertexGroupToMask(bpy.types.Operator): 6 | '''Vertex Group To Mask''' 7 | bl_idname = "mesh.vgrouptomask" 8 | bl_label = "Vertex Group To Mask" 9 | bl_options = {'REGISTER', 'UNDO'} 10 | 11 | @classmethod 12 | 13 | def poll(cls, context): 14 | 15 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 16 | 17 | def execute(self, context): 18 | 19 | dynatopoEnabled = False 20 | 21 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 22 | 23 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 24 | 25 | if vGroupLocked == False : 26 | 27 | if context.sculpt_object.use_dynamic_topology_sculpting : 28 | 29 | dynatopoEnabled = True 30 | 31 | bpy.ops.sculpt.dynamic_topology_toggle() 32 | 33 | bmeshContainer = bmesh.new() # New bmesh container 34 | 35 | bmeshContainer.from_mesh(context.active_object.data) # Fill container with our object 36 | 37 | activeVertexGroup = context.active_object.vertex_groups.active # Set active vgroup 38 | 39 | mask = bmeshContainer.verts.layers.paint_mask.verify() # get active mask layer 40 | 41 | bmeshContainer.verts.ensure_lookup_table() # Update vertex lookup table 42 | 43 | for x in context.active_object.data.vertices: # For each x vert 44 | 45 | bmeshContainer.verts[x.index] [mask] = 0.0 # Set mask to 0 weight 46 | 47 | if len(x.groups) > 0: # if vert is a member of a vgroup 48 | 49 | for y in x.groups: # For each y vgroup in group list 50 | 51 | if y.group == activeVertexGroup.index: # if y is active group x belongs to 52 | 53 | if activeVertexGroup.weight(x.index) > 0 : # and x vert weight is not zero 54 | 55 | currVert = bmeshContainer.verts[x.index] # current vert is x bmesh vert 56 | 57 | maskWeight = activeVertexGroup.weight(x.index) # set weight from active vgroup 58 | 59 | currVert[mask] = maskWeight # assign weight to custom data layer 60 | 61 | 62 | bmeshContainer.to_mesh(context.active_object.data) # Fill obj data with bmesh data 63 | 64 | bmeshContainer.free() # Release bmesh 65 | 66 | if dynatopoEnabled : 67 | 68 | bpy.ops.sculpt.dynamic_topology_toggle() 69 | 70 | return {'FINISHED'} 71 | 72 | # APPEND 73 | class VertexGroupToMaskAppend(bpy.types.Operator): 74 | '''Append Vertex Group To Mask''' 75 | bl_idname = "mesh.vgrouptomask_append" 76 | bl_label = "Append Vertex Group To Mask" 77 | bl_options = {'REGISTER', 'UNDO'} 78 | 79 | @classmethod 80 | 81 | def poll(cls, context): 82 | 83 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 84 | 85 | def execute(self, context): 86 | 87 | dynatopoEnabled = False 88 | 89 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 90 | 91 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 92 | 93 | if vGroupLocked == False : 94 | 95 | if context.sculpt_object.use_dynamic_topology_sculpting : 96 | 97 | dynatopoEnabled = True 98 | 99 | bpy.ops.sculpt.dynamic_topology_toggle() 100 | 101 | bmeshContainer = bmesh.new() # New bmesh container 102 | 103 | bmeshContainer.from_mesh(context.active_object.data) # Fill container with our object 104 | 105 | activeVertexGroup = context.active_object.vertex_groups.active # Set active vgroup 106 | 107 | mask = bmeshContainer.verts.layers.paint_mask.verify() # get active mask layer 108 | 109 | bmeshContainer.verts.ensure_lookup_table() # Update vertex lookup table 110 | 111 | for x in context.active_object.data.vertices: # For each x vert 112 | 113 | if len(x.groups) > 0: # if vert is a member of a vgroup 114 | 115 | for y in x.groups: # For each y vgroup in group list 116 | 117 | if y.group == activeVertexGroup.index: # if y is active group x belongs to 118 | 119 | if activeVertexGroup.weight(x.index) > 0 : # and x vert weight is not zero 120 | 121 | currVert = bmeshContainer.verts[x.index] # current vert is x bmesh vert 122 | 123 | maskWeight = activeVertexGroup.weight(x.index) # set weight from active vgroup 124 | 125 | currVert[mask] = (maskWeight + currVert[mask]) # add current mask weight to maskweight and assign 126 | if currVert[mask] > 1.0 : # is current mask weight greater than 0-1 range 127 | 128 | currVert[mask] = 1.0 # then Normalize mask weight 129 | 130 | 131 | bmeshContainer.to_mesh(context.active_object.data) # Fill obj data with bmesh data 132 | 133 | bmeshContainer.free() # Release bmesh 134 | 135 | if dynatopoEnabled : 136 | 137 | bpy.ops.sculpt.dynamic_topology_toggle() 138 | 139 | return {'FINISHED'} 140 | 141 | #REMOVE 142 | class VertexGroupToMaskRemove(bpy.types.Operator): 143 | '''Remove Vertex Group From Mask''' 144 | bl_idname = "mesh.vgrouptomask_remove" 145 | bl_label = "Remove Vertex Group From Mask" 146 | bl_options = {'REGISTER', 'UNDO'} 147 | 148 | @classmethod 149 | 150 | def poll(cls, context): 151 | 152 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 153 | 154 | def execute(self, context): 155 | 156 | dynatopoEnabled = False 157 | 158 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 159 | 160 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 161 | 162 | if vGroupLocked == False : 163 | 164 | if context.sculpt_object.use_dynamic_topology_sculpting : 165 | 166 | dynatopoEnabled = True 167 | 168 | bpy.ops.sculpt.dynamic_topology_toggle() 169 | 170 | bmeshContainer = bmesh.new() # New bmesh container 171 | 172 | bmeshContainer.from_mesh(context.active_object.data) # Fill container with our object 173 | 174 | activeVertexGroup = context.active_object.vertex_groups.active # Set active vgroup 175 | 176 | mask = bmeshContainer.verts.layers.paint_mask.verify() # get active mask layer 177 | 178 | bmeshContainer.verts.ensure_lookup_table() # Update vertex lookup table 179 | 180 | for x in context.active_object.data.vertices: # For each x vert 181 | 182 | if len(x.groups) > 0: # if vert is a member of a vgroup 183 | 184 | for y in x.groups: # For each y vgroup in group list 185 | 186 | if y.group == activeVertexGroup.index: # if y is active group x belongs to 187 | 188 | if activeVertexGroup.weight(x.index) > 0 : # and x vert weight is not zero 189 | 190 | currVert = bmeshContainer.verts[x.index] # current vert is x bmesh vert 191 | 192 | maskWeight = activeVertexGroup.weight(x.index) # set weight from active vgroup 193 | 194 | currVert[mask] -= (maskWeight * currVert[mask]) # multiply current mask with maskweight and subtract 195 | if currVert[mask] < 0 : # is current mask weight less than 0 196 | 197 | currVert[mask] = 0 # then Normalize mask weight 198 | 199 | 200 | bmeshContainer.to_mesh(context.active_object.data) # Fill obj data with bmesh data 201 | 202 | bmeshContainer.free() # Release bmesh 203 | 204 | if dynatopoEnabled : 205 | 206 | bpy.ops.sculpt.dynamic_topology_toggle() 207 | 208 | return {'FINISHED'} 209 | 210 | # 211 | # def register(): 212 | # bpy.utils.register_module(__name__) 213 | # 214 | # 215 | # 216 | # def unregister(): 217 | # bpy.utils.unregister_module(__name__) 218 | # 219 | # 220 | # if __name__ == "__main__": 221 | # register() 222 | # 223 | # 224 | # 225 | -------------------------------------------------------------------------------- /maskTools_2-8.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bookyakuno/-Blender-/baa2945d72379f2cf4b6da5ae20a7453dfdb0856/maskTools_2-8.zip -------------------------------------------------------------------------------- /maskTools_2-8/maskToVGroup.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import bmesh 3 | 4 | # CREATE NEW 5 | class MaskToVertexGroup(bpy.types.Operator): 6 | '''Mask To Vertex Group''' 7 | bl_idname = "mesh.masktovgroup" 8 | bl_label = "Mask To Vertex Group" 9 | bl_options = {'REGISTER'} 10 | 11 | @classmethod 12 | 13 | def poll(cls, context): 14 | 15 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 16 | 17 | def execute(self, context): 18 | 19 | dynatopoEnabled = False 20 | 21 | if context.active_object.mode == 'SCULPT' : 22 | 23 | if context.sculpt_object.use_dynamic_topology_sculpting : 24 | 25 | dynatopoEnabled = True 26 | 27 | bpy.ops.sculpt.dynamic_topology_toggle() 28 | 29 | #print(context.active_object.use_dynamic_topology_sculpting) 30 | 31 | bmeshContainer = bmesh.new() # New bmesh container 32 | 33 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 34 | 35 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 36 | 37 | newVertexGroup = context.sculpt_object.vertex_groups.new(name = "Mask") # Create an empty vgroup 38 | 39 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 40 | 41 | for x in bmeshContainer.verts: # itterate from bmesh.verts 42 | 43 | if x[mask] > 0 : # if x BMVert has mask weight 44 | 45 | maskWeight = x[mask] # assign float variable for weight from mask layer 46 | 47 | newVertexGroup.add([x.index], maskWeight, "REPLACE") # add it to vgroup, set mask weight 48 | else : 49 | 50 | newVertexGroup.add([x.index], 0, "REPLACE") 51 | 52 | bmeshContainer.free() 53 | 54 | if dynatopoEnabled : 55 | 56 | bpy.ops.sculpt.dynamic_topology_toggle() 57 | 58 | #print("Mask Converted to Vertex Group") 59 | 60 | return {'FINISHED'} 61 | 62 | 63 | # APPEND 64 | class MaskToVertexGroupAppend(bpy.types.Operator): 65 | '''Append Mask To Vertex Group''' 66 | bl_idname = "mesh.masktovgroup_append" 67 | bl_label = "Append Mask To Vertex Group" 68 | bl_options = {'REGISTER'} 69 | 70 | @classmethod 71 | 72 | def poll(cls, context): 73 | 74 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 75 | 76 | def execute(self, context): 77 | 78 | dynatopoEnabled = False 79 | 80 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 81 | 82 | vGroupLocked = context.sculpt_object.vertex_groups.active.lock_weight 83 | 84 | if vGroupLocked == False : 85 | 86 | if context.sculpt_object.use_dynamic_topology_sculpting : 87 | 88 | dynatopoEnabled = True 89 | 90 | bpy.ops.sculpt.dynamic_topology_toggle() 91 | 92 | bmeshContainer = bmesh.new() # New bmesh container 93 | 94 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 95 | 96 | activeVertexGroup = context.sculpt_object.vertex_groups.active # Set active vgroup 97 | 98 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 99 | 100 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 101 | 102 | for x in bmeshContainer.verts: # itterate from bmesh.verts 103 | 104 | if x[mask] > 0 : # if x BMVERT has mask weight 105 | 106 | maskWeight = x[mask] # assign float variable for weight from mask layer 107 | 108 | activeVertexGroup.add([x.index],maskWeight,"ADD") # add it to vgroup, set mask weight 109 | 110 | bmeshContainer.free() 111 | 112 | if dynatopoEnabled : 113 | 114 | bpy.ops.sculpt.dynamic_topology_toggle() 115 | 116 | #print("Mask Added to Vertex Group") 117 | 118 | return {'FINISHED'} 119 | 120 | # REMOVE 121 | class MaskToVertexGroupRemove(bpy.types.Operator): 122 | '''Remove Mask From Vertex Group''' 123 | bl_idname = "mesh.masktovgroup_remove" 124 | bl_label = "Remove Mask From Vertex Group" 125 | bl_options = {'REGISTER'} 126 | 127 | @classmethod 128 | 129 | def poll(cls, context): 130 | 131 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 132 | 133 | def execute(self, context): 134 | 135 | dynatopoEnabled = False 136 | 137 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 138 | 139 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 140 | 141 | if vGroupLocked == False : 142 | 143 | if context.sculpt_object.use_dynamic_topology_sculpting : 144 | 145 | dynatopoEnabled = True 146 | 147 | bpy.ops.sculpt.dynamic_topology_toggle() 148 | 149 | bmeshContainer = bmesh.new() # New bmesh container 150 | 151 | bmeshContainer.from_mesh(context.sculpt_object.data) # Fill container with our object 152 | 153 | activeVertexGroup = context.sculpt_object.vertex_groups.active # Set active vgroup 154 | 155 | mask = bmeshContainer.verts.layers.paint_mask.verify() # Set the active mask layer as custom layer 156 | 157 | bmeshContainer.verts.ensure_lookup_table() # Just incase > Remove if unneccessary 158 | 159 | for x in bmeshContainer.verts: # itterate from bmesh.verts 160 | 161 | if x[mask] > 0 : # if x BMVert has mask weight 162 | 163 | maskWeight = x[mask] # assign float variable for weight from mask layer 164 | 165 | activeVertexGroup.add([x.index], maskWeight,"SUBTRACT") # add it to vgroup, set mask weight 166 | 167 | 168 | bmeshContainer.free() 169 | 170 | if dynatopoEnabled : 171 | 172 | bpy.ops.sculpt.dynamic_topology_toggle() 173 | 174 | #print("Mask Removed from Vertex Group") 175 | 176 | return {'FINISHED'} 177 | 178 | # 179 | # def register(): 180 | # bpy.utils.register_module(__name__) 181 | # 182 | # 183 | # 184 | # def unregister(): 185 | # bpy.utils.unregister_module(__name__) 186 | # 187 | # 188 | # if __name__ == "__main__": 189 | # register() 190 | # 191 | # 192 | -------------------------------------------------------------------------------- /maskTools_2-8/vgroupToMask.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import bmesh 3 | 4 | # CREATE NEW 5 | class VertexGroupToMask(bpy.types.Operator): 6 | '''Vertex Group To Mask''' 7 | bl_idname = "mesh.vgrouptomask" 8 | bl_label = "Vertex Group To Mask" 9 | bl_options = {'REGISTER', 'UNDO'} 10 | 11 | @classmethod 12 | 13 | def poll(cls, context): 14 | 15 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 16 | 17 | def execute(self, context): 18 | 19 | dynatopoEnabled = False 20 | 21 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 22 | 23 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 24 | 25 | if vGroupLocked == False : 26 | 27 | if context.sculpt_object.use_dynamic_topology_sculpting : 28 | 29 | dynatopoEnabled = True 30 | 31 | bpy.ops.sculpt.dynamic_topology_toggle() 32 | 33 | bmeshContainer = bmesh.new() # New bmesh container 34 | 35 | bmeshContainer.from_mesh(context.active_object.data) # Fill container with our object 36 | 37 | activeVertexGroup = context.active_object.vertex_groups.active # Set active vgroup 38 | 39 | mask = bmeshContainer.verts.layers.paint_mask.verify() # get active mask layer 40 | 41 | bmeshContainer.verts.ensure_lookup_table() # Update vertex lookup table 42 | 43 | for x in context.active_object.data.vertices: # For each x vert 44 | 45 | bmeshContainer.verts[x.index] [mask] = 0.0 # Set mask to 0 weight 46 | 47 | if len(x.groups) > 0: # if vert is a member of a vgroup 48 | 49 | for y in x.groups: # For each y vgroup in group list 50 | 51 | if y.group == activeVertexGroup.index: # if y is active group x belongs to 52 | 53 | if activeVertexGroup.weight(x.index) > 0 : # and x vert weight is not zero 54 | 55 | currVert = bmeshContainer.verts[x.index] # current vert is x bmesh vert 56 | 57 | maskWeight = activeVertexGroup.weight(x.index) # set weight from active vgroup 58 | 59 | currVert[mask] = maskWeight # assign weight to custom data layer 60 | 61 | 62 | bmeshContainer.to_mesh(context.active_object.data) # Fill obj data with bmesh data 63 | 64 | bmeshContainer.free() # Release bmesh 65 | 66 | if dynatopoEnabled : 67 | 68 | bpy.ops.sculpt.dynamic_topology_toggle() 69 | 70 | return {'FINISHED'} 71 | 72 | # APPEND 73 | class VertexGroupToMaskAppend(bpy.types.Operator): 74 | '''Append Vertex Group To Mask''' 75 | bl_idname = "mesh.vgrouptomask_append" 76 | bl_label = "Append Vertex Group To Mask" 77 | bl_options = {'REGISTER', 'UNDO'} 78 | 79 | @classmethod 80 | 81 | def poll(cls, context): 82 | 83 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 84 | 85 | def execute(self, context): 86 | 87 | dynatopoEnabled = False 88 | 89 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 90 | 91 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 92 | 93 | if vGroupLocked == False : 94 | 95 | if context.sculpt_object.use_dynamic_topology_sculpting : 96 | 97 | dynatopoEnabled = True 98 | 99 | bpy.ops.sculpt.dynamic_topology_toggle() 100 | 101 | bmeshContainer = bmesh.new() # New bmesh container 102 | 103 | bmeshContainer.from_mesh(context.active_object.data) # Fill container with our object 104 | 105 | activeVertexGroup = context.active_object.vertex_groups.active # Set active vgroup 106 | 107 | mask = bmeshContainer.verts.layers.paint_mask.verify() # get active mask layer 108 | 109 | bmeshContainer.verts.ensure_lookup_table() # Update vertex lookup table 110 | 111 | for x in context.active_object.data.vertices: # For each x vert 112 | 113 | if len(x.groups) > 0: # if vert is a member of a vgroup 114 | 115 | for y in x.groups: # For each y vgroup in group list 116 | 117 | if y.group == activeVertexGroup.index: # if y is active group x belongs to 118 | 119 | if activeVertexGroup.weight(x.index) > 0 : # and x vert weight is not zero 120 | 121 | currVert = bmeshContainer.verts[x.index] # current vert is x bmesh vert 122 | 123 | maskWeight = activeVertexGroup.weight(x.index) # set weight from active vgroup 124 | 125 | currVert[mask] = (maskWeight + currVert[mask]) # add current mask weight to maskweight and assign 126 | if currVert[mask] > 1.0 : # is current mask weight greater than 0-1 range 127 | 128 | currVert[mask] = 1.0 # then Normalize mask weight 129 | 130 | 131 | bmeshContainer.to_mesh(context.active_object.data) # Fill obj data with bmesh data 132 | 133 | bmeshContainer.free() # Release bmesh 134 | 135 | if dynatopoEnabled : 136 | 137 | bpy.ops.sculpt.dynamic_topology_toggle() 138 | 139 | return {'FINISHED'} 140 | 141 | #REMOVE 142 | class VertexGroupToMaskRemove(bpy.types.Operator): 143 | '''Remove Vertex Group From Mask''' 144 | bl_idname = "mesh.vgrouptomask_remove" 145 | bl_label = "Remove Vertex Group From Mask" 146 | bl_options = {'REGISTER', 'UNDO'} 147 | 148 | @classmethod 149 | 150 | def poll(cls, context): 151 | 152 | return context.active_object is not None and context.active_object.mode == 'SCULPT' 153 | 154 | def execute(self, context): 155 | 156 | dynatopoEnabled = False 157 | 158 | if context.active_object.mode == 'SCULPT'and context.active_object.vertex_groups.active is not None : 159 | 160 | vGroupLocked = context.active_object.vertex_groups.active.lock_weight 161 | 162 | if vGroupLocked == False : 163 | 164 | if context.sculpt_object.use_dynamic_topology_sculpting : 165 | 166 | dynatopoEnabled = True 167 | 168 | bpy.ops.sculpt.dynamic_topology_toggle() 169 | 170 | bmeshContainer = bmesh.new() # New bmesh container 171 | 172 | bmeshContainer.from_mesh(context.active_object.data) # Fill container with our object 173 | 174 | activeVertexGroup = context.active_object.vertex_groups.active # Set active vgroup 175 | 176 | mask = bmeshContainer.verts.layers.paint_mask.verify() # get active mask layer 177 | 178 | bmeshContainer.verts.ensure_lookup_table() # Update vertex lookup table 179 | 180 | for x in context.active_object.data.vertices: # For each x vert 181 | 182 | if len(x.groups) > 0: # if vert is a member of a vgroup 183 | 184 | for y in x.groups: # For each y vgroup in group list 185 | 186 | if y.group == activeVertexGroup.index: # if y is active group x belongs to 187 | 188 | if activeVertexGroup.weight(x.index) > 0 : # and x vert weight is not zero 189 | 190 | currVert = bmeshContainer.verts[x.index] # current vert is x bmesh vert 191 | 192 | maskWeight = activeVertexGroup.weight(x.index) # set weight from active vgroup 193 | 194 | currVert[mask] -= (maskWeight * currVert[mask]) # multiply current mask with maskweight and subtract 195 | if currVert[mask] < 0 : # is current mask weight less than 0 196 | 197 | currVert[mask] = 0 # then Normalize mask weight 198 | 199 | 200 | bmeshContainer.to_mesh(context.active_object.data) # Fill obj data with bmesh data 201 | 202 | bmeshContainer.free() # Release bmesh 203 | 204 | if dynatopoEnabled : 205 | 206 | bpy.ops.sculpt.dynamic_topology_toggle() 207 | 208 | return {'FINISHED'} 209 | 210 | # 211 | # def register(): 212 | # bpy.utils.register_module(__name__) 213 | # 214 | # 215 | # 216 | # def unregister(): 217 | # bpy.utils.unregister_module(__name__) 218 | # 219 | # 220 | # if __name__ == "__main__": 221 | # register() 222 | # 223 | # 224 | # 225 | -------------------------------------------------------------------------------- /misc/addon-keymap-menu(can be changed from the menu).py: -------------------------------------------------------------------------------- 1 | # "addon_keymaps" に登録されたアドオンのキーと一致するキーを、Blenderの設定内から検索して、表示するメニュー 2 | 3 | box = layout.box() 4 | col = box.column() 5 | col.label(text="Keymap List:",icon="KEYINGSET") 6 | 7 | wm = bpy.context.window_manager 8 | kc = wm.keyconfigs.user 9 | old_km_name = "" 10 | for km_add, kmi_add in addon_keymaps: 11 | for km_con in kc.keymaps: 12 | if km_add.name == km_con.name: 13 | km = km_con 14 | 15 | for kmi_con in km.keymap_items: 16 | if kmi_add.name == kmi_con.name: 17 | # ここから オペレーター名が同じで、プロパティが違う場合は、プロパティが同じものを判定する(例は"axis_x")。プロパティを設定していなければここは不要 18 | try: 19 | ad_pro = kmi_add.properties 20 | con_pro = kmi_con.properties 21 | if ad_pro.axis_x == con_pro.axis_x: 22 | kmi = kmi_con 23 | except: 24 | # ここまで 25 | kmi = kmi_con 26 | try: 27 | if not km.name == old_km_name: 28 | col.label(text=str(km.name),icon="DOT") 29 | col.context_pointer_set("keymap", km) 30 | rna_keymap_ui.draw_kmi([], kc, km, kmi, col, 0) 31 | col.separator() 32 | old_km_name = km.name 33 | except: pass 34 | 35 | -------------------------------------------------------------------------------- /misc/bone_hierarchy_menu.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | 4 | # ボーンを階層表示するメニュー 5 | def bone_hierarchy_menu(self,context,layout): 6 | if not bpy.context.active_object: 7 | return 8 | if not bpy.context.object.type == "ARMATURE": 9 | return 10 | 11 | obj = bpy.context.object 12 | bone_data = obj.data.bones 13 | 14 | col = layout.column(align=True) 15 | 16 | # ボーンの最上階層(親なし) 17 | top_bone_l = [b for b in bone_data if not b.parent] 18 | 19 | for bone in top_bone_l: 20 | # アクティブなボーンのアイコン 21 | try: 22 | if bone.name == bone_data.active.name: 23 | icon_val = "BONE_DATA" 24 | else: 25 | icon_val = "BLANK1" 26 | except: icon_val = "BLANK1" 27 | 28 | if not bone.parent and bone.children: # トップ 29 | col.prop(bone ,"name",text="top",icon=icon_val) 30 | 31 | if not bone.children: # 子がない(一番した) 32 | col.prop(bone ,"name",text="no child",icon=icon_val) 33 | continue 34 | 35 | # メイン 36 | bone_hierarchy_loop(obj,bone,col,icon_val,1) 37 | col.separator() 38 | 39 | 40 | # ループ 41 | def bone_hierarchy_loop(obj,bone,col,icon_val,count): 42 | for bone in bone.children: 43 | bone_child_item_menu(obj,bone,col,icon_val,count) 44 | bone_hierarchy_loop(obj,bone,col,icon_val,count + 1) 45 | 46 | if not bone.children: 47 | return 48 | 49 | 50 | # 各ボーンのメニュー 51 | def bone_child_item_menu(obj,bone,col,icon_val,range_count): 52 | rows = col.row(align=True) 53 | for i in range(range_count): 54 | rows.separator(factor=2) 55 | rows.prop(bone ,"name",text="",icon=icon_val) 56 | -------------------------------------------------------------------------------- /misc/startup.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bookyakuno/-Blender-/baa2945d72379f2cf4b6da5ae20a7453dfdb0856/misc/startup.blend -------------------------------------------------------------------------------- /misc/userpref.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bookyakuno/-Blender-/baa2945d72379f2cf4b6da5ae20a7453dfdb0856/misc/userpref.blend -------------------------------------------------------------------------------- /multi_ob_bake.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | 19 | bl_info = { 20 | "name": "multi_ob_bake", 21 | "author": "bookyakuno", 22 | "version": (1,0), 23 | "blender": (2, 78, 0), 24 | 'location': 'Properties > Render > Bake', 25 | "warning": "Required 2 add-ons", 26 | "description": "multi object bake Macro. Create target object & bake object , bake texture", 27 | "category": "Render", 28 | } 29 | 30 | 31 | import bpy 32 | import bmesh 33 | from bpy.types import Menu 34 | from bpy.props import IntProperty, FloatProperty, BoolProperty 35 | 36 | 37 | # AddonPreferences 38 | class Wazou_fast_skin_x(bpy.types.AddonPreferences): 39 | bl_idname = __name__ 40 | 41 | 42 | # bpy.types.Scene.Enable_Tab_FK_01 = bpy.props.BoolProperty(default=False) 43 | 44 | def draw(self, context): 45 | layout = self.layout 46 | 47 | 48 | # layout.prop(context.scene, "Enable_Tab_FK_01", text="URL's", icon="URL") 49 | # if context.scene.Enable_Tab_FK_01: 50 | layout.label(text="Required add-ons", icon="ERROR") 51 | row = layout.row() 52 | 53 | row.operator("wm.url_open", text="Scramble Addon Ghitub").url = "https://github.com/saidenka/Blender-Scramble-Addon" 54 | row.operator("wm.url_open", text="AddAsImageTexture Ghitub").url = "https://github.com/chichige-bobo/BlenderPython/blob/master/AddAsImageTexture.py" 55 | # row.operator("wm.url_open", text="BlenderLounge Forum ").url = "http://blenderlounge.fr/forum/" 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | # operator 65 | class multi_ob_bake(bpy.types.Operator): 66 | bl_idname = "object.multi_ob_bake" 67 | bl_label = "multi_ob_bake" 68 | bl_options = {'REGISTER', 'UNDO'} 69 | def execute(self, context): 70 | 71 | 72 | #ターゲット用オブジェクト複製 73 | bpy.ops.object.duplicate_move() 74 | #名前を取得 75 | active = bpy.context.active_object 76 | name = active.name 77 | 78 | #モディファイア適用・結合 79 | bpy.ops.object.convert(target='MESH') 80 | bpy.ops.object.join() 81 | bpy.context.object.name = name + "_target" 82 | 83 | #ベイク用オブジェクト作成 84 | bpy.ops.object.duplicate_move() 85 | bpy.context.object.name = name + "_bake" 86 | 87 | #ターゲットオブジェクト選択 88 | target = bpy.data.objects[name + "_target"] 89 | target.select = True 90 | 91 | #マテリアル全削除 92 | bpy.ops.material.remove_all_material_slot() 93 | 94 | #UV パッキング 95 | bpy.ops.object.view_menu(variable="VIEW_3D") 96 | bpy.ops.object.editmode_toggle() 97 | bpy.ops.mesh.select_all(action='SELECT') 98 | bpy.ops.object.view_menu(variable="IMAGE_EDITOR") 99 | bpy.ops.uv.select_all(action='SELECT') 100 | bpy.ops.uv.average_islands_scale() 101 | bpy.ops.uv.pack_islands(rotate=False, margin=0.0) 102 | bpy.ops.object.editmode_toggle() 103 | 104 | #Scramble Addon 新規画像作成 105 | bpy.ops.image.new_bake_image(name=name + "_iBake", alpha=False) 106 | 107 | #AddAsImageTexture 画像を元にマテリアル作成 108 | bpy.ops.object.add_as_image_texture() 109 | 110 | #ベイク設定c 111 | bpy.context.scene.cycles.bake_type = 'COMBINED' 112 | bpy.context.scene.use_selected_to_active = True 113 | bpy.context.scene.cage_extrusion = 0.01 114 | 115 | #ベイク 116 | #bpy.ops.object.bake(type='COMBINED') 117 | return {'FINISHED'} 118 | 119 | 120 | 121 | 122 | # Menu 123 | def multi_ob_bake_ui(self, context): 124 | 125 | layout = self.layout 126 | 127 | scene = context.scene 128 | cscene = scene.cycles 129 | rd = context.scene.render 130 | 131 | 132 | scene = context.scene 133 | cscene = scene.cycles 134 | device_type = context.user_preferences.system.compute_device_type 135 | 136 | 137 | col = layout.column(align=True) 138 | row = col.row(align=True) 139 | 140 | 141 | row.operator("object.multi_ob_bake", icon="RENDER_REGION") 142 | 143 | 144 | 145 | 146 | def register(): 147 | bpy.utils.register_module(__name__) 148 | 149 | # bpy.utils.register_class(multi_ob_bake) 150 | bpy.types.CyclesRender_PT_bake.append(multi_ob_bake_ui) 151 | 152 | 153 | def unregister(): 154 | bpy.utils.unregister_module(__name__) 155 | 156 | # bpy.utils.unregister_class(multi_ob_bake) 157 | bpy.types.CyclesRender_PT_bake.remove(multi_ob_bake_ui) 158 | 159 | 160 | if __name__ == "__main__": 161 | register() 162 | -------------------------------------------------------------------------------- /optiloops.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | 19 | bl_info = { 20 | "name": "Optiloops", 21 | "author": "Vilem Duha", 22 | "version": (1, 0), 23 | "blender": (2, 80, 0), 24 | "location": "View3D > Mesh > Mesh Tools panel > Optimize loops", 25 | "description": "Optimize meshes by removing loops with angle threshold", 26 | "warning": "", 27 | "wiki_url": "", 28 | "category": "Add Mesh", 29 | } 30 | 31 | import bpy, bmesh 32 | 33 | from bpy.props import ( 34 | BoolProperty, 35 | BoolVectorProperty, 36 | FloatProperty, 37 | FloatVectorProperty, 38 | ) 39 | 40 | 41 | def get_loop(bm, e): 42 | checkverts = e.verts[:] 43 | checkedverts = [] 44 | loop_edges = [e] 45 | while len(checkverts) > 0: 46 | v = checkverts.pop() 47 | checkedverts.append(v) 48 | if len(v.link_edges) == 4: 49 | for e in v.link_edges: 50 | if e in loop_edges: 51 | estart = e 52 | for e in v.link_edges: 53 | isneighbour = False 54 | for f in e.link_faces: 55 | if f in estart.link_faces: 56 | isneighbour = True 57 | if not isneighbour: 58 | loop_edges.append(e) 59 | for v in e.verts: 60 | if v not in checkedverts and v not in checkverts: 61 | checkverts.append(v) 62 | return loop_edges 63 | 64 | 65 | def get_neighbours(loops): 66 | for l in loops: 67 | l.neighbours = [] 68 | for l in loops: 69 | e = l.edges[0] 70 | neighbours = 0 71 | for f in e.link_faces: 72 | if len(f.verts) == 4: 73 | for e1 in f.edges: 74 | if e1 != e: 75 | do = True 76 | for v in e1.verts: # check it's the parallel edge... 77 | if v in e.verts: 78 | do = False 79 | if do: 80 | for l1 in loops: 81 | if l1 != l and e1 in l1.edges: 82 | neighbours += 1 83 | if l1 not in l.neighbours: 84 | l.neighbours.append(l1) 85 | l1.neighbours.append(l) 86 | 87 | 88 | class edgeloop(): 89 | edges = [] 90 | neighbours = [] 91 | 92 | 93 | def loop_closed(es): 94 | closed = True 95 | for e in es: 96 | for v in e.verts: 97 | ec = 0 98 | for e1 in v.link_edges: 99 | if e1 in es: 100 | ec += 1 101 | if ec == 1: 102 | closed = False 103 | return False 104 | return True 105 | 106 | 107 | def check_angles(edges, angle_threshold): 108 | for e in edges: 109 | if len(e.link_faces) != 2: 110 | return False 111 | # print(len(e.link_faces)) 112 | a = e.calc_face_angle() 113 | if a > angle_threshold: 114 | return False 115 | return True 116 | 117 | 118 | def skiploop(result_loops, final_loops, skip_loops, lstart): 119 | final_loops.append(lstart) 120 | last_neighbour = None 121 | checkneighbours = lstart.neighbours[:] 122 | checked = [] 123 | while len(checkneighbours) > 0: 124 | neighbour = checkneighbours.pop() 125 | checked.append(neighbour) 126 | skip_loops.append(neighbour) 127 | for n in neighbour.neighbours: 128 | if n not in final_loops and n not in checked: 129 | final_loops.append(n) 130 | checked.append(n) 131 | for n1 in n.neighbours: 132 | checkneighbours.append(n1) 133 | 134 | if n1 not in skip_loops and n1 not in final_loops: 135 | skip_loops.append(n1) 136 | checked.append(n1) 137 | 138 | 139 | def optiloops(self, context): 140 | angle_threshold = self.angle_threshold / 180 * 3.1415926 141 | 142 | ob = bpy.context.active_object 143 | bpy.ops.object.mode_set(mode='EDIT') 144 | bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') 145 | 146 | bm = bmesh.from_edit_mesh(ob.data) 147 | 148 | checkedges = [] # bm.edges[:] 149 | bpy.ops.mesh.loop_multi_select(ring=False) 150 | for e in bm.edges: 151 | if e.select: 152 | checkedges.append(e) 153 | if len(checkedges) == 0: 154 | checkedges = bm.edges[:] 155 | resultedges = [] 156 | result_loops = [] 157 | shape_loop_edges = [] 158 | bpy.ops.mesh.select_all(action='DESELECT') 159 | i = 0 160 | while len(checkedges) > 0: 161 | 162 | es = get_loop(bm, checkedges[0]) 163 | 164 | for e in es: 165 | if e in checkedges: 166 | checkedges.remove(e) 167 | 168 | thresok = True 169 | if len(es) == 0: 170 | thresok = False 171 | 172 | if thresok: # only manifold 173 | for e in es: 174 | if len(e.link_faces) < 2: 175 | thresok = False 176 | if e.seam and self.keep_seams: 177 | thresok = False 178 | if thresok: # first level angle check 179 | thresok = check_angles(es, angle_threshold) 180 | 181 | if thresok and self.only_closed: # only closed check 182 | thresok = loop_closed(es) 183 | 184 | if thresok: # append results 185 | resultedges.extend(es) 186 | loop = edgeloop() 187 | loop.edges = es 188 | 189 | result_loops.append(loop) 190 | # if i == 1: 191 | # print(thresok) 192 | # fal 193 | for e in es: 194 | e.select = False 195 | 196 | i += 1 197 | 198 | get_neighbours(result_loops) 199 | 200 | if self.keep_subsurf_influencing_loops: 201 | # check for neighbouring loops if they aren't in the cleanup group which means they are where borders start. 202 | remove_loops = [] 203 | for l in result_loops: 204 | if len(l.neighbours) < 2: 205 | remove_loops.append(l) 206 | for l in remove_loops: 207 | result_loops.remove(l) 208 | get_neighbours(result_loops) 209 | 210 | if not self.finish_dissolve: 211 | for l in result_loops: 212 | for e in l.edges: 213 | e.select = True 214 | else: 215 | while len(result_loops) > 0: 216 | final_loops = [] 217 | # while len(result_loops)>0: 218 | skip_loops = [] 219 | 220 | for l in result_loops: 221 | if len(l.neighbours) == 1 and l.neighbours[0] not in final_loops: 222 | skiploop(result_loops, final_loops, skip_loops, l) 223 | 224 | if len(l.neighbours) == 0: 225 | final_loops.append(l) 226 | if len(skip_loops) + len(final_loops) < len(result_loops): 227 | for l in result_loops: 228 | if l not in skip_loops and l not in final_loops: 229 | skiploop(result_loops, final_loops, skip_loops, l) 230 | # if l not in skip_loops and l not in final_loops and # nothing was done this round 231 | 232 | for l in final_loops: 233 | for e in l.edges: 234 | e.select = True 235 | # fal 236 | bpy.ops.mesh.dissolve_edges() 237 | result_loops = [] 238 | 239 | for l in skip_loops: 240 | 241 | filter = False 242 | for e in l.edges: 243 | if e not in bm.edges: 244 | filter = True 245 | continue 246 | if not filter: 247 | if check_angles(l.edges, angle_threshold): 248 | result_loops.append(l) 249 | 250 | get_neighbours(result_loops) 251 | # make things iterative here 252 | 253 | 254 | # def main(context): 255 | # for ob in context.scene.objects: 256 | # print(ob) 257 | 258 | 259 | class OptiloopsOperator(bpy.types.Operator): 260 | """Reduces mesh geometry while keeping loops""" 261 | bl_idname = "mesh.optiloops" 262 | bl_label = "Optimize loops" 263 | bl_options = {'REGISTER', 'UNDO'} 264 | 265 | angle_threshold = FloatProperty( 266 | name="Max angle", 267 | description="loops containing only lower angles will be removed", 268 | min=0.01, max=180.0, 269 | default=5.0, 270 | ) 271 | 272 | only_closed = BoolProperty( 273 | name="Remove only closed loops", 274 | default=False, 275 | ) 276 | keep_subsurf_influencing_loops = BoolProperty( 277 | name="Keep loops defining subsurf creases", 278 | default=False, 279 | ) 280 | 281 | keep_seams = BoolProperty( 282 | name="Keep uv seams", 283 | description="keep uv seams loops intact", 284 | default=True, 285 | ) 286 | finish_dissolve = BoolProperty( 287 | name="Delete loop candidates", 288 | description="If disabled, loops will only be selected", 289 | default=True, 290 | ) 291 | 292 | @classmethod 293 | def poll(cls, context): 294 | return context.active_object is not None 295 | 296 | def execute(self, context): 297 | optiloops(self, context) 298 | return {'FINISHED'} 299 | 300 | def optiloops_panel(self, context): 301 | layout = self.layout 302 | layout.operator('mesh.optiloops') 303 | 304 | # Regustratuib 305 | 306 | def register(): 307 | bpy.utils.register_class(OptiloopsOperator) 308 | bpy.types.VIEW3D_MT_edit_mesh.append(optiloops_panel) 309 | 310 | 311 | def unregister(): 312 | bpy.utils.unregister_class(OptiloopsOperator) 313 | bpy.types.VIEW3D_MT_edit_mesh.remove(optiloops_panel) 314 | 315 | if __name__ == "__main__": 316 | register() 317 | -------------------------------------------------------------------------------- /reload_addon.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | 19 | # 20 | 21 | 22 | """ 23 | # Blender Add-on: Reload Add-on 24 | blenderを再起動せずにアドオンを再読み込みする 25 | 26 | ## Info Header -> Help -> Reload Addon 27 | メニューから選択したアドオンをリロードする。表示されるのは更新のあった物のみ。 28 | 29 | ## UserPreferences -> Header -> Reload 30 | 更新のあったアドオンを全てリロード。 31 | 32 | ## UserPreferences -> Add-ons -> System: Reload Add-on 33 | 初期設定では一秒間隔でファイルの変更を監視し、変更のあったアドオンを画面に表示、そのボタンを押す事でリロードを行う。 34 | 35 | Show All で現在有効な全てのアドオンを表示。変更のあった物にはアイコンが付く。 36 | 37 | 監視は UserPreference -> Add-ons 画面が表示されている場合にのみ働く。 38 | 間隔は Time Step で設定。単位は秒。0でこの機能を無効化。 39 | 無効化した場合は、Check Update で手動更新する。 40 | 41 | Exclude Pattern で監視対象外のディレクトリを正規表現で指定する。 42 | 初期状態では \__pycache__ 、 .で始まるディレクトリ、 ~で終わるファイルを無視する。 43 | 44 | ## Command 45 | Add-onをリロード 46 | ``` 47 | bpy.ops.wm.addon_reload(module='module_name') 48 | ``` 49 | 50 | 更新のあったアドオンを全てリロード 51 | ``` 52 | bpy.ops.wm.addon_reload_all() 53 | ``` 54 | """ 55 | 56 | 57 | import importlib 58 | import os 59 | import re 60 | import sys 61 | import time 62 | import traceback 63 | 64 | import bpy 65 | import addon_utils 66 | 67 | 68 | bl_info = { 69 | 'name': 'Reload Add-on', 70 | 'author': 'chromoly', 71 | 'version': (0, 1), 72 | 'blender': (2, 76, 0), 73 | 'location': 'UserPreferences -> Add-ons -> Reload Add-on, ' 74 | 'UserPreferences -> Header -> Reload, ' 75 | 'Info -> Header -> Help -> Reload Add-on', 76 | 'description': '', 77 | 'warning': '', 78 | 'wiki_url': '', 79 | 'category': 'System' 80 | } 81 | 82 | 83 | # モジュール名をキー、ファイルパスと更新時間で構成される辞書を値とする辞書 84 | module_mtimes = None 85 | """:type: dict[str, dict[str, float]]""" 86 | 87 | # 更新されたモジュール名を入れる 88 | module_updated = set() 89 | 90 | # 自動更新した時間 91 | prev_time = time.time() 92 | 93 | 94 | class ReloadAddonPreferences(bpy.types.AddonPreferences): 95 | bl_idname = __name__ 96 | 97 | show_all = bpy.props.BoolProperty( 98 | name='Show All', 99 | default=False, 100 | ) 101 | check_interval = bpy.props.IntProperty( 102 | name='Time Step', 103 | description='Interval in seconds between update check' 104 | '(Available only if display UserPreferences->Add-ons)', 105 | min=0, 106 | max=60, 107 | default=1, 108 | subtype='TIME' 109 | ) 110 | exclude_pattern = bpy.props.StringProperty( 111 | name='Exclude Pattern', 112 | description='Regular expression pattern', 113 | default='((.*{s})?__pycache__|(.*{s})?\..*|.*~$)'.format(s=os.sep), 114 | ) 115 | 116 | def draw(self, context): 117 | layout = self.layout 118 | """:type: bpy.types.UILayout""" 119 | column = layout.column() 120 | 121 | split = column.split(0.15) 122 | row = split.row() 123 | row.prop(self, 'show_all') 124 | row = split.row() 125 | row.operator('wm.addon_check_update', icon='FILE_REFRESH') 126 | row.prop(self, 'check_interval') 127 | row.prop(self, 'exclude_pattern') 128 | 129 | flow = column.column_flow(2) 130 | 131 | addons = context.user_preferences.addons 132 | if self.show_all: 133 | module_names = list(addons.keys()) 134 | else: 135 | module_names = [addon.module for addon in addons 136 | if addon.module in module_updated] 137 | 138 | def sort_func(name): 139 | if name in sys.modules: 140 | return addon_utils.module_bl_info(sys.modules[name])['name'] 141 | else: 142 | return name 143 | module_names.sort(key=sort_func) 144 | 145 | for module_name in module_names: 146 | if module_name == __name__: 147 | continue 148 | row = flow.row() 149 | if module_name in module_updated: 150 | icon = 'FILE_REFRESH' 151 | else: 152 | icon = 'NONE' 153 | if module_name in sys.modules: 154 | mod = sys.modules[module_name] 155 | name = addon_utils.module_bl_info(mod)['name'] 156 | else: 157 | name = module_name 158 | op = row.operator('wm.addon_reload', text=name, icon=icon) 159 | op.module = module_name 160 | 161 | @classmethod 162 | def get_prefs(self): 163 | return bpy.context.user_preferences.addons[__name__].preferences 164 | 165 | 166 | def get_module_mtimes(module_name=None): 167 | prefs = ReloadAddonPreferences.get_prefs() 168 | pattern = prefs.exclude_pattern 169 | 170 | mod_mtimes = {} 171 | for addon in bpy.context.user_preferences.addons: 172 | mod_name = addon.module 173 | if module_name and module_name != mod_name: 174 | continue 175 | if mod_name in sys.modules: 176 | mod = sys.modules[mod_name] 177 | else: 178 | try: 179 | importlib.import_module(mod_name) 180 | except: 181 | traceback.print_exc() 182 | mod_mtimes[mod_name] = {} 183 | continue 184 | mtimes = {} 185 | if hasattr(mod, '__path__'): 186 | for mod_path in mod.__path__: 187 | for root, dirs, files in os.walk(mod_path): 188 | for d in list(dirs): 189 | p = os.path.join(root, d) 190 | relpath = os.path.relpath(p, mod_path) 191 | if re.match(pattern, relpath): 192 | dirs.remove(d) 193 | for file in files: 194 | path = os.path.join(root, file) 195 | relpath = os.path.relpath(path, mod_path) 196 | if re.match(pattern, relpath): 197 | continue 198 | mtimes[path] = os.path.getmtime(path) 199 | else: 200 | path = mod.__file__ 201 | mtimes[path] = os.path.getmtime(path) 202 | mod_mtimes[mod_name] = mtimes 203 | return mod_mtimes 204 | 205 | 206 | def check_update(): 207 | global module_mtimes, prev_time 208 | updated = False 209 | if module_mtimes is None: 210 | module_mtimes = get_module_mtimes() 211 | else: 212 | mtimes = get_module_mtimes() 213 | for mod_name, d in mtimes.items(): 214 | if mod_name in module_mtimes: 215 | if d != module_mtimes[mod_name]: 216 | module_updated.add(mod_name) 217 | updated = True 218 | else: 219 | module_updated.add(mod_name) 220 | updated = True 221 | module_mtimes.update(mtimes) 222 | prev_time = time.time() 223 | return updated 224 | 225 | 226 | def reload_addon(context, module_name): 227 | addons = context.user_preferences.addons 228 | if module_name not in addons: 229 | return False 230 | 231 | addon = addons[module_name] 232 | module_name = addon.module 233 | if module_name in sys.modules: 234 | mod = sys.modules[module_name] 235 | try: 236 | mod.unregister() 237 | except: 238 | traceback.print_exc() 239 | del mod 240 | ccc = [] 241 | 242 | for km, kmi in ccc: 243 | km.keymap_items.remove(kmi) 244 | # ccc.clear() 245 | 246 | 247 | for key in list(sys.modules): 248 | if key == module_name or key.startswith(module_name + '.'): 249 | del sys.modules[key] 250 | 251 | bpy.ops.wm.addon_refresh() 252 | try: 253 | mod = importlib.import_module(module_name) 254 | mod.register() 255 | except: 256 | # for key in list(sys.modules): 257 | # if key == module_name or key.startswith(module_name + '.'): 258 | # del sys.modules[key] 259 | # bpy.ops.wm.addon_disable(module=module_name) 260 | traceback.print_exc() 261 | return False 262 | 263 | mtimes = get_module_mtimes(module_name) 264 | module_mtimes[module_name] = mtimes[module_name] 265 | if module_name in module_updated: 266 | module_updated.remove(module_name) 267 | print("Reload '{}'".format(module_name)) 268 | return True 269 | 270 | 271 | def redraw_userprefs(context): 272 | if context.user_preferences.active_section == 'ADDONS': 273 | for win in context.window_manager.windows: 274 | for area in win.screen.areas: 275 | if area.type == 'USER_PREFERENCES': 276 | area.tag_redraw() 277 | 278 | 279 | class WM_OT_addon_check_update(bpy.types.Operator): 280 | bl_idname = 'wm.addon_check_update' 281 | bl_label = 'Check Update' 282 | 283 | def execute(self, context): 284 | check_update() 285 | redraw_userprefs(context) 286 | return {'FINISHED'} 287 | 288 | 289 | class WM_OT_addon_reload(bpy.types.Operator): 290 | bl_idname = 'wm.addon_reload' 291 | bl_label = 'Reload Add-on' 292 | bl_description = 'Reload add-on' 293 | 294 | module = bpy.props.StringProperty(name='Module Name') 295 | 296 | def execute(self, context): 297 | if not reload_addon(context, self.module): 298 | return {'CANCELLED'} 299 | 300 | redraw_userprefs(context) 301 | return {'FINISHED'} 302 | 303 | 304 | class WM_OT_addon_reload_all(bpy.types.Operator): 305 | bl_idname = 'wm.addon_reload_all' 306 | bl_label = 'Reload Add-ons' 307 | bl_description = 'Reload updated add-ons' 308 | 309 | def execute(self, context): 310 | addons = context.user_preferences.addons 311 | check_update() 312 | result = False 313 | for addon in addons: 314 | if addon.module in module_updated: 315 | result |= reload_addon(context, addon.module) 316 | if not result: 317 | return {'CANCELLED'} 318 | 319 | redraw_userprefs(context) 320 | return {'FINISHED'} 321 | 322 | 323 | @bpy.app.handlers.persistent 324 | def scene_update_pre(scene): 325 | global module_mtimes, prev_time 326 | 327 | context = bpy.context 328 | 329 | # メインループからの呼び出しの場合は必ずNoneになる 330 | if context.region: 331 | return 332 | 333 | if module_mtimes is None: 334 | check_update() 335 | else: 336 | prefs = ReloadAddonPreferences.get_prefs() 337 | if prefs.check_interval == 0: 338 | return 339 | if time.time() - prev_time > prefs.check_interval: 340 | if context.user_preferences.active_section == 'ADDONS': 341 | for win in context.window_manager.windows: 342 | for area in win.screen.areas: 343 | if area.type == 'USER_PREFERENCES': 344 | updated = check_update() 345 | if updated: 346 | area.tag_redraw() 347 | return 348 | 349 | 350 | def userprefs_header_draw(self, context): 351 | layout = self.layout 352 | if context.user_preferences.active_section == 'ADDONS': 353 | layout.operator('wm.addon_reload_all', text='Reload', 354 | icon='FILE_REFRESH') 355 | 356 | 357 | class INFO_MT_help_addon_reload(bpy.types.Menu): 358 | bl_idname = 'INFO_MT_help_addon_reload' 359 | bl_label = 'Reload Add-on' 360 | 361 | def draw(self, context): 362 | layout = self.layout 363 | check_update() 364 | 365 | addons = context.user_preferences.addons 366 | module_names = [addon.module for addon in addons 367 | if addon.module in module_updated] 368 | 369 | def sort_func(name): 370 | if name in sys.modules: 371 | return addon_utils.module_bl_info(sys.modules[name])['name'] 372 | else: 373 | return name 374 | module_names.sort(key=sort_func) 375 | 376 | for module_name in module_names: 377 | if module_name == __name__: 378 | continue 379 | if module_name in sys.modules: 380 | mod = sys.modules[module_name] 381 | name = addon_utils.module_bl_info(mod)['name'] 382 | text = name + ' (' + sys.modules[module_name].__file__ + ')' 383 | else: 384 | text = module_name 385 | op = layout.operator('wm.addon_reload', text=text) 386 | op.module = module_name 387 | 388 | 389 | def info_menu_draw(self, context): 390 | layout = self.layout 391 | layout.menu('INFO_MT_help_addon_reload', icon='FILE_REFRESH') 392 | 393 | 394 | classes = [ 395 | WM_OT_addon_check_update, 396 | WM_OT_addon_reload, 397 | WM_OT_addon_reload_all, 398 | INFO_MT_help_addon_reload, 399 | ReloadAddonPreferences, 400 | ] 401 | 402 | 403 | def register(): 404 | for cls in classes: 405 | bpy.utils.register_class(cls) 406 | bpy.app.handlers.scene_update_pre.append(scene_update_pre) 407 | bpy.types.USERPREF_HT_header.append(userprefs_header_draw) 408 | bpy.types.INFO_MT_help.append(info_menu_draw) 409 | 410 | 411 | def unregister(): 412 | bpy.types.USERPREF_HT_header.remove(userprefs_header_draw) 413 | bpy.types.INFO_MT_help.remove(info_menu_draw) 414 | bpy.app.handlers.scene_update_pre.remove(scene_update_pre) 415 | for cls in classes[::-1]: 416 | bpy.utils.unregister_class(cls) 417 | 418 | 419 | if __name__ == '__main__': 420 | register() 421 | -------------------------------------------------------------------------------- /render_check_list.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or 2 | # modify it under the terms of the GNU General Public License 3 | # as published by the Free Software Foundation; either version 2 4 | # of the License, or (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU General Public License 12 | # along with this program; if not, write to the Free Software Foundation, 13 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 | 15 | bl_info = { 16 | "name": "render check list + misc", 17 | "author": "bookyakuno", 18 | "version": (1, 0, 3), 19 | "blender": (2, 79), 20 | "location": "Dimensions", 21 | "description": "render check list + misc", 22 | "warning": "", 23 | "wiki_url": "", 24 | "tracker_url": "", 25 | "category": "Render", 26 | } 27 | 28 | import bpy 29 | 30 | from bpy.props import (BoolProperty, 31 | FloatProperty, 32 | FloatVectorProperty, 33 | StringProperty, 34 | PointerProperty) 35 | 36 | from bpy.props import * 37 | 38 | 39 | 40 | 41 | class set_f(bpy.types.Operator): 42 | bl_idname = "object.set_f" 43 | bl_label = "set_f" 44 | bl_description = "Change the number of sheets" 45 | def execute(self, context): 46 | 47 | scn = context.scene 48 | 49 | set_f = scn.frame_start + scn.floatSample 50 | scn.frame_end = set_f 51 | 52 | return {'FINISHED'} 53 | 54 | class now_f(bpy.types.Operator): 55 | bl_idname = "object.now_f" 56 | bl_label = "now_f" 57 | bl_description = "Current number of sheets" 58 | 59 | def execute(self, context): 60 | 61 | scn = context.scene 62 | 63 | scn.floatSample = scn.frame_end - scn.frame_start 64 | 65 | 66 | return {'FINISHED'} 67 | 68 | 69 | 70 | 71 | 72 | class SampleUI_PT_object(bpy.types.Panel): 73 | bl_label = "UI For Sample Prop" 74 | bl_context = "object" 75 | bl_space_type = "PROPERTIES" 76 | bl_region_type = "WINDOW" 77 | 78 | def draw(self, context): 79 | self.layout.prop(context.object.sample_props,"floatSample") 80 | 81 | layout = self.layout 82 | row = layout.row(align=True) 83 | row.operator("object.fff", text="fff") 84 | 85 | 86 | 87 | class render_cycleslots(bpy.types.Operator): 88 | bl_idname = "object.render_cycleslots" 89 | bl_label = "render_cycleslots" 90 | bl_options = {'REGISTER', 'UNDO'} 91 | bl_description = "Slots change every time rendering" 92 | 93 | def execute(self, context): 94 | 95 | 96 | slots = bpy.data.images['Render Result'].render_slots 97 | slots.active_index=(slots.active_index+1)%8 98 | #bpy.ops.render.render('EXECUTION_CONTEXT') 99 | bpy.ops.render.render('INVOKE_DEFAULT') 100 | return {'FINISHED'} 101 | 102 | 103 | class x_y_change(bpy.types.Operator): 104 | bl_idname = "object.x_y_change" 105 | bl_label = "X-Y" 106 | 107 | def execute(self, context): 108 | # main(context) 109 | old_x = bpy.context.scene.render.resolution_x 110 | old_y = bpy.context.scene.render.resolution_y 111 | mainScreen = bpy.context.screen 112 | scene = mainScreen.scene 113 | scene.render.resolution_x = old_y 114 | scene.render.resolution_y = old_x 115 | 116 | return {'FINISHED'} 117 | 118 | 119 | 120 | 121 | def render_final_resolution_ui_z(self, context): 122 | 123 | 124 | 125 | # ===================================================== 126 | # ↓===================================================== 127 | 128 | layout = self.layout 129 | 130 | scene = context.scene 131 | rd = scene.render 132 | 133 | row = layout.row(align=True) 134 | row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label) 135 | row.operator("render.preset_add", text="", icon='ZOOMIN') 136 | row.operator("render.preset_add", text="", icon='ZOOMOUT').remove_active = True 137 | 138 | split = layout.split() 139 | 140 | col = split.column() 141 | sub = col.column(align=True) 142 | subrow = sub.row(align=True) 143 | 144 | # subrow.label(text="Resolution:") 145 | 146 | rd = context.scene.render 147 | layout = self.layout 148 | 149 | final_res_x = (rd.resolution_x * rd.resolution_percentage) / 100 150 | final_res_y = (rd.resolution_y * rd.resolution_percentage) / 100 151 | 152 | if rd.use_border: 153 | final_res_x_border = round( 154 | (final_res_x * (rd.border_max_x - rd.border_min_x))) 155 | final_res_y_border = round( 156 | (final_res_y * (rd.border_max_y - rd.border_min_y))) 157 | subrow.label(text="{} x {} [B:{} x {}]".format( 158 | str(final_res_x)[:-2], str(final_res_y)[:-2], 159 | str(final_res_x_border), str(final_res_y_border))) 160 | else: 161 | subrow.label(text="{} x {}".format( 162 | str(final_res_x)[:-2], str(final_res_y)[:-2])) 163 | 164 | subrow.operator("object.x_y_change", text="", icon="FILE_REFRESH") 165 | 166 | 167 | sub.prop(rd, "resolution_x", text="X") 168 | sub.prop(rd, "resolution_y", text="Y") 169 | sub.prop(rd, "resolution_percentage", text="") 170 | sub.separator() 171 | 172 | 173 | row = col.row() 174 | row.prop(rd, "use_border", text="", icon="BORDER_RECT") 175 | sub = row.row() 176 | sub.active = rd.use_border 177 | sub.prop(rd, "use_crop_to_border", text="",icon="RENDER_REGION") 178 | 179 | 180 | scn = context.scene 181 | tt = scn.frame_end - scn.frame_start 182 | # row = layout.row(align=True) 183 | sub.label() 184 | col = split.column() 185 | sub = col.column(align=True) 186 | sub.label(text="Frame Range: " + str(tt)) 187 | # ===================================================== 188 | 189 | sub.prop(scene, "frame_start") 190 | sub.prop(scene, "frame_end") 191 | sub.separator() 192 | sub.prop(scene, "frame_current") 193 | sub.separator() 194 | 195 | subrow = sub.row(align=True) 196 | 197 | subrow.operator("object.now_f", text="",icon="EYEDROPPER") 198 | subrow.operator("object.set_f", text="",icon="FILE_TICK") 199 | subrow.prop(scene, "floatSample", text="") 200 | 201 | 202 | 203 | 204 | # ↑===================================================== 205 | # ===================================================== 206 | 207 | 208 | 209 | layout = self.layout 210 | scene = context.scene 211 | cscene = scene.cycles 212 | rd = context.scene.render 213 | 214 | 215 | 216 | col = layout.column(align=True) 217 | row = col.row(align=True) 218 | 219 | 220 | 221 | 222 | row.operator_context = 'EXEC_DEFAULT' 223 | row.operator("render.render", text="Render", icon='RENDER_STILL') 224 | row.operator("object.render_cycleslots", text="Slot", icon="RENDER_REGION") 225 | row.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True 226 | row.prop(rd, "use_lock_interface", icon_only=True) 227 | row = col.row(align=True) 228 | 229 | 230 | 231 | 232 | 233 | 234 | # col = split.column() 235 | row = col.row(align=True) 236 | 237 | row.prop(cscene, "film_transparent", text="BG Alpha", icon="WORLD") 238 | row.prop(rd, "use_overwrite", icon="ORTHO") 239 | 240 | split = layout.split() 241 | row = col.row(align=True) 242 | row.prop(context.scene, 'save_after_render', text='Auto Save Image', icon="IMAGE_DATA", toggle=False) 243 | 244 | row.prop(cscene, "use_square_samples", icon="IPO_QUAD") 245 | 246 | 247 | 248 | 249 | 250 | row = col.row(align=True) 251 | row.prop(rd, "use_stamp", icon="OUTLINER_DATA_FONT") 252 | row.prop(cscene, "samples", text="samples") 253 | 254 | 255 | row = col.row(align=True) 256 | row.prop(rd, "use_persistent_data", text="Persistent Images") 257 | 258 | row.prop(cscene, "preview_samples", text="Preview") 259 | 260 | 261 | # draw_samples_info(layout, context) 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | # ===================================================== 272 | 273 | # ===================================================== 274 | 275 | sub.label() 276 | col = split.column() 277 | sub = col.column(align=True) 278 | 279 | 280 | sub.prop(scene, "frame_step") 281 | 282 | 283 | 284 | 285 | 286 | sub.label(text="Frame Rate:") 287 | 288 | self.draw_framerate(sub, rd) 289 | 290 | 291 | sub.label() 292 | col = split.column() 293 | sub = col.column(align=True) 294 | 295 | 296 | subrow = sub.row(align=True) 297 | subrow.label(text="Time Remapping:") 298 | subrow = sub.row(align=True) 299 | subrow.prop(rd, "frame_map_old", text="Old") 300 | subrow.prop(rd, "frame_map_new", text="New") 301 | 302 | 303 | sub.label(text="Aspect Ratio:") 304 | sub.prop(rd, "pixel_aspect_x", text="X") 305 | sub.prop(rd, "pixel_aspect_y", text="Y") 306 | 307 | 308 | # ===================================================== 309 | 310 | # ===================================================== 311 | 312 | 313 | # ===================================================== 314 | 315 | # ===================================================== 316 | 317 | 318 | original_draw_func = None 319 | 320 | def register(): 321 | bpy.utils.register_module(__name__) 322 | 323 | global original_draw_func 324 | original_draw_func = bpy.types.RENDER_PT_dimensions.draw 325 | bpy.types.RENDER_PT_dimensions.draw = render_final_resolution_ui_z 326 | 327 | 328 | 329 | bpy.types.Scene.floatSample = IntProperty(name="FloatPropSample", description="Number of sheets to be rendered", min=0, default=0) 330 | 331 | 332 | 333 | 334 | def unregister(): 335 | bpy.types.RENDER_PT_dimensions.remove(render_final_resolution_ui_z) 336 | 337 | 338 | 339 | 340 | if __name__ == "__main__": 341 | register() 342 | -------------------------------------------------------------------------------- /rigify_select_pie_menu.py: -------------------------------------------------------------------------------- 1 | ########################################### 2 | 3 | # RigifyPicker Addon download Link 4 | # 5 | # Downloads | Salva Artero 6 | # http://salvadorartero.com/downloads/ 7 | 8 | ########################################### 9 | # 10 | # THIS SCRIPT IS LICENSED UNDER GPL, 11 | # please read the license block. 12 | # 13 | # ##### BEGIN GPL LICENSE BLOCK ##### 14 | # 15 | # This program is free software; you can redistribute it and/or 16 | # modify it under the terms of the GNU General Public License 17 | # as published by the Free Software Foundation; either version 2 18 | # of the License, or (at your option) any later version. 19 | # 20 | # This program is distributed in the hope that it will be useful, 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | # GNU General Public License for more details. 24 | # 25 | # You should have received a copy of the GNU General Public License 26 | # along with this program; if not, write to the Free Software Foundation, 27 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 28 | # 29 | # ##### END GPL LICENSE BLOCK ##### 30 | 31 | bl_info = { 32 | "name": "rigify select Pie menu", 33 | "author": "Bookyakuno", 34 | "version": (1, 0, 0), 35 | "blender": (2,77,0), 36 | "description": "rigify rig Quick Select. ", 37 | "location": "Pose mode > Ctrl + W", 38 | "category": "Pie menu", 39 | "warning": "Use RigifyPicker Addon !! http://salvadorartero.com/downloads/" 40 | } 41 | 42 | 43 | import bpy 44 | from bpy.types import Menu 45 | 46 | 47 | 48 | import bpy, os 49 | from bpy.types import Menu, Header 50 | from bpy.props import IntProperty, FloatProperty, BoolProperty 51 | import bmesh 52 | from mathutils import * 53 | import math 54 | 55 | 56 | 57 | class rigify_select_Prefs(bpy.types.AddonPreferences): 58 | bl_idname = __name__ 59 | bpy.types.Scene.Enable_Tab_01 = bpy.props.BoolProperty(default=False) 60 | 61 | 62 | def draw(self, context): 63 | layout = self.layout 64 | layout.prop(context.scene, "Enable_Tab_01", text="Info", icon="QUESTION") 65 | if context.scene.Enable_Tab_01: 66 | 67 | row = layout.row() 68 | layout.label(text="timeline") 69 | layout.label(text="RigifyPicker Addon download Link") 70 | 71 | 72 | row.operator("wm.url_open", text="Downloads | Salva Artero").url = "http://salvadorartero.com/downloads/" 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | ################## 85 | # Pie Menu Class # 86 | ################## 87 | class rigify_select_x(Menu): 88 | bl_idname = "object.rigify_select" 89 | bl_label = "Add Modifier" 90 | 91 | def draw(self, context): 92 | layout = self.layout 93 | pie = layout.menu_pie() 94 | 95 | #4 - LEFT 96 | pie.operator("operador.mano_r", text="hand.ik.R", icon='HAND') 97 | #6 - RIGHT 98 | pie.operator("operador.mano_l", text="hand.ik.L", icon='HAND') 99 | #2 - BOTTOM 100 | pie.operator("operador.torso", text="Torso", icon='MONKEY') 101 | #8 - TOP 102 | pie.operator("operador.cabeza", text="Head", icon='BLENDER') 103 | #7 - TOP - LEFT 104 | pie.operator("operador.rodilla_r", text="foot_ROOL.R", icon='CURSOR') 105 | #9 - TOP - RIGHT 106 | pie.operator("operador.rodilla_l", text="foot_ROOL.L", icon='CURSOR') 107 | #1 - BOTTOM - LEFT 108 | pie.operator("operador.pie_r", text="foot.R", icon='EXPORT') 109 | #3 - BOTTOM - RIGHT 110 | pie.operator("operador.pie_l", text="foot.L", icon='EXPORT') 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | ############ 120 | # Register # 121 | ############ 122 | addon_keymaps = [] 123 | def register(): 124 | bpy.utils.register_class(rigify_select_x) 125 | 126 | 127 | ### Keymap ### 128 | wm = bpy.context.window_manager 129 | 130 | km = wm.keyconfigs.addon.keymaps.new(name="Pose") 131 | kmi = km.keymap_items.new("wm.call_menu_pie", "W", "PRESS", ctrl=True) 132 | kmi.properties.name="object.rigify_select" 133 | addon_keymaps.append(km) 134 | 135 | 136 | ############## 137 | # Unregister # 138 | ############## 139 | def unregister(): 140 | bpy.utils.unregister_class(rigify_select_x) 141 | 142 | ### Keymap ### 143 | for km in addon_keymaps: 144 | for kmi in km.keymap_items: 145 | km.keymap_items.remove(kmi) 146 | 147 | wm.keyconfigs.addon.keymaps.remove(km) 148 | 149 | # clear the list 150 | del addon_keymaps[:] 151 | 152 | 153 | if __name__ == "__main__": 154 | register() 155 | 156 | #bpy.ops.wm.call_menu_pie(name="object.rigify_select") 157 | -------------------------------------------------------------------------------- /vert_circle_x.py: -------------------------------------------------------------------------------- 1 | # ##### BEGIN GPL LICENSE BLOCK ##### 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # ##### END GPL LICENSE BLOCK ##### 18 | bl_info = { 19 | "name": "vert_circle_x", 20 | "author": "bookyakuno", 21 | "version": (1,2), 22 | "location": "alt + Y or object.vert_circle_x", 23 | "description": "need loop tool addon circle", 24 | "warning": "", 25 | "category": "3D View"} 26 | 27 | import bpy 28 | 29 | 30 | class vert_circle_x(bpy.types.Operator): 31 | """Tooltip""" 32 | bl_idname = "object.vert_circle_x" 33 | bl_label = "vert_circle_x" 34 | bl_options = {'REGISTER', 'UNDO'} 35 | 36 | def execute(self, context): 37 | 38 | # before_Apivot = bpy.context.space_data.pivot_point 39 | automerge_setting = bpy.context.scene.tool_settings.use_mesh_automerge 40 | bpy.context.scene.tool_settings.use_mesh_automerge = False 41 | # bpy.data.scenes['Scene'].tool_settings.use_mesh_automerge = False 42 | 43 | bpy.ops.mesh.select_more() 44 | bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={"value":(0, 0, 0)}) 45 | bpy.ops.mesh.looptools_circle(custom_radius=False, fit='best', flatten=True, influence=100, lock_x=False, lock_y=False, lock_z=False, radius=1, regular=True) 46 | 47 | bpy.context.space_data.pivot_point = 'INDIVIDUAL_ORIGINS' # あとで複数の作った円を一括してスケール調整できるよう、ピボットを「それぞれの原点」に変更 48 | 49 | bpy.ops.transform.resize(value=(0.5, 0.5, 0.5),release_confirm=False) 50 | 51 | # bpy.ops.transform.resize("INVOKE_DEFAULT") # 実行したあとすぐにスケール調整ジェスチャーが始まる。自分としては使わないのでオフ。使いたい場合は「行頭の「# 」を取る 52 | 53 | bpy.context.user_preferences.edit.use_global_undo = True # 使っているLoop Toolsアドオンのcircleが、グローバルアンドゥをオフにするようになっているので、最後にグローバルアンドゥがオンになるように修正 54 | 55 | # bpy.context.space_data.pivot_point = before_pivot 56 | bpy.context.scene.tool_settings.use_mesh_automerge = automerge_setting 57 | 58 | 59 | return {'FINISHED'} 60 | 61 | 62 | 63 | addon_keymaps = [] 64 | def register(): 65 | bpy.utils.register_module(__name__) 66 | wm = bpy.context.window_manager 67 | 68 | km = wm.keyconfigs.addon.keymaps.new(name = 'Mesh') 69 | kmi = km.keymap_items.new(vert_circle_x.bl_idname, 'Y', 'PRESS', alt=True) 70 | addon_keymaps.append((km, kmi)) 71 | 72 | def unregister(): 73 | bpy.utils.unregister_module(__name__) 74 | for km, kmi in addon_keymaps: 75 | km.keymap_items.remove(kmi) 76 | addon_keymaps.clear() 77 | -------------------------------------------------------------------------------- /vtools_libraryManager.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "vtools - texture library manager", 3 | "author": "Antonio Mendozam,Bookyakuno (2.8Update) ", 4 | "version": (0, 0, 3), 5 | "blender": (2, 80, 0), 6 | "location": "View3D > Property Shelf > Texture libraries panel (sculpt mode)", 7 | "warning": "", 8 | "description": "Load and unload image libraries", 9 | "category": "Paint", 10 | } 11 | 12 | 13 | import bpy 14 | import os 15 | import sys 16 | import time 17 | 18 | 19 | 20 | from bpy.props import (StringProperty,BoolProperty,IntProperty,FloatProperty,FloatVectorProperty,EnumProperty,PointerProperty) 21 | from bpy.types import (Menu, Panel,Operator,AddonPreferences, PropertyGroup) 22 | from bpy_extras.io_utils import ImportHelper 23 | 24 | 25 | 26 | #---- Definitions -----# 27 | 28 | def findImage (p_Name): 29 | 30 | found = False 31 | 32 | for img in bpy.data.textures: 33 | if img.name == p_Name: 34 | found = True 35 | break 36 | 37 | return found 38 | 39 | def selectImages (p_fileList): 40 | 41 | file_list = p_fileList 42 | img_list = [item for item in file_list if item[-3:] == 'png' or item[-3:] == 'jpg' or item[-4:] == 'jpeg' or item[-3:] == 'tga'] 43 | #img_list = [item for item in file_list if item[-3:] == 'jpg' or item[-4:] == 'jpeg'] 44 | return img_list 45 | 46 | def image_batchImport(p_dir): 47 | 48 | 49 | if os.path.isdir(p_dir): 50 | file_list = sorted(os.listdir(p_dir)) 51 | img_list = selectImages (file_list) 52 | 53 | imgLimits = 25 54 | cont = 0 55 | for img in img_list: 56 | dirImage = os.path.join(p_dir, img) 57 | tName = os.path.basename(os.path.splitext(img)[0]) 58 | 59 | if findImage(tName) == False: 60 | nImage = bpy.data.images.load(dirImage) 61 | nT = bpy.data.textures.new(name=tName,type='IMAGE') 62 | bpy.data.textures[tName].image = nImage 63 | #cont += 1 64 | 65 | #if cont >= imgLimits: 66 | # break 67 | 68 | 69 | def image_batchRemove(p_dir): 70 | 71 | 72 | if os.path.isdir(p_dir): 73 | file_list = sorted(os.listdir(p_dir)) 74 | img_list = selectImages (file_list) 75 | 76 | 77 | 78 | for img in img_list: 79 | dirImage = os.path.join(p_dir, img) 80 | tName = os.path.basename(os.path.splitext(img)[0]) 81 | 82 | 83 | 84 | for tex in bpy.data.textures: 85 | if tex.name == tName: 86 | if tex.type == 'IMAGE': 87 | image = tex.image 88 | imgName = image.name 89 | tex.user_clear() 90 | bpy.data.textures.remove(tex) 91 | bpy.data.images[imgName].user_clear() 92 | bpy.data.images.remove(bpy.data.images[imgName]) 93 | 94 | 95 | def image_DeleteNonExisting(p_dir): 96 | 97 | if os.path.isdir(p_dir): 98 | for img in bpy.data.images: 99 | dirImage = os.path.join(p_dir, img.name) 100 | if not os.path.isfile(dirImage): 101 | tName = os.path.basename(os.path.splitext(img.name)[0]) 102 | 103 | texID = bpy.data.textures.find(tName) 104 | if texID != -1: 105 | tex = bpy.data.textures[texID] 106 | if tex.type == 'IMAGE': 107 | image = tex.image 108 | tex.user_clear() 109 | bpy.data.textures.remove(tex) 110 | img.user_clear() 111 | bpy.data.images.remove(img) 112 | 113 | 114 | def findUserSysPath(): 115 | 116 | userPath = '' 117 | 118 | def readLibraryDir(): 119 | dir = '' 120 | fileDir = os.path.join(bpy.utils.resource_path('USER'), "scripts\\presets\\texture_library.conf") 121 | if os.path.isfile(fileDir): 122 | file = open(fileDir, 'r') 123 | dir = file.read() 124 | file.close() 125 | return dir 126 | 127 | 128 | #-----------------------# 129 | 130 | 131 | 132 | def deleteNonExistingLibraries(): 133 | 134 | i = 0 135 | cont = 0 136 | while i < len(bpy.context.scene.textureLibrary): 137 | l = bpy.context.scene.textureLibrary[i] 138 | if not os.path.isdir(l.dirPath): 139 | removeLibrary(i) 140 | i = -1 141 | 142 | i += 1 143 | 144 | def findSubLibraries(p_parentLibrary): 145 | existing = False 146 | dir = p_parentLibrary 147 | 148 | if os.path.isdir(dir): 149 | file_list = sorted(os.listdir(dir)) 150 | for item in file_list: 151 | lib_dir = os.path.join(dir,item) 152 | if os.path.isdir(lib_dir): 153 | existing = False 154 | for l in bpy.context.scene.textureLibrary: 155 | if l.dirPath == lib_dir: 156 | existing = True 157 | 158 | if not existing: 159 | newLibrary = bpy.context.scene.textureLibrary.add() 160 | newLibrary.name = os.path.basename(os.path.normpath(lib_dir)) 161 | newLibrary.dirPath = lib_dir 162 | newLibrary.loaded = False 163 | newLibrary.parent = p_parentLibrary 164 | 165 | sortLibrary(newLibrary, len(bpy.context.scene.textureLibrary)-1) 166 | 167 | 168 | 169 | def loadLibrary(p_filePath): 170 | 171 | 172 | existing = False 173 | loaded = False 174 | deleteNonExistingLibraries() 175 | 176 | for l in bpy.context.scene.textureLibrary: 177 | if l.dirPath == p_filePath: 178 | existing = True 179 | 180 | if not existing: 181 | 182 | if os.path.isfile(p_filePath): 183 | fileName = os.path.basename(os.path.normpath(p_filePath)) 184 | p_filePath = p_filePath.replace(fileName,"") 185 | 186 | 187 | if os.path.isdir(p_filePath): 188 | newLibrary = bpy.context.scene.textureLibrary.add() 189 | newLibrary.name = os.path.basename(os.path.normpath(p_filePath)) 190 | newLibrary.dirPath = p_filePath 191 | newLibrary.loaded = False 192 | newLibrary.parent = "None" 193 | 194 | findSubLibraries(p_filePath) 195 | loaded = True 196 | 197 | return loaded 198 | 199 | def removeLibrary(p_Id): 200 | 201 | idSelected = p_Id 202 | numItems = len(bpy.context.scene.textureLibrary) 203 | 204 | if numItems > 0 and idSelected != -1: 205 | library = bpy.context.scene.textureLibrary[idSelected] 206 | 207 | if library.parent == "None" : 208 | i = 0 209 | while i < len(bpy.context.scene.textureLibrary): 210 | l = bpy.context.scene.textureLibrary[i] 211 | if l.parent != "None" and l.parent == library.dirPath: 212 | bpy.context.scene.textureLibrary[i].loaded = False 213 | bpy.context.scene.textureLibrary.remove(i) 214 | i = 0 215 | 216 | i += 1 217 | 218 | 219 | if idSelected == (len(bpy.context.scene.textureLibrary)-1): 220 | bpy.context.scene.textureLibrary_ID_index = bpy.context.scene.textureLibrary_ID_index - 1 221 | 222 | bpy.context.scene.textureLibrary[idSelected].loaded = False 223 | bpy.context.scene.textureLibrary.remove(idSelected) 224 | 225 | 226 | def sortLibrary(p_library, p_id): 227 | 228 | idCont = p_id 229 | if p_library.parent != "None": 230 | while idCont > 0: 231 | prevLib = bpy.context.scene.textureLibrary[idCont - 1] 232 | if prevLib.parent != p_library.parent and prevLib.dirPath != p_library.parent: 233 | bpy.context.scene.textureLibrary.move(idCont, idCont - 1) 234 | idCont = idCont - 1 235 | p_library = bpy.context.scene.textureLibrary[idCont] 236 | else: 237 | idCont = -100 238 | break 239 | 240 | 241 | 242 | 243 | #-------- library collection operator ----------------------- # 244 | 245 | 246 | class VTOOLS_OP_addLibrary(bpy.types.Operator, ImportHelper): 247 | bl_idname = "vtools.addlibrary" 248 | bl_label = "add new library" 249 | bl_description = "add a new library and every folder within it" 250 | 251 | def addLibrary(self, context, p_filePath): 252 | loaded = loadLibrary(p_filePath) 253 | if loaded == False: 254 | self.report({'WARNING', 'INFO'}, "No valid directory path. Keep filename slot empty") 255 | return {'FINISHED'} 256 | 257 | def execute(self,context): 258 | return self.addLibrary(context, self.filepath) 259 | 260 | class VTOOLS_OP_removeLibrary(bpy.types.Operator): 261 | bl_idname = "vtools.removelibrary" 262 | bl_label = "remove library" 263 | bl_description = "remove the selected library from the list" 264 | 265 | def execute(self,context): 266 | 267 | removeLibrary(bpy.context.scene.textureLibrary_ID_index) 268 | return {'FINISHED'} 269 | 270 | 271 | 272 | class VTOOLS_OP_cleanLibraries(bpy.types.Operator): 273 | bl_idname = "vtools.cleanlibraries" 274 | bl_label = "clean libraries" 275 | bl_description = "remove every library" 276 | 277 | def execute(self,context): 278 | 279 | 280 | while len(bpy.context.scene.textureLibrary) > 0: 281 | lib = bpy.context.scene.textureLibrary[0] 282 | 283 | if os.path.isdir(lib.dirPath): 284 | image_batchRemove(lib.dirPath) 285 | bpy.context.scene.textureLibrary.remove(0) 286 | 287 | return {'FINISHED'} 288 | 289 | 290 | class VTOOLS_OP_refreshLibraries(bpy.types.Operator): 291 | 292 | bl_idname = "vtools.refreshlibraries" 293 | bl_label = "refresh libraries" 294 | bl_description = "refresh existing libraries" 295 | 296 | def execute(self,context): 297 | 298 | deleteNonExistingLibraries() 299 | for l in bpy.context.scene.textureLibrary: 300 | 301 | 302 | #reload images 303 | if l.loaded == True: 304 | image_DeleteNonExisting(l.dirPath) 305 | image_batchImport(l.dirPath) 306 | 307 | #reload folders 308 | if l.parent == "None": 309 | dir = l.dirPath 310 | findSubLibraries(dir) 311 | 312 | return {'FINISHED'} 313 | 314 | 315 | 316 | 317 | #------------ CALLBACKS -------------# 318 | 319 | def activeSelected(p_name): 320 | 321 | cont = 0 322 | for item in bpy.context.scene.textureLibrary: 323 | if item.name == p_name: 324 | bpy.context.scene.textureLibrary_ID_index = cont 325 | break 326 | 327 | cont += 1 328 | 329 | 330 | def callback_loadLibrary(self, value): 331 | library = self 332 | 333 | if self.loaded: 334 | #load library 335 | 336 | image_batchImport(self.dirPath) 337 | if self.parent == "None": 338 | for l in bpy.context.scene.textureLibrary: 339 | if l.parent == self.dirPath: 340 | l.loaded = True 341 | 342 | else: 343 | #unload library 344 | if self.parent == "None": 345 | for l in bpy.context.scene.textureLibrary: 346 | if l.parent == self.dirPath: 347 | l.loaded = False 348 | 349 | 350 | image_batchRemove(self.dirPath) 351 | 352 | activeSelected(library.name) 353 | 354 | #--------------------------------------# 355 | 356 | #----------- UI libraries --------------------# 357 | 358 | class VTOOLS_UIL_textureLibraryUI(bpy.types.UIList): 359 | 360 | def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 361 | 362 | row = layout.row(align = True) 363 | 364 | if item.parent == "None": 365 | 366 | if item.loaded == True: 367 | row.prop(item, "loaded", text="",emboss = False, icon='HIDE_OFF' ) 368 | 369 | else: 370 | row.prop(item, "loaded", text="",emboss = False, icon='HIDE_ON') 371 | 372 | row.label(text="",icon="SHORTDISPLAY") 373 | row.label(item.name.upper()) 374 | else: 375 | subLibraryName = " " + item.name 376 | row.scale_x = 0.5 377 | 378 | for i in range(0, 7): 379 | row.separator() 380 | 381 | 382 | if item.loaded == True: 383 | row.prop(item, "loaded", text="",emboss = False, icon='HIDE_OFF' ) 384 | 385 | else: 386 | row.prop(item, "loaded", text="",emboss = False, icon='HIDE_ON') 387 | 388 | row.label(subLibraryName) 389 | 390 | class VTOOLS_CC_textureLibrary(bpy.types.PropertyGroup): 391 | 392 | ID = IntProperty() 393 | name = StringProperty(default="") 394 | parent = StringProperty(default="None") 395 | loaded = BoolProperty(default=False, update=callback_loadLibrary) 396 | dirPath = StringProperty(default="") 397 | 398 | 399 | 400 | 401 | #-------------------------------# 402 | 403 | 404 | class LBM_PN_LibraryManager(bpy.types.Panel): 405 | bl_label = "Texture library" 406 | #bl_category = "LibraryManager" 407 | #bl_context = 'sculptmode' 408 | bl_space_type = 'VIEW_3D' 409 | bl_region_type = 'UI' 410 | bl_category = 'Tools' 411 | bl_options = {'DEFAULT_CLOSED'} 412 | 413 | 414 | 415 | @classmethod 416 | def poll(cls, context): 417 | return (context.sculpt_object or context.vertex_paint_object or context.vertex_paint_object or context.image_paint_object) 418 | 419 | def draw(self,context): 420 | 421 | layout = self.layout 422 | row = layout.row() 423 | 424 | col = row.column() 425 | col.template_list('VTOOLS_UIL_textureLibraryUI', "ID", bpy.context.scene, "textureLibrary", bpy.context.scene, "textureLibrary_ID_index", rows=5, type='DEFAULT') 426 | 427 | col = row.column(align=True) 428 | col.operator(VTOOLS_OP_addLibrary.bl_idname, text = "", icon = "ADD") 429 | col.operator(VTOOLS_OP_removeLibrary.bl_idname, text = "", icon = "REMOVE") 430 | col.operator(VTOOLS_OP_refreshLibraries.bl_idname, text = "", icon = "FILE_REFRESH") 431 | col.operator(VTOOLS_OP_cleanLibraries.bl_idname, text = "", icon = "X") 432 | 433 | 434 | 435 | 436 | classes = { 437 | VTOOLS_OP_addLibrary, 438 | VTOOLS_OP_removeLibrary, 439 | VTOOLS_OP_cleanLibraries, 440 | VTOOLS_OP_refreshLibraries, 441 | VTOOLS_UIL_textureLibraryUI, 442 | VTOOLS_CC_textureLibrary, 443 | LBM_PN_LibraryManager, 444 | 445 | } 446 | 447 | 448 | def register(): 449 | for cls in classes: 450 | bpy.utils.register_class(cls) 451 | 452 | 453 | bpy.types.Scene.textureLibrary = bpy.props.CollectionProperty(type=VTOOLS_CC_textureLibrary) 454 | bpy.types.Scene.textureLibrary_ID_index = bpy.props.IntProperty() 455 | 456 | 457 | 458 | def unregister(): 459 | for cls in classes: 460 | bpy.utils.unregister_class(cls) 461 | 462 | del bpy.types.Scene.textureLibrary 463 | del bpy.types.Scene.textureLibrary_ID_index 464 | 465 | 466 | 467 | if __name__ == "__main__": 468 | register() 469 | -------------------------------------------------------------------------------- /w_pie.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bookyakuno/-Blender-/baa2945d72379f2cf4b6da5ae20a7453dfdb0856/w_pie.zip -------------------------------------------------------------------------------- /w_pie/TranslationDictionary.csv: -------------------------------------------------------------------------------- 1 | "このアドオンはWazou Pie Menuをコンパクトにし、さらに機能を追加したアドオンです。","This add-on is a compact modified 'wazou pie menu'and added functions." 2 | "右クリックをパイメニューで拡張するアドオン。","Extend Right click with pie menu." 3 | "必要な機能だけ・アクセスしやすく・使いやすいをコンセプトに、","Only necessary functions - Accessible - Easy to use concept as a concept," 4 | "パイメニューを右クリックを中心にキー設定をしたものです。","Key setting with centering on Right click." 5 | "その他オブジェクト追加やUVエディターでの選択、機能追加などもあります。","Other, addition of objects, selection with UV editor, fine addition function, etc." 6 | "左選択を前提に作っているので、ユーザー設定のセレクトボタンを「左」に変えてください!!","Change the the system setting select button to the LEFT!!" 7 | "(選択マウスは左という前提で記入します)","(SELECTMOUSE is write it as a LEFT)" 8 | "ーショートカットー","-Shortcut-" 9 | "ー設定ー","-Setting-" 10 | "ー使用するアドオンー","-Use Addon-" 11 | "Ctrl + Fキーでのmisc_pieで、下記のアドオンにアクセスできます。","You can access the following addon with Pie misc with Ctrl + F." 12 | "右クリックキーでのメッシュ選択モードで、下記のアドオンにアクセスできます。","You can access the following addon In the mesh select mode with the Right click." 13 | "円化・ブリッジなどのモデリング補助アドオン(元からBlenderに無効化状態で同梱されています)。","Mesh modeling toolkit (Installed by default. But it is disabled). " 14 | "ブーリアンを簡単にするアドオン。(元からBlenderに無効化状態で同梱されています。)","Boolean toolkit (Installed by default. But it is disabled). " 15 | "複数オブジェクトのUVを一括編集するアドオン。","a quick way to create one UV Layout for multiple objects." 16 | "カーソル/原点","Cursor/Origin" 17 | "雑多/モデリングツールキット","Misc/Modeling toolkit" 18 | "マルチビュー/その他","Views misc" 19 | "ライブ展開","Live Unwrap" 20 | "ノーマル方向によるプロジェクション","Project From Normal Vector" 21 | "複数オブジェクトのUV編集","Multi UV" 22 | "裏面の選択制限","Limit to Visible" 23 | "編集/オブジェクトモード","Edit/Object" 24 | "直前の履歴オプション","Setting" 25 | "横にウィンドウ分割","Split Window H" 26 | "縦にウィンドウ分割","Split Window V" 27 | "ウィンドウ同士を結合","Merge Window" 28 | "実行後にマージしたいウィンドウをクリックします。","Click on the window you want to merge after execution." 29 | "NLAエディター","NLA Editor" 30 | "アウトライナー","Outliner" 31 | "シーケンスエディター","Sequence Editor" 32 | "3Dビュー","VIEW 3D" 33 | "UV/画像エディター","Image Editor" 34 | "ノードエディター","Node Editor" 35 | "テキストエディター","Text Editor" 36 | "グラフエディター","Graph Editor" 37 | "ユーザー設定","User Preferences" 38 | "ドープシート","Dope Sheet" 39 | "Pythonコンソール","Python Console" 40 | "動画クリップエディター","Movie Clip Editor" 41 | -------------------------------------------------------------------------------- /w_pie/misc_pie.py: -------------------------------------------------------------------------------- 1 | import bpy, os 2 | from bpy.types import Menu, Header 3 | from bpy.props import IntProperty, FloatProperty, BoolProperty 4 | import bmesh 5 | from mathutils import * 6 | import math 7 | 8 | 9 | 10 | 11 | # misc pie menuz 12 | class misc_pie(Menu): 13 | bl_idname = "pie.misc_pie" 14 | bl_label = "Pie Misc" 15 | 16 | def draw(self, context): 17 | layout = self.layout 18 | pie = layout.menu_pie() 19 | #4 - LEFT 20 | pie.operator("object.modifier_add", text="Bevel" , icon='MOD_BEVEL').type='BEVEL' 21 | #6 - RIGHT 22 | pie.operator("object.make_links_data", icon='MATERIAL').type='MATERIAL' 23 | #2 - BOTTOM 24 | pie.operator("object.modifier_add", text="Array" , icon='MOD_ARRAY').type='ARRAY' 25 | # #8 - TOP 26 | pie.operator("object.freeze_transformation", icon='MANIPUL') 27 | # #7 - TOP - LEFT 28 | pie.operator("object.modifier_add", text="Solidify" , icon='MOD_SOLIDIFY').type='SOLIDIFY' 29 | # #9 - TOP - RIGHT 30 | pie.operator("btool.auto_union", icon='ROTATECOLLECTION' , text="Union").solver='BMESH' 31 | # #1 - BOTTOM - LEFT 32 | pie.operator("object.join", icon='GROUP') 33 | # #3 - BOTTOM - RIGHT 34 | pie.operator("btool.auto_difference", icon='ROTACTIVE' , text="Difference").solver='BMESH' 35 | 36 | 37 | 38 | 39 | 40 | 41 | # misc edit pie menu 42 | class misc_edit_pie(Menu): 43 | bl_idname = "pie.misc_edit_pie" 44 | bl_label = "Pie Misc Edit" 45 | 46 | def draw(self, context): 47 | layout = self.layout 48 | pie = layout.menu_pie() 49 | #4 - LEFT 50 | pie.operator("mesh.looptools_bridge", icon='NODE_INSERT_OFF') 51 | #6 - RIGHT 52 | pie.operator("mesh.bevel", icon='MOD_BEVEL') 53 | #2 - BOTTOM 54 | pie.operator("mesh.extrude_region_shrink_fatten", icon='FACESEL') 55 | # #8 - TOP 56 | pie.operator("mesh.looptools_relax", icon='MOD_LATTICE') 57 | # #7 - TOP - LEFT 58 | pie.operator("mesh.looptools_circle", icon='MESH_CIRCLE') 59 | # #9 - TOP - RIGHT 60 | pie.operator("mesh.remove_doubles", icon='AUTOMERGE_ON').threshold=0.01 61 | # #1 - BOTTOM - LEFT 62 | pie.operator("mesh.separate", icon='MOD_UVPROJECT').type='SELECTED' 63 | # #3 - BOTTOM - RIGHT 64 | pie.operator("mesh.subdivide", icon='OUTLINER_OB_LATTICE') 65 | 66 | # Menu srt 67 | ################################################### 68 | 69 | ################################################### 70 | group = pie.column() 71 | box = group.box() 72 | row = box.row() 73 | box.menu("VIEW3D_MT_edit_mesh_vertices", icon="LOOPSEL") 74 | box.scale_x = 3 75 | 76 | group.separator() 77 | 78 | box = group.box() 79 | box.operator("mesh.rip_move", icon="MOD_NORMALEDIT") 80 | ################################################### 81 | 82 | ################################################### 83 | box = pie.split().column() 84 | ################################################### 85 | 86 | ################################################### 87 | group = pie.column() 88 | box = group.box() 89 | row = box.row() 90 | 91 | group.separator() 92 | 93 | ################################################### 94 | box = group.box() 95 | box.menu("VIEW3D_MT_edit_mesh_faces", icon="FACESEL") 96 | box = group.box() 97 | row = box.row() 98 | row.operator("mesh.extrude_faces_move", icon="UV_ISLANDSEL") 99 | row.operator("mesh.flip_normals", icon="UV_ISLANDSEL") 100 | box.scale_x = 1 101 | 102 | ################################################### 103 | group = pie.column() 104 | box = group.box() 105 | row = box.row() 106 | box.menu("VIEW3D_MT_edit_mesh_edges", icon="EDGESEL") 107 | box.scale_x = 3 108 | 109 | group.separator() 110 | 111 | box = group.box() 112 | ################################################### 113 | # Menu end 114 | 115 | 116 | 117 | 118 | class freeze_transformation(bpy.types.Operator): 119 | bl_idname = 'object.freeze_transformation' 120 | bl_label = 'Apply' 121 | bl_description = 'Freeze Transformation' 122 | bl_options = {'REGISTER', 'UNDO'} 123 | 124 | def execute(self, context): 125 | bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) 126 | 127 | return {'FINISHED'} 128 | -------------------------------------------------------------------------------- /w_pie/uv_pie.py: -------------------------------------------------------------------------------- 1 | 2 | import bpy 3 | import mathutils 4 | from mathutils import Vector, Matrix 5 | import bpy, os 6 | from bpy.types import Menu, Header 7 | from bpy.props import IntProperty, FloatProperty, BoolProperty 8 | import bmesh 9 | from mathutils import * 10 | import math 11 | 12 | 13 | # 14 | # bl_info = { 15 | # "name": "Jimmy_pie_uv", 16 | # "description": "Jimmy's UV select mode pie menu", 17 | # "category": "3D View", 18 | # } 19 | 20 | 21 | # Operators 22 | 23 | 24 | 25 | 26 | ################################################# 27 | 28 | ################################################# 29 | # uv_prj_from_normal 30 | # bl_info = { 31 | # 'name': 'Project From Normal', 32 | # 'author': 'chaosdesk', 33 | # 'version': (0,1), 34 | # 'blender': (2, 6, 9), 35 | # "location": "View3D > UV Mapping > Project From Normal", 36 | # 'description': 'Project from average normal of all Face', 37 | # 'warning': '', 38 | # 'wiki_url': '', 39 | # 'tracker_url': 'http://chaosdesk.blog123.fc2.com/', 40 | # "category": "UV"} 41 | 42 | MAX_LOCATION = 1 43 | 44 | 45 | class ProjectFromNormal(object): 46 | def __init__(self): 47 | bpy.ops.object.mode_set(mode='OBJECT') 48 | 49 | self.current_obj = bpy.context.selected_objects[0] 50 | self.mesh = self.current_obj.data 51 | self.select_poly = [] 52 | 53 | # check if more than one face is selected 54 | self.NoneSelect = True 55 | for poly in self.mesh.polygons: 56 | if poly.select == True: 57 | self.NoneSelect = False 58 | self.select_poly.append(poly) 59 | 60 | if self.NoneSelect == True: 61 | return 62 | 63 | if self.mesh.uv_layers.active == None: 64 | self.mesh.uv_textures.new() 65 | 66 | # translate position that selected polygon's uv 67 | self.transUvVector() 68 | 69 | bpy.ops.object.mode_set(mode='EDIT') 70 | 71 | 72 | def transUvVector(self): 73 | max_position = 0. 74 | min_position_x = 0. 75 | min_position_y = 0. 76 | 77 | # calculate two rotation matrix from normal vector of selected polygons 78 | vector_nor = self.averageNormal() 79 | 80 | theta_x = self.calcRotAngle('X', vector_nor.x, vector_nor.y, vector_nor.z) 81 | mat_rotx = Matrix.Rotation(theta_x, 3, 'X') 82 | vector_nor.rotate(mat_rotx) 83 | 84 | theta_y = self.calcRotAngle('Y', vector_nor.x, vector_nor.y, vector_nor.z) 85 | mat_roty = Matrix.Rotation(theta_y, 3, 'Y') 86 | 87 | # apply two rotation matrix to vertex 88 | uv_array = self.mesh.uv_layers.active.data 89 | for poly in self.select_poly: 90 | for id in range(poly.loop_start, poly.loop_start + poly.loop_total): 91 | new_vector = Vector((self.mesh.vertices[self.mesh.loops[id].vertex_index].co[0], 92 | self.mesh.vertices[self.mesh.loops[id].vertex_index].co[1], 93 | self.mesh.vertices[self.mesh.loops[id].vertex_index].co[2])) 94 | 95 | new_vector.rotate(mat_rotx) 96 | new_vector.rotate(mat_roty) 97 | 98 | uv_array[id].uv = new_vector.to_2d() 99 | 100 | if min_position_x > uv_array[id].uv.x: 101 | min_position_x = uv_array[id].uv.x 102 | if min_position_y > uv_array[id].uv.y: 103 | min_position_y = uv_array[id].uv.y 104 | 105 | # recalculate uv position 106 | for poly in self.select_poly: 107 | for id in range(poly.loop_start, poly.loop_start + poly.loop_total): 108 | uv_array[id].uv.x = uv_array[id].uv.x + abs(min_position_x) 109 | uv_array[id].uv.y = uv_array[id].uv.y + abs(min_position_y) 110 | 111 | if max_position < uv_array[id].uv.x: 112 | max_position = uv_array[id].uv.x 113 | if max_position < uv_array[id].uv.y: 114 | max_position = uv_array[id].uv.y 115 | 116 | # scale uv position 117 | for poly in self.select_poly: 118 | for id in range(poly.loop_start, poly.loop_start + poly.loop_total): 119 | uv_array[id].uv.x = uv_array[id].uv.x * MAX_LOCATION / max_position 120 | uv_array[id].uv.y = uv_array[id].uv.y * MAX_LOCATION / max_position 121 | 122 | 123 | def averageNormal(self): 124 | weight_norx = 0. 125 | weight_nory = 0. 126 | weight_norz = 0. 127 | aver_normal = None 128 | 129 | for poly in self.select_poly: 130 | weight_norx = weight_norx + (poly.normal.x * poly.area) 131 | weight_nory = weight_nory + (poly.normal.y * poly.area) 132 | weight_norz = weight_norz + (poly.normal.z * poly.area) 133 | 134 | aver_normal = Vector((weight_norx, weight_nory, weight_norz)) 135 | aver_normal.normalize() 136 | 137 | return aver_normal 138 | 139 | 140 | def calcRotAngle(self, axis, nor_x, nor_y, nor_z): 141 | theta = 0 142 | vector_z = Vector((0.0, 0.0, 1.0)) 143 | vector_n = None 144 | vector_cross = None 145 | 146 | if axis == 'X': 147 | vector_n = Vector((0.0, nor_y, nor_z)) 148 | theta = vector_z.angle(vector_n, 999) 149 | vector_cross = vector_n.cross(vector_z) 150 | if vector_cross.x < 0: 151 | theta = -(theta) 152 | elif axis == 'Y': 153 | vector_n = Vector((nor_x, 0.0, nor_z)) 154 | theta = vector_z.angle(vector_n, 999) 155 | vector_cross = vector_n.cross(vector_z) 156 | if vector_cross.y < 0: 157 | theta = -(theta) 158 | else: 159 | pass 160 | 161 | return theta 162 | 163 | 164 | class NewUvProjectMenu(bpy.types.Operator): 165 | """Project From Normal""" 166 | bl_idname = "mesh.uv_project_from_normal_vector" 167 | bl_label = "Project From Normal Vector" 168 | bl_options = {'REGISTER', 'UNDO'} 169 | 170 | def execute(self, context): 171 | ProjectFromNormal() 172 | return {'FINISHED'} 173 | 174 | 175 | ################################################# 176 | 177 | ################################################# 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | class Placeholder(bpy.types.Operator): 204 | """Placeholder to get pie menu items in arbitrary positions""" 205 | bl_idname = "ui.placeholder" 206 | bl_label = "" 207 | 208 | @classmethod 209 | def poll(cls, context): 210 | return False 211 | 212 | def execute(self, context): 213 | return {'FINISHED'} 214 | 215 | 216 | class SplitAndGrab(bpy.types.Operator): 217 | """Same as pressing Y, then G in UV editor""" 218 | bl_idname = "uv.split_and_grab" 219 | bl_label = "Rip Face" 220 | 221 | def execute(self, context): 222 | 223 | bpy.ops.uv.select_split() 224 | bpy.ops.transform.translate() 225 | 226 | return {'FINISHED'} 227 | 228 | 229 | # Menu 230 | 231 | 232 | 233 | class live_unwrap_toggle(bpy.types.Operator): 234 | bl_idname = "uv.live_unwrap_toggle" 235 | bl_label = "Live Unwrap" 236 | 237 | def execute(self, context): 238 | if bpy.context.scene.tool_settings.edge_path_live_unwrap == (False): 239 | bpy.context.scene.tool_settings.edge_path_live_unwrap = True 240 | else: 241 | bpy.context.scene.tool_settings.edge_path_live_unwrap = False 242 | return {'FINISHED'} 243 | 244 | 245 | 246 | # bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.02) 247 | # bpy.ops.uv.project_from_view(camera_bounds=False, correct_aspect=True, scale_to_bounds=False) 248 | 249 | # uv pie menu 250 | class uv_pie(Menu): 251 | bl_idname = "pie.uv_pie" 252 | bl_label = "UV" 253 | 254 | def draw(self, context): 255 | layout = self.layout 256 | pie = layout.menu_pie() 257 | #4 - LEFT 258 | pie.operator("uv.unwrap", icon='LOOPSEL').margin=0.00 259 | #6 - RIGHT 260 | pie.operator("uv.smart_project", icon='UV_ISLANDSEL') 261 | #2 - BOTTOM 262 | pie.operator("uv.seams_from_islands", icon='MOD_MESHDEFORM') 263 | # tool_settings = context.tool_settings 264 | # pie.prop(tool_settings, "edge_path_live_unwrap") 265 | #8 - TOP 266 | pie.operator("uv.project_from_view", icon='RENDER_REGION') 267 | #7 - TOP - LEFT 268 | pie.operator("uv.pack_islands", icon='MOD_TRIANGULATE').rotate=False 269 | #9 - TOP - RIGHT 270 | pie.operator("uv.live_unwrap_toggle", icon='COLOR_RED') 271 | #1 - BOTTOM - LEFT 272 | pie.operator("mesh.uv_project_from_normal_vector", icon='VERTEXSEL') 273 | #3 - BOTTOM - RIGHT 274 | # pie.operator("uv.paste_uv_map", icon='PASTEDOWN') 275 | 276 | 277 | 278 | 279 | class UvSelectMode(bpy.types.Menu): 280 | bl_label = "UV Select Mode" 281 | bl_idname = "pie.uv_select_mode" 282 | 283 | def draw(self, context): 284 | layout = self.layout 285 | 286 | layout.operator_context = 'INVOKE_REGION_WIN' 287 | toolsettings = context.tool_settings 288 | pie = layout.menu_pie() 289 | 290 | _ = 0 if toolsettings.use_uv_select_sync else 1 291 | 292 | # Left 293 | op = pie.operator("wm.context_set_value", text="Vertex", 294 | icon=('VERTEXSEL', 'UV_VERTEXSEL')[_]) 295 | op.value = ("(True, False, False)", "'VERTEX'")[_] 296 | op.data_path = "tool_settings.%s_select_mode" % ('mesh', 'uv')[_] 297 | 298 | # Right 299 | op = pie.operator("wm.context_set_string", 300 | text="Island", icon='UV_ISLANDSEL') 301 | if _: 302 | op.value = 'ISLAND' 303 | op.data_path = "tool_settings.uv_select_mode" 304 | 305 | # Bottom 306 | op = pie.operator("wm.context_set_value", text="Face", 307 | icon=('FACESEL', 'UV_FACESEL')[_]) 308 | op.value = ("(False, False, True)", "'FACE'")[_] 309 | op.data_path = "tool_settings.%s_select_mode" % ('mesh', 'uv')[_] 310 | 311 | # Top 312 | op = pie.operator("wm.context_set_value", text="Edge", 313 | icon=('EDGESEL', 'UV_EDGESEL')[_]) 314 | op.value = ("(False, True, False)", "'EDGE'")[_] 315 | op.data_path = "tool_settings.%s_select_mode" % ('mesh', 'uv')[_] 316 | 317 | # Top-left linked 318 | op = pie.operator("uv.select_linked", text="Select Linked", 319 | icon="OUTLINER_OB_LATTICE") 320 | 321 | # Top-right 322 | op = pie.operator("wm.context_set_value", text="Sync Selection", 323 | icon="UV_SYNC_SELECT") 324 | op.value = ("False", "True")[_] 325 | op.data_path = "tool_settings.use_uv_select_sync" 326 | 327 | # Bottom-left 328 | op = pie.operator("uv.stitch", icon="SNAP_ON") 329 | 330 | # Bottom-right 331 | op = pie.operator("uv.split_and_grab", text="Rip Face", 332 | icon="MOD_MESHDEFORM") 333 | 334 | 335 | # addon_keymaps = [] 336 | # 337 | # 338 | # def register(): 339 | # bpy.utils.register_module(__name__) 340 | # 341 | # # Keymap Config 342 | # wm = bpy.context.window_manager 343 | # 344 | # if wm.keyconfigs.addon: 345 | # km = wm.keyconfigs.addon.keymaps.new(name='Image', 346 | # space_type='IMAGE_EDITOR') 347 | # kmi = km.keymap_items.new('wm.call_menu_pie', 'RIGHTMOUSE', 'PRESS') 348 | # kmi.properties.name = "pie.uv_select_mode" 349 | # 350 | # addon_keymaps.append(km) 351 | # 352 | # 353 | # def unregister(): 354 | # bpy.utils.unregister_module(__name__) 355 | # 356 | # wm = bpy.context.window_manager 357 | # 358 | # if wm.keyconfigs.addon: 359 | # for km in addon_keymaps: 360 | # for kmi in km.keymap_items: 361 | # km.keymap_items.remove(kmi) 362 | # 363 | # wm.keyconfigs.addon.keymaps.remove(km) 364 | # 365 | # del addon_keymaps[:] 366 | # 367 | # if __name__ == "__main__": 368 | # register() 369 | --------------------------------------------------------------------------------