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 19bl_info = { 20 "name": "3D-Coat Applink", 21 "author": "Kalle-Samuli Riihikoski (haikalle)", 22 "version": (4, 9, 34), 23 "blender": (2, 80, 0), 24 "location": "Scene > 3D-Coat Applink", 25 "description": "Transfer data between 3D-Coat/Blender", 26 "warning": "", 27 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/coat3D.html", 28 "category": "Import-Export", 29} 30 31if "bpy" in locals(): 32 import importlib 33 importlib.reload(tex) 34else: 35 from . import tex 36from bpy.app.handlers import persistent 37 38from io_coat3D import tex 39from io_coat3D import texVR 40from io_coat3D import folders 41 42import os 43import platform 44import ntpath 45import re 46import shutil 47import pathlib 48 49 50import time 51import bpy 52 53import subprocess 54from bpy.types import PropertyGroup 55from bpy.props import ( 56 BoolProperty, 57 EnumProperty, 58 FloatVectorProperty, 59 StringProperty, 60 PointerProperty, 61 ) 62 63foundExchangeFolder = False 64saved_exchange_folder = '' 65liveUpdate = True 66mTime = 0 67 68@persistent 69def every_3_seconds(): 70 71 global global_exchange_folder 72 global liveUpdate 73 global mTime 74 global foundExchangeFolder 75 try: 76 coat3D = bpy.context.scene.coat3D 77 78 79 if(foundExchangeFolder == False): 80 foundExchangeFolder, global_exchange_folder = folders.InitFolders() 81 82 Export_folder = coat3D.exchangeFolder 83 Export_folder += ('%sexport.txt' % (os.sep)) 84 85 if (os.path.isfile(Export_folder) and mTime != os.path.getmtime(Export_folder)): 86 87 for objekti in bpy.data.objects: 88 if(objekti.coat3D.applink_mesh): 89 tex.updatetextures(objekti) 90 91 mTime = os.path.getmtime(Export_folder) 92 93 if (os.path.normpath(global_exchange_folder) != os.path.normpath(coat3D.exchangeFolder) and coat3D.exchangeFolder != ''): 94 folders.updateExchangeFile(coat3D.exchangeFolder) 95 96 except: 97 pass 98 99 return 3.0 100 101@persistent 102def load_handler(dummy): 103 global foundExchangeFolder 104 foundExchangeFolder = False 105 bpy.app.timers.register(every_3_seconds) 106 107def removeFile(exportfile): 108 if (os.path.isfile(exportfile)): 109 os.remove(exportfile) 110 111 112def folder_size(path): 113 114 folder_size_max = int(bpy.context.scene.coat3D.folder_size) 115 116 if(bpy.context.scene.coat3D.defaultfolder == ''): 117 tosi = True 118 while tosi: 119 list_of_files = [] 120 for file in os.listdir(path): 121 list_of_files.append(path + os.sep + file) 122 123 if len(list_of_files) >= folder_size_max: 124 oldest_file = min(list_of_files, key=os.path.getctime) 125 os.remove(os.path.abspath(oldest_file)) 126 else: 127 tosi = False 128 129def make_texture_list(texturefolder): 130 texturefolder += ('%stextures.txt'%(os.sep)) 131 texturelist = [] 132 133 if (os.path.isfile(texturefolder)): 134 texturefile = open(texturefolder) 135 index = 0 136 for line in texturefile: 137 if line != '' and index == 0: 138 line = line.rstrip('\n') 139 objekti = line 140 index += 1 141 elif index == 1: 142 line = line.rstrip('\n') 143 material = line 144 index += 1 145 elif index == 2: 146 line = line.rstrip('\n') 147 type = line 148 index += 1 149 elif index == 3: 150 line = line.rstrip('\n') 151 address = line 152 texturelist.append([objekti,material,type,address]) 153 index = 0 154 texturefile.close() 155 return texturelist 156 157 158''' 159#Updating objects MESH part ( Mesh, Vertex Groups, Vertex Colors ) 160''' 161 162def updatemesh(objekti, proxy, texturelist): 163 # Vertex colors 164 if(len(proxy.data.vertex_colors) > 0): 165 bring_vertex_map = True 166 else: 167 bring_vertex_map = False 168 169 if(bring_vertex_map): 170 if(len(objekti.data.vertex_colors) > 0): 171 for vertex_map in objekti.data.vertex_colors: 172 if vertex_map.name == 'Col': 173 copy_data = True 174 vertex_map_copy = vertex_map 175 break 176 else: 177 copy_data = False 178 else: 179 copy_data = False 180 181 if(copy_data): 182 for poly in objekti.data.polygons: 183 for loop_index in poly.loop_indices: 184 vertex_map_copy.data[loop_index].color = proxy.data.vertex_colors[0].data[loop_index].color 185 else: 186 objekti.data.vertex_colors.new() 187 vertex_map_copy = objekti.data.vertex_colors[-1] 188 for poly in objekti.data.polygons: 189 for loop_index in poly.loop_indices: 190 vertex_map_copy.data[loop_index].color = proxy.data.vertex_colors[0].data[loop_index].color 191 192 # UV -Sets 193 udim_textures = False 194 if(texturelist != []): 195 if(texturelist[0][0].startswith('100')): 196 udim_textures =True 197 198 proxy.select_set(True) 199 objekti.select_set(True) 200 201 uv_count = len(proxy.data.uv_layers) 202 index = 0 203 while(index < uv_count and len(proxy.data.polygons) == len(objekti.data.polygons)): 204 for poly in proxy.data.polygons: 205 for indi in poly.loop_indices: 206 if(proxy.data.uv_layers[index].data[indi].uv[0] != 0 and proxy.data.uv_layers[index].data[indi].uv[1] != 0): 207 208 if(udim_textures): 209 udim = proxy.data.uv_layers[index].name 210 udim_index = int(udim[2:]) - 1 211 212 objekti.data.uv_layers[0].data[indi].uv[0] = proxy.data.uv_layers[index].data[indi].uv[0] 213 objekti.data.uv_layers[0].data[indi].uv[1] = proxy.data.uv_layers[index].data[indi].uv[1] 214 215 index = index + 1 216 217 # Mesh Copy 218 if(proxy.name.startswith('RetopoGroup')): 219 objekti.data = proxy.data 220 else: 221 for ind, v in enumerate(objekti.data.vertices): 222 v.co = proxy.data.vertices[ind].co 223 224class SCENE_OT_getback(bpy.types.Operator): 225 bl_idname = "getback.pilgway_3d_coat" 226 bl_label = "Export your custom property" 227 bl_description = "Export your custom property" 228 bl_options = {'UNDO'} 229 230 def invoke(self, context, event): 231 232 global global_exchange_folder 233 path_ex = '' 234 235 Export_folder = global_exchange_folder 236 Blender_folder = os.path.join(Export_folder, 'Blender') 237 238 BlenderFolder = Blender_folder 239 ExportFolder = Export_folder 240 241 Blender_folder += ('%sexport.txt' % (os.sep)) 242 Export_folder += ('%sexport.txt' % (os.sep)) 243 244 if (bpy.app.background == False): 245 if os.path.isfile(Export_folder): 246 247 print('BLENDER -> 3DC -> BLENDER WORKFLLOW') 248 DeleteExtra3DC() 249 workflow1(ExportFolder) 250 removeFile(Export_folder) 251 removeFile(Blender_folder) 252 253 elif os.path.isfile(Blender_folder): 254 255 print('3DC -> BLENDER WORKFLLOW') 256 DeleteExtra3DC() 257 workflow2(BlenderFolder) 258 removeFile(Blender_folder) 259 260 return {'FINISHED'} 261 262class SCENE_OT_folder(bpy.types.Operator): 263 bl_idname = "update_exchange_folder.pilgway_3d_coat" 264 bl_label = "Export your custom property" 265 bl_description = "Export your custom property" 266 bl_options = {'UNDO'} 267 268 def invoke(self, context, event): 269 global foundExchangeFolder 270 coat3D = bpy.context.scene.coat3D 271 if(os.path.isdir(coat3D.exchangeFolder)): 272 foundExchangeFolder= True 273 else: 274 foundExchangeFolder = False 275 276 return {'FINISHED'} 277 278class SCENE_OT_opencoat(bpy.types.Operator): 279 bl_idname = "open_3dcoat.pilgway_3d_coat" 280 bl_label = "Export your custom property" 281 bl_description = "Export your custom property" 282 bl_options = {'UNDO'} 283 284 def invoke(self, context, event): 285 286 coat3D = bpy.context.selected_objects[0].coat3D.applink_3b_path 287 platform = os.sys.platform 288 if (platform == 'win32' or platform == 'darwin'): 289 importfile = bpy.context.scene.coat3D.exchangeFolder 290 importfile += ('%simport.txt' % (os.sep)) 291 file = open(importfile, "w") 292 file.write("%s" % (coat3D)) 293 file.write("\n%s" % (coat3D)) 294 file.write("\n[3B]") 295 file.close() 296 else: 297 importfile = bpy.context.scene.coat3D.exchangeFolder 298 importfile += ('%simport.txt' % (os.sep)) 299 file = open(importfile, "w") 300 file.write("%s" % (coat3D)) 301 file.write("\n%s" % (coat3D)) 302 file.write("\n[3B]") 303 file.close() 304 305 return {'FINISHED'} 306 307def scaleParents(): 308 save = [] 309 names =[] 310 311 for objekti in bpy.context.selected_objects: 312 temp = objekti 313 while (temp.parent is not None and temp.parent.name not in names): 314 save.append([temp.parent,(temp.parent.scale[0],temp.parent.scale[1],temp.parent.scale[2])]) 315 names.append(temp.parent) 316 temp = temp.parent 317 318 for name in names: 319 name.scale = (1,1,1) 320 321 return save 322 323def scaleBackParents(save): 324 325 for data in save: 326 data[0].scale = data[1] 327 328def deleteNodes(type): 329 330 deletelist = [] 331 deleteimages = [] 332 deletegroup =[] 333 delete_images = bpy.context.scene.coat3D.delete_images 334 335 if type == 'Material': 336 if(len(bpy.context.selected_objects) == 1): 337 material = bpy.context.selected_objects[0].active_material 338 if(material.use_nodes): 339 for node in material.node_tree.nodes: 340 if(node.name.startswith('3DC')): 341 if (node.type == 'GROUP'): 342 deletegroup.append(node.node_tree.name) 343 deletelist.append(node.name) 344 if node.type == 'TEX_IMAGE' and delete_images == True: 345 deleteimages.append(node.image.name) 346 if deletelist: 347 for node in deletelist: 348 material.node_tree.nodes.remove(material.node_tree.nodes[node]) 349 if deleteimages: 350 for image in deleteimages: 351 bpy.data.images.remove(bpy.data.images[image]) 352 353 elif type == 'Object': 354 if (len(bpy.context.selected_objects) > 0): 355 for objekti in bpy.context.selected_objects: 356 for material in objekti.material_slots: 357 if (material.material.use_nodes): 358 for node in material.material.node_tree.nodes: 359 if (node.name.startswith('3DC')): 360 if(node.type == 'GROUP'): 361 deletegroup.append(node.node_tree.name) 362 deletelist.append(node.name) 363 if node.type == 'TEX_IMAGE' and delete_images == True: 364 deleteimages.append(node.image.name) 365 if deletelist: 366 for node in deletelist: 367 material.material.node_tree.nodes.remove(material.material.node_tree.nodes[node]) 368 deletelist = [] 369 370 if deleteimages: 371 for image in deleteimages: 372 bpy.data.images.remove(bpy.data.images[image]) 373 deleteimages = [] 374 375 elif type == 'Collection': 376 for collection_object in bpy.context.view_layer.active_layer_collection.collection.all_objects: 377 if(collection_object.type == 'MESH'): 378 for material in collection_object.material_slots: 379 if (material.material.use_nodes): 380 for node in material.material.node_tree.nodes: 381 if (node.name.startswith('3DC')): 382 if (node.type == 'GROUP'): 383 deletegroup.append(node.node_tree.name) 384 deletelist.append(node.name) 385 if node.type == 'TEX_IMAGE' and delete_images == True: 386 deleteimages.append(node.image.name) 387 388 if deletelist: 389 for node in deletelist: 390 material.material.node_tree.nodes.remove(material.material.node_tree.nodes[node]) 391 deletelist = [] 392 393 if deleteimages: 394 for image in deleteimages: 395 bpy.data.images.remove(bpy.data.images[image]) 396 deleteimages = [] 397 398 elif type == 'Scene': 399 for collection in bpy.data.collections: 400 for collection_object in collection.all_objects: 401 if (collection_object.type == 'MESH'): 402 for material in collection_object.material_slots: 403 if (material.material.use_nodes): 404 for node in material.material.node_tree.nodes: 405 if (node.name.startswith('3DC')): 406 if (node.type == 'GROUP'): 407 deletegroup.append(node.node_tree.name) 408 409 deletelist.append(node.name) 410 if node.type == 'TEX_IMAGE' and delete_images == True: 411 deleteimages.append(node.image.name) 412 if deletelist: 413 for node in deletelist: 414 material.material.node_tree.nodes.remove(material.material.node_tree.nodes[node]) 415 deletelist = [] 416 417 if deleteimages: 418 for image in deleteimages: 419 bpy.data.images.remove(bpy.data.images[image]) 420 deleteimages = [] 421 422 if(deletelist): 423 for node in deletelist: 424 bpy.data.node_groups.remove(bpy.data.node_groups[node]) 425 426 for image in bpy.data.images: 427 if (image.name.startswith('3DC') and image.name[6] == '_'): 428 deleteimages.append(image.name) 429 430 431 if(deletegroup): 432 for node in deletegroup: 433 bpy.data.node_groups.remove(bpy.data.node_groups[node]) 434 435 if deleteimages: 436 for image in deleteimages: 437 bpy.data.images.remove(bpy.data.images[image]) 438 439 440def delete_materials_from_end(keep_materials_count, objekti): 441 #bpy.context.object.active_material_index = 0 442 index_t = 0 443 while (index_t < keep_materials_count): 444 temp_len = len(objekti.material_slots)-1 445 bpy.context.object.active_material_index = temp_len 446 bpy.ops.object.material_slot_remove() 447 index_t +=1 448 449''' DELETE NODES BUTTONS''' 450 451class SCENE_OT_delete_material_nodes(bpy.types.Operator): 452 bl_idname = "delete_material_nodes.pilgway_3d_coat" 453 bl_label = "Delete material nodes" 454 bl_description = "Delete material nodes" 455 bl_options = {'UNDO'} 456 457 def invoke(self, context, event): 458 type = bpy.context.scene.coat3D.deleteMode = 'Material' 459 deleteNodes(type) 460 return {'FINISHED'} 461 462class SCENE_OT_delete_object_nodes(bpy.types.Operator): 463 bl_idname = "delete_object_nodes.pilgway_3d_coat" 464 bl_label = "Delete material nodes" 465 bl_description = "Delete material nodes" 466 bl_options = {'UNDO'} 467 468 def invoke(self, context, event): 469 type = bpy.context.scene.coat3D.deleteMode = 'Object' 470 deleteNodes(type) 471 return {'FINISHED'} 472 473class SCENE_OT_delete_collection_nodes(bpy.types.Operator): 474 bl_idname = "delete_collection_nodes.pilgway_3d_coat" 475 bl_label = "Delete material nodes" 476 bl_description = "Delete material nodes" 477 bl_options = {'UNDO'} 478 479 def invoke(self, context, event): 480 type = bpy.context.scene.coat3D.deleteMode = 'Collection' 481 deleteNodes(type) 482 return {'FINISHED'} 483 484class SCENE_OT_delete_scene_nodes(bpy.types.Operator): 485 bl_idname = "delete_scene_nodes.pilgway_3d_coat" 486 bl_label = "Delete material nodes" 487 bl_description = "Delete material nodes" 488 bl_options = {'UNDO'} 489 490 def invoke(self, context, event): 491 type = bpy.context.scene.coat3D.deleteMode = 'Scene' 492 deleteNodes(type) 493 return {'FINISHED'} 494 495 496''' TRANSFER AND UPDATE BUTTONS''' 497 498class SCENE_OT_export(bpy.types.Operator): 499 bl_idname = "export_applink.pilgway_3d_coat" 500 bl_label = "Export your custom property" 501 bl_description = "Export your custom property" 502 bl_options = {'UNDO'} 503 504 def invoke(self, context, event): 505 bpy.ops.export_applink.pilgway_3d_coat() 506 507 return {'FINISHED'} 508 509 def execute(self, context): 510 global run_background_update 511 run_background_update = False 512 for mesh in bpy.data.meshes: 513 if (mesh.users == 0 and mesh.coat3D.name == '3DC'): 514 bpy.data.meshes.remove(mesh) 515 516 for material in bpy.data.materials: 517 if (material.users == 1 and material.coat3D.name == '3DC'): 518 bpy.data.materials.remove(material) 519 520 export_ok = False 521 coat3D = bpy.context.scene.coat3D 522 523 if (bpy.context.selected_objects == []): 524 return {'FINISHED'} 525 else: 526 for objec in bpy.context.selected_objects: 527 if objec.type == 'MESH': 528 if(len(objec.data.uv_layers) == 0): 529 objec.data.uv_layers.new(name='UVMap', do_init = False) 530 531 export_ok = True 532 if (export_ok == False): 533 return {'FINISHED'} 534 535 scaled_objects = scaleParents() 536 537 activeobj = bpy.context.active_object.name 538 checkname = '' 539 coa = bpy.context.active_object.coat3D 540 541 p = pathlib.Path(coat3D.exchangeFolder) 542 kokeilu = coat3D.exchangeFolder[:-9] 543 Blender_folder2 = ("%s%sExchange" % (kokeilu, os.sep)) 544 Blender_folder2 += ('%sexport.txt' % (os.sep)) 545 546 if (os.path.isfile(Blender_folder2)): 547 os.remove(Blender_folder2) 548 549 if (not os.path.isdir(coat3D.exchangeFolder)): 550 coat3D.exchange_found = False 551 return {'FINISHED'} 552 553 folder_objects = folders.set_working_folders() 554 folder_size(folder_objects) 555 556 importfile = coat3D.exchangeFolder 557 texturefile = coat3D.exchangeFolder 558 importfile += ('%simport.txt'%(os.sep)) 559 texturefile += ('%stextures.txt'%(os.sep)) 560 561 looking = True 562 object_index = 0 563 active_render = bpy.context.scene.render.engine 564 565 if(coat3D.type == 'autopo'): 566 checkname = folder_objects + os.sep 567 checkname = ("%sretopo.fbx" % (checkname)) 568 569 elif(coat3D.type == 'update'): 570 checkname = bpy.context.selected_objects[0].coat3D.applink_address 571 572 else: 573 while(looking == True): 574 checkname = folder_objects + os.sep + "3DC" 575 checkname = ("%s%.3d.fbx"%(checkname,object_index)) 576 if(os.path.isfile(checkname)): 577 object_index += 1 578 else: 579 looking = False 580 coa.applink_name = ("%s%.2d"%(activeobj,object_index)) 581 coa.applink_address = checkname 582 583 matindex = 0 584 585 for objekti in bpy.context.selected_objects: 586 if objekti.type == 'MESH': 587 objekti.name = '__' + objekti.name 588 if(objekti.material_slots.keys() == []): 589 newmat = bpy.data.materials.new('Material') 590 newmat.use_nodes = True 591 objekti.data.materials.append(newmat) 592 matindex += 1 593 objekti.coat3D.applink_name = objekti.name 594 mod_mat_list = {} 595 596 597 bake_location = folder_objects + os.sep + 'Bake' 598 if (os.path.isdir(bake_location)): 599 shutil.rmtree(bake_location) 600 os.makedirs(bake_location) 601 else: 602 os.makedirs(bake_location) 603 604 # BAKING # 605 606 temp_string = '' 607 for objekti in bpy.context.selected_objects: 608 if objekti.type == 'MESH': 609 mod_mat_list[objekti.name] = [] 610 objekti.coat3D.applink_scale = objekti.scale 611 objekti.coat3D.retopo = False 612 613 ''' Checks what materials are linked into UV ''' 614 615 if(coat3D.type == 'ppp'): 616 final_material_indexs = [] 617 uvtiles_index = [] 618 for poly in objekti.data.polygons: 619 if(poly.material_index not in final_material_indexs): 620 final_material_indexs.append(poly.material_index) 621 loop_index = poly.loop_indices[0] 622 uvtiles_index.append([poly.material_index,objekti.data.uv_layers.active.data[loop_index].uv[0]]) 623 if(len(final_material_indexs) == len(objekti.material_slots)): 624 break 625 626 material_index = 0 627 if (len(final_material_indexs) != len(objekti.material_slots)): 628 for material in objekti.material_slots: 629 if material_index not in final_material_indexs: 630 temp_mat = material.material 631 material.material = objekti.material_slots[0].material 632 mod_mat_list[objekti.name].append([material_index, temp_mat]) 633 material_index = material_index + 1 634 635 bake_list = [] 636 if(coat3D.bake_diffuse): 637 bake_list.append(['DIFFUSE', '$LOADTEX']) 638 if (coat3D.bake_ao): 639 bake_list.append(['AO', '$ExternalAO']) 640 if (coat3D.bake_normal): 641 bake_list.append(['NORMAL', '$LOADLOPOLYTANG']) 642 if (coat3D.bake_roughness): 643 bake_list.append(['ROUGHNESS', '$LOADROUGHNESS']) 644 645 if(coat3D.bake_resolution == 'res_64'): 646 res_size = 64 647 elif (coat3D.bake_resolution == 'res_128'): 648 res_size = 128 649 elif (coat3D.bake_resolution == 'res_256'): 650 res_size = 256 651 elif (coat3D.bake_resolution == 'res_512'): 652 res_size = 512 653 elif (coat3D.bake_resolution == 'res_1024'): 654 res_size = 1024 655 elif (coat3D.bake_resolution == 'res_2048'): 656 res_size = 2048 657 elif (coat3D.bake_resolution == 'res_4096'): 658 res_size = 4096 659 elif (coat3D.bake_resolution == 'res_8192'): 660 res_size = 8192 661 662 if(len(bake_list) > 0): 663 index_bake_tex = 0 664 while(index_bake_tex < len(bake_list)): 665 bake_index = 0 666 for bake_mat_index in final_material_indexs: 667 bake_node = objekti.material_slots[bake_mat_index].material.node_tree.nodes.new('ShaderNodeTexImage') 668 bake_node.name = 'ApplinkBake' + str(bake_index) 669 bpy.ops.image.new(name=bake_node.name, width=res_size, height=res_size) 670 bake_node.image = bpy.data.images[bake_node.name] 671 objekti.material_slots[bake_mat_index].material.node_tree.nodes.active = bake_node 672 673 bake_index += 1 674 if(bpy.context.scene.render.engine != 'CYCLES'): 675 bpy.context.scene.render.engine = 'CYCLES' 676 bpy.context.scene.render.bake.use_pass_direct = False 677 bpy.context.scene.render.bake.use_pass_indirect = False 678 bpy.context.scene.render.bake.use_pass_color = True 679 680 bpy.ops.object.bake(type=bake_list[index_bake_tex][0], margin=1, width=res_size, height=res_size) 681 682 bake_index = 0 683 for bake_mat_index in final_material_indexs: 684 bake_image = 'ApplinkBake' + str(bake_index) 685 bpy.data.images[bake_image].filepath_raw = bake_location + os.sep + objekti.name + '_' + bake_image + '_' + bake_list[index_bake_tex][0] + ".png" 686 image_bake_name = bpy.data.images[bake_image].filepath_raw 687 tie = image_bake_name.split(os.sep) 688 toi = '' 689 for sana in tie: 690 toi += sana 691 toi += "/" 692 final_bake_name = toi[:-1] 693 bpy.data.images[bake_image].save() 694 temp_string += '''\n[script ImportTexture("''' + bake_list[index_bake_tex][1] + '''","''' + objekti.material_slots[bake_mat_index].material.name + '''","''' + final_bake_name + '''");]''' 695 696 bake_index += 1 697 698 for material in objekti.material_slots: 699 if material.material.use_nodes == True: 700 for node in material.material.node_tree.nodes: 701 if (node.name.startswith('ApplinkBake') == True): 702 material.material.node_tree.nodes.remove(node) 703 704 for image in bpy.data.images: 705 if (image.name.startswith('ApplinkBake') == True): 706 bpy.data.images.remove(image) 707 708 index_bake_tex += 1 709 710 #BAKING ENDS 711 712 #bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') 713 if(len(bpy.context.selected_objects) > 1 and coat3D.type != 'vox'): 714 bpy.ops.object.transforms_to_deltas(mode='ROT') 715 716 if(coat3D.type == 'autopo'): 717 coat3D.bring_retopo = True 718 coat3D.bring_retopo_path = checkname 719 bpy.ops.export_scene.fbx(filepath=checkname, global_scale = 0.01, use_selection=True, use_mesh_modifiers=coat3D.exportmod, axis_forward='-Z', axis_up='Y') 720 721 elif (coat3D.type == 'vox'): 722 coat3D.bring_retopo = False 723 bpy.ops.export_scene.fbx(filepath=coa.applink_address, global_scale = 0.01, use_selection=True, 724 use_mesh_modifiers=coat3D.exportmod, axis_forward='-Z', axis_up='Y') 725 726 else: 727 coat3D.bring_retopo = False 728 bpy.ops.export_scene.fbx(filepath=coa.applink_address,global_scale = 0.01, use_selection=True, use_mesh_modifiers=coat3D.exportmod, axis_forward='-Z', axis_up='Y') 729 730 file = open(importfile, "w") 731 file.write("%s"%(checkname)) 732 file.write("\n%s"%(checkname)) 733 file.write("\n[%s]"%(coat3D.type)) 734 if(coat3D.type == 'ppp' or coat3D.type == 'mv' or coat3D.type == 'ptex'): 735 file.write("\n[export_preset Blender Cycles]") 736 file.write(temp_string) 737 738 file.close() 739 for idx, objekti in enumerate(bpy.context.selected_objects): 740 if objekti.type == 'MESH': 741 objekti.name = objekti.name[2:] 742 if(len(bpy.context.selected_objects) == 1): 743 objekti.coat3D.applink_onlyone = True 744 objekti.coat3D.type = coat3D.type 745 objekti.coat3D.applink_mesh = True 746 objekti.coat3D.obj_mat = '' 747 objekti.coat3D.applink_index = ("3DC%.3d" % (object_index)) 748 749 objekti.coat3D.applink_firsttime = True 750 if(coat3D.type != 'autopo'): 751 objekti.coat3D.applink_address = coa.applink_address 752 objekti.coat3D.objecttime = str(os.path.getmtime(objekti.coat3D.applink_address)) 753 objekti.data.coat3D.name = '3DC' 754 755 if(coat3D.type != 'vox'): 756 if(objekti.material_slots.keys() != []): 757 for material in objekti.material_slots: 758 if material.material.use_nodes == True: 759 for node in material.material.node_tree.nodes: 760 if(node.name.startswith('3DC_') == True): 761 material.material.node_tree.nodes.remove(node) 762 763 764 for ind, mat_list in enumerate(mod_mat_list): 765 if(mat_list == '__' + objekti.name): 766 for ind, mat in enumerate(mod_mat_list[mat_list]): 767 objekti.material_slots[mod_mat_list[mat_list][ind][0]].material = mod_mat_list[mat_list][ind][1] 768 769 scaleBackParents(scaled_objects) 770 bpy.context.scene.render.engine = active_render 771 return {'FINISHED'} 772 773 774def DeleteExtra3DC(): 775 776 for node_group in bpy.data.node_groups: 777 if(node_group.users == 0): 778 bpy.data.node_groups.remove(node_group) 779 780 for mesh in bpy.data.meshes: 781 if(mesh.users == 0 and mesh.coat3D.name == '3DC'): 782 bpy.data.meshes.remove(mesh) 783 784 for material in bpy.data.materials: 785 img_list = [] 786 if (material.users == 1 and material.coat3D.name == '3DC'): 787 if material.use_nodes == True: 788 for node in material.node_tree.nodes: 789 if node.type == 'TEX_IMAGE' and node.name.startswith('3DC'): 790 img_list.append(node.image) 791 if img_list != []: 792 for del_img in img_list: 793 bpy.data.images.remove(del_img) 794 795 bpy.data.materials.remove(material) 796 797 image_del_list = [] 798 for image in bpy.data.images: 799 if (image.name.startswith('3DC')): 800 if image.users == 0: 801 image_del_list.append(image.name) 802 803 if (image_del_list != []): 804 for image in image_del_list: 805 bpy.data.images.remove(bpy.data.images[image]) 806 807def new_ref_function(new_applink_address, nimi): 808 809 create_collection = True 810 for collection in bpy.data.collections: 811 if collection.name == 'Applink_Objects': 812 create_collection = False 813 814 if create_collection: 815 bpy.data.collections.new('Applink_Objects') 816 817 coll_items = bpy.context.scene.collection.children.items() 818 819 add_applink_collection = True 820 for coll in coll_items: 821 if coll[0] == 'Applink_Objects': 822 add_applink_collection = False 823 824 if add_applink_collection: 825 bpy.context.scene.collection.children.link(bpy.data.collections['Applink_Objects']) 826 827 bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children['Applink_Objects'] 828 829 old_objects = bpy.data.objects.keys() 830 object_list = [] 831 832 833 bpy.ops.import_scene.fbx(filepath=new_applink_address, global_scale = 0.01,axis_forward='X', axis_up='Y',use_custom_normals=False) 834 new_objects = bpy.data.objects.keys() 835 diff_objects = [i for i in new_objects if i not in old_objects] 836 texturelist = [] 837 838 for diff_object in diff_objects: 839 840 refmesh = bpy.data.objects[nimi] 841 copymesh = bpy.data.objects[nimi].copy() 842 843 copymesh.data = bpy.data.objects[diff_object].data 844 copymesh.coat3D.applink_name = bpy.data.objects[diff_object].data.name 845 copymesh.coat3D.applink_address = refmesh.coat3D.applink_address 846 ne_name = bpy.data.objects[diff_object].data.name 847 848 copymesh.coat3D.type = 'ppp' 849 copymesh.coat3D.retopo = True 850 851 bpy.data.collections['Applink_Objects'].objects.link(copymesh) 852 853 bpy.data.objects.remove(bpy.data.objects[diff_object]) 854 bpy.ops.object.select_all(action='DESELECT') 855 copymesh.select_set(True) 856 copymesh.delta_rotation_euler[0] = 1.5708 857 copymesh.name = ne_name 858 859 normal_node = copymesh.material_slots[0].material.node_tree.nodes['Normal Map'] 860 copymesh.material_slots[0].material.node_tree.nodes.remove(normal_node) 861 copymesh.material_slots[0].material.node_tree.nodes['Principled BSDF'].inputs['Metallic'].default_value = 0 862 copymesh.material_slots[0].material.node_tree.nodes['Principled BSDF'].inputs['Specular'].default_value = 0.5 863 864 865 refmesh.coat3D.applink_name = '' 866 refmesh.coat3D.applink_address = '' 867 refmesh.coat3D.type = '' 868 copymesh.scale = (1,1,1) 869 copymesh.coat3D.applink_scale = (1,1,1) 870 copymesh.location = (0,0,0) 871 copymesh.rotation_euler = (0,0,0) 872 873 874def blender_3DC_blender(texturelist, file_applink_address): 875 876 coat3D = bpy.context.scene.coat3D 877 878 old_materials = bpy.data.materials.keys() 879 old_objects = bpy.data.objects.keys() 880 cache_base = bpy.data.objects.keys() 881 882 object_list = [] 883 import_list = [] 884 import_type = [] 885 886 for objekti in bpy.data.objects: 887 if objekti.type == 'MESH' and objekti.coat3D.applink_address == file_applink_address: 888 obj_coat = objekti.coat3D 889 890 object_list.append(objekti.name) 891 if(os.path.isfile(obj_coat.applink_address)): 892 if (obj_coat.objecttime != str(os.path.getmtime(obj_coat.applink_address))): 893 obj_coat.dime = objekti.dimensions 894 obj_coat.import_mesh = True 895 obj_coat.objecttime = str(os.path.getmtime(obj_coat.applink_address)) 896 if(obj_coat.applink_address not in import_list): 897 import_list.append(obj_coat.applink_address) 898 import_type.append(coat3D.type) 899 900 if(import_list or coat3D.importmesh): 901 for idx, list in enumerate(import_list): 902 903 bpy.ops.import_scene.fbx(filepath=list, global_scale = 0.01,axis_forward='X',use_custom_normals=False) 904 cache_objects = bpy.data.objects.keys() 905 cache_objects = [i for i in cache_objects if i not in cache_base] 906 for cache_object in cache_objects: 907 908 bpy.data.objects[cache_object].coat3D.type = import_type[idx] 909 bpy.data.objects[cache_object].coat3D.applink_address = list 910 cache_base.append(cache_object) 911 912 bpy.ops.object.select_all(action='DESELECT') 913 new_materials = bpy.data.materials.keys() 914 new_objects = bpy.data.objects.keys() 915 916 917 diff_mat = [i for i in new_materials if i not in old_materials] 918 diff_objects = [i for i in new_objects if i not in old_objects] 919 920 for mark_mesh in diff_objects: 921 bpy.data.objects[mark_mesh].data.coat3D.name = '3DC' 922 923 for c_index in diff_mat: 924 bpy.data.materials.remove(bpy.data.materials[c_index]) 925 926 '''The main Applink Object Loop''' 927 928 for oname in object_list: 929 930 objekti = bpy.data.objects[oname] 931 if(objekti.coat3D.applink_mesh == True): 932 933 path3b_n = coat3D.exchangeFolder 934 path3b_n += ('%slast_saved_3b_file.txt' % (os.sep)) 935 936 if(objekti.coat3D.import_mesh and coat3D.importmesh == True): 937 938 objekti.coat3D.import_mesh = False 939 objekti.select_set(True) 940 941 use_smooth = objekti.data.polygons[0].use_smooth 942 found_obj = False 943 944 '''Changes objects mesh into proxy mesh''' 945 if(objekti.coat3D.type != 'ref'): 946 947 for proxy_objects in diff_objects: 948 if(objekti.coat3D.retopo == False): 949 if (proxy_objects == objekti.coat3D.applink_name): 950 obj_proxy = bpy.data.objects[proxy_objects] 951 obj_proxy.coat3D.delete_proxy_mesh = True 952 found_obj = True 953 else: 954 if (proxy_objects == objekti.coat3D.applink_name + '.001'): 955 obj_proxy = bpy.data.objects[proxy_objects] 956 obj_proxy.coat3D.delete_proxy_mesh = True 957 found_obj = True 958 959 960 mat_list = [] 961 if (objekti.material_slots): 962 for obj_mat in objekti.material_slots: 963 mat_list.append(obj_mat.material) 964 965 if(found_obj == True): 966 exportfile = coat3D.exchangeFolder 967 path3b_n = coat3D.exchangeFolder 968 path3b_n += ('%slast_saved_3b_file.txt' % (os.sep)) 969 exportfile += ('%sBlender' % (os.sep)) 970 exportfile += ('%sexport.txt'%(os.sep)) 971 if(os.path.isfile(exportfile)): 972 export_file = open(exportfile) 973 export_file.close() 974 os.remove(exportfile) 975 if(os.path.isfile(path3b_n)): 976 977 mesh_time = os.path.getmtime(objekti.coat3D.applink_address) 978 b_time = os.path.getmtime(path3b_n) 979 if (abs(mesh_time - b_time) < 240): 980 export_file = open(path3b_n) 981 for line in export_file: 982 objekti.coat3D.applink_3b_path = line 983 head, tail = os.path.split(line) 984 just_3b_name = tail 985 objekti.coat3D.applink_3b_just_name = just_3b_name 986 export_file.close() 987 coat3D.remove_path = True 988 989 bpy.ops.object.select_all(action='DESELECT') 990 obj_proxy.select_set(True) 991 992 bpy.ops.object.select_all(action='TOGGLE') 993 994 if objekti.coat3D.applink_firsttime == True and objekti.coat3D.type == 'vox': 995 objekti.select_set(True) 996 objekti.scale = (0.01, 0.01, 0.01) 997 objekti.rotation_euler[0] = 1.5708 998 objekti.rotation_euler[2] = 1.5708 999 bpy.ops.object.transforms_to_deltas(mode='ROT') 1000 bpy.ops.object.transforms_to_deltas(mode='SCALE') 1001 objekti.coat3D.applink_firsttime = False 1002 objekti.select_set(False) 1003 1004 elif objekti.coat3D.applink_firsttime == True: 1005 objekti.scale = (objekti.scale[0]/objekti.coat3D.applink_scale[0],objekti.scale[1]/objekti.coat3D.applink_scale[1],objekti.scale[2]/objekti.coat3D.applink_scale[2]) 1006 #bpy.ops.object.transforms_to_deltas(mode='SCALE') 1007 if(objekti.coat3D.applink_onlyone == False): 1008 objekti.rotation_euler = (0,0,0) 1009 objekti.coat3D.applink_firsttime = False 1010 1011 if(coat3D.importlevel): 1012 obj_proxy.select = True 1013 obj_proxy.modifiers.new(name='temp',type='MULTIRES') 1014 objekti.select = True 1015 bpy.ops.object.multires_reshape(modifier=multires_name) 1016 bpy.ops.object.select_all(action='TOGGLE') 1017 else: 1018 1019 bpy.context.view_layer.objects.active = obj_proxy 1020 keep_materials_count = len(obj_proxy.material_slots) - len(objekti.material_slots) 1021 1022 #delete_materials_from_end(keep_materials_count, obj_proxy) 1023 1024 1025 updatemesh(objekti,obj_proxy, texturelist) 1026 bpy.context.view_layer.objects.active = objekti 1027 1028 1029 1030 #tärkee että saadaan oikein käännettyä objekt 1031 1032 objekti.select_set(True) 1033 1034 if (use_smooth): 1035 for data_mesh in objekti.data.polygons: 1036 data_mesh.use_smooth = True 1037 else: 1038 for data_mesh in objekti.data.polygons: 1039 data_mesh.use_smooth = False 1040 1041 bpy.ops.object.select_all(action='DESELECT') 1042 1043 if(coat3D.importmesh and not(os.path.isfile(objekti.coat3D.applink_address))): 1044 coat3D.importmesh = False 1045 1046 objekti.select_set(True) 1047 if(coat3D.importtextures): 1048 is_new = False 1049 if(objekti.coat3D.retopo == False): 1050 tex.matlab(objekti,mat_list,texturelist,is_new) 1051 objekti.select_set(False) 1052 else: 1053 mat_list = [] 1054 if (objekti.material_slots): 1055 for obj_mat in objekti.material_slots: 1056 mat_list.append(obj_mat.material) 1057 1058 if (coat3D.importtextures): 1059 is_new = False 1060 if(objekti.coat3D.retopo == False): 1061 tex.matlab(objekti,mat_list,texturelist, is_new) 1062 objekti.select_set(False) 1063 1064 if(coat3D.remove_path == True): 1065 if(os.path.isfile(path3b_n)): 1066 os.remove(path3b_n) 1067 coat3D.remove_path = False 1068 1069 bpy.ops.object.select_all(action='DESELECT') 1070 if(import_list): 1071 1072 for del_obj in diff_objects: 1073 1074 if(bpy.context.collection.all_objects[del_obj].coat3D.type == 'vox' and bpy.context.collection.all_objects[del_obj].coat3D.delete_proxy_mesh == False): 1075 bpy.context.collection.all_objects[del_obj].select_set(True) 1076 objekti = bpy.context.collection.all_objects[del_obj] 1077 #bpy.ops.object.transforms_to_deltas(mode='ROT') 1078 objekti.scale = (1, 1, 1) 1079 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') 1080 1081 objekti.data.coat3D.name = '3DC' 1082 1083 objekti.coat3D.objecttime = str(os.path.getmtime(objekti.coat3D.applink_address)) 1084 objekti.coat3D.applink_name = objekti.name 1085 objekti.coat3D.applink_mesh = True 1086 objekti.coat3D.import_mesh = False 1087 1088 #bpy.ops.object.transforms_to_deltas(mode='SCALE') 1089 objekti.coat3D.applink_firsttime = False 1090 bpy.context.collection.all_objects[del_obj].select_set(False) 1091 1092 else: 1093 bpy.context.collection.all_objects[del_obj].select_set(True) 1094 bpy.data.objects.remove(bpy.data.objects[del_obj]) 1095 1096 if (coat3D.bring_retopo or coat3D.bring_retopo_path): 1097 if(os.path.isfile(coat3D.bring_retopo_path)): 1098 bpy.ops.import_scene.fbx(filepath=coat3D.bring_retopo_path, global_scale=1, axis_forward='X', use_custom_normals=False) 1099 os.remove(coat3D.bring_retopo_path) 1100 1101 kokeilu = coat3D.exchangeFolder[:-9] 1102 Blender_folder2 = ("%s%sExchange" % (kokeilu, os.sep)) 1103 Blender_folder2 += ('%sexport.txt' % (os.sep)) 1104 if (os.path.isfile(Blender_folder2)): 1105 os.remove(Blender_folder2) 1106 1107def blender_3DC(texturelist, new_applink_address): 1108 1109 bpy.ops.object.select_all(action='DESELECT') 1110 for old_obj in bpy.context.collection.objects: 1111 old_obj.coat3D.applink_old = True 1112 1113 coat3D = bpy.context.scene.coat3D 1114 Blender_folder = ("%s%sBlender"%(coat3D.exchangeFolder,os.sep)) 1115 Blender_export = Blender_folder 1116 path3b_now = coat3D.exchangeFolder + os.sep 1117 path3b_now += ('last_saved_3b_file.txt') 1118 Blender_export += ('%sexport.txt'%(os.sep)) 1119 mat_list = [] 1120 osoite_3b = '' 1121 if (os.path.isfile(path3b_now)): 1122 path3b_fil = open(path3b_now) 1123 for lin in path3b_fil: 1124 osoite_3b = lin 1125 path3b_fil.close() 1126 head, tail = os.path.split(osoite_3b) 1127 just_3b_name = tail 1128 os.remove(path3b_now) 1129 1130 create_collection = True 1131 for collection in bpy.data.collections: 1132 if collection.name == 'Applink_Objects': 1133 create_collection = False 1134 1135 if create_collection: 1136 bpy.data.collections.new('Applink_Objects') 1137 1138 coll_items = bpy.context.scene.collection.children.items() 1139 1140 add_applink_collection = True 1141 for coll in coll_items: 1142 if coll[0] == 'Applink_Objects': 1143 add_applink_collection = False 1144 1145 if add_applink_collection: 1146 bpy.context.scene.collection.children.link(bpy.data.collections['Applink_Objects']) 1147 1148 bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children['Applink_Objects'] 1149 1150 old_materials = bpy.data.materials.keys() 1151 old_objects = bpy.data.objects.keys() 1152 1153 bpy.ops.import_scene.fbx(filepath=new_applink_address, global_scale = 1, axis_forward='-Z', axis_up='Y') 1154 1155 new_materials = bpy.data.materials.keys() 1156 new_objects = bpy.data.objects.keys() 1157 1158 diff_mat = [i for i in new_materials if i not in old_materials] 1159 diff_objects = [i for i in new_objects if i not in old_objects] 1160 1161 1162 for mark_mesh in diff_mat: 1163 bpy.data.materials[mark_mesh].coat3D.name = '3DC' 1164 bpy.data.materials[mark_mesh].use_fake_user = True 1165 laskuri = 0 1166 index = 0 1167 1168 facture_object = False 1169 1170 for c_index in diff_objects: 1171 bpy.data.objects[c_index].data.coat3D.name = '3DC' 1172 laskuri += 1 1173 if(laskuri == 2 and c_index == ('vt_' + diff_objects[0])): 1174 facture_object = True 1175 print('Facture object founded!!') 1176 1177 #bpy.ops.object.transforms_to_deltas(mode='SCALE') 1178 bpy.ops.object.select_all(action='DESELECT') 1179 for new_obj in bpy.context.collection.objects: 1180 1181 if(new_obj.coat3D.applink_old == False): 1182 new_obj.select_set(True) 1183 new_obj.coat3D.applink_firsttime = False 1184 new_obj.select_set(False) 1185 new_obj.coat3D.type = 'ppp' 1186 new_obj.coat3D.applink_address = new_applink_address 1187 new_obj.coat3D.applink_mesh = True 1188 new_obj.coat3D.objecttime = str(os.path.getmtime(new_obj.coat3D.applink_address)) 1189 1190 new_obj.coat3D.applink_name = new_obj.name 1191 index = index + 1 1192 1193 bpy.context.view_layer.objects.active = new_obj 1194 1195 new_obj.coat3D.applink_export = True 1196 1197 if (os.path.isfile(osoite_3b)): 1198 mesh_time = os.path.getmtime(new_obj.coat3D.applink_address) 1199 b_time = os.path.getmtime(osoite_3b) 1200 if (abs(mesh_time-b_time) < 240): 1201 new_obj.coat3D.applink_3b_path = osoite_3b 1202 new_obj.coat3D.applink_3b_just_name = just_3b_name 1203 1204 mat_list.append(new_obj.material_slots[0].material) 1205 is_new = True 1206 1207 if(facture_object): 1208 texVR.matlab(new_obj, mat_list, texturelist, is_new) 1209 new_obj.scale = (0.01, 0.01, 0.01) 1210 else: 1211 tex.matlab(new_obj, mat_list, texturelist, is_new) 1212 1213 mat_list.pop() 1214 1215 for new_obj in bpy.context.collection.objects: 1216 if(new_obj.coat3D.applink_old == False): 1217 new_obj.coat3D.applink_old = True 1218 1219 kokeilu = coat3D.exchangeFolder[:-10] 1220 Blender_folder2 = ("%s%sExchange%sBlender" % (kokeilu, os.sep, os.sep)) 1221 Blender_folder2 += ('%sexport.txt' % (os.sep)) 1222 1223 if (os.path.isfile(Blender_export)): 1224 os.remove(Blender_export) 1225 if (os.path.isfile(Blender_folder2)): 1226 os.remove(Blender_folder2) 1227 1228 for material in bpy.data.materials: 1229 if material.use_nodes == True: 1230 for node in material.node_tree.nodes: 1231 if (node.name).startswith('3DC'): 1232 node.location = node.location 1233 1234 1235def workflow1(ExportFolder): 1236 1237 coat3D = bpy.context.scene.coat3D 1238 1239 texturelist = make_texture_list(ExportFolder) 1240 1241 for texturepath in texturelist: 1242 for image in bpy.data.images: 1243 if(image.filepath == texturepath[3] and image.users == 0): 1244 bpy.data.images.remove(image) 1245 1246 path3b_now = coat3D.exchangeFolder 1247 1248 path3b_now += ('last_saved_3b_file.txt') 1249 new_applink_address = 'False' 1250 new_object = False 1251 new_ref_object = False 1252 1253 exportfile3 = coat3D.exchangeFolder 1254 exportfile3 += ('%sexport.txt' % (os.sep)) 1255 1256 if(os.path.isfile(exportfile3)): 1257 1258 obj_pathh = open(exportfile3) 1259 1260 for line in obj_pathh: 1261 new_applink_address = line 1262 break 1263 obj_pathh.close() 1264 for scene_objects in bpy.context.collection.all_objects: 1265 if(scene_objects.type == 'MESH'): 1266 if(scene_objects.coat3D.applink_address == new_applink_address and scene_objects.coat3D.type == 'ref'): 1267 scene_objects.coat3D.type == '' 1268 new_ref_object = True 1269 nimi = scene_objects.name 1270 1271 1272 1273 1274 exportfile = coat3D.exchangeFolder 1275 exportfile += ('%sBlender' % (os.sep)) 1276 exportfile += ('%sexport.txt' % (os.sep)) 1277 if (os.path.isfile(exportfile)): 1278 os.remove(exportfile) 1279 1280 if(new_ref_object): 1281 1282 new_ref_function(new_applink_address, nimi) 1283 1284 else: 1285 blender_3DC_blender(texturelist, new_applink_address) 1286 1287def workflow2(BlenderFolder): 1288 1289 coat3D = bpy.context.scene.coat3D 1290 1291 texturelist = make_texture_list(BlenderFolder) 1292 1293 for texturepath in texturelist: 1294 for image in bpy.data.images: 1295 if(image.filepath == texturepath[3] and image.users == 0): 1296 bpy.data.images.remove(image) 1297 1298 kokeilu = coat3D.exchangeFolder 1299 1300 Blender_export = os.path.join(kokeilu, 'Blender') 1301 1302 path3b_now = coat3D.exchangeFolder 1303 1304 path3b_now += ('last_saved_3b_file.txt') 1305 Blender_export += ('%sexport.txt'%(os.sep)) 1306 new_applink_address = 'False' 1307 new_object = False 1308 new_ref_object = False 1309 1310 if(os.path.isfile(Blender_export)): 1311 obj_pathh = open(Blender_export) 1312 new_object = True 1313 for line in obj_pathh: 1314 new_applink_address = line 1315 break 1316 obj_pathh.close() 1317 1318 for scene_objects in bpy.context.collection.all_objects: 1319 if(scene_objects.type == 'MESH'): 1320 if(scene_objects.coat3D.applink_address == new_applink_address): 1321 new_object = False 1322 1323 exportfile = coat3D.exchangeFolder 1324 exportfile += ('%sBlender' % (os.sep)) 1325 exportfile += ('%sexport.txt' % (os.sep)) 1326 if (os.path.isfile(exportfile)): 1327 os.remove(exportfile) 1328 1329 if(new_ref_object): 1330 1331 new_ref_function(new_applink_address, nimi) 1332 1333 else: 1334 1335 blender_3DC(texturelist, new_applink_address) 1336 1337from bpy import * 1338from mathutils import Vector, Matrix 1339 1340class SCENE_PT_Main(bpy.types.Panel): 1341 bl_label = "3D-Coat Applink" 1342 bl_space_type = "VIEW_3D" 1343 bl_region_type = "UI" 1344 bl_category = '3D-Coat' 1345 1346 @classmethod 1347 def poll(cls, context): 1348 if bpy.context.mode == 'OBJECT': 1349 return True 1350 else: 1351 return False 1352 1353 def draw(self, context): 1354 layout = self.layout 1355 coat3D = bpy.context.scene.coat3D 1356 global foundExchangeFolder 1357 1358 if(foundExchangeFolder == False): 1359 row = layout.row() 1360 row.label(text="Applink didn't find your 3d-Coat/Exchange folder.") 1361 row = layout.row() 1362 row.label(text="Please select it before using Applink.") 1363 row = layout.row() 1364 row.prop(coat3D,"exchangeFolder",text="") 1365 row = layout.row() 1366 row.operator("update_exchange_folder.pilgway_3d_coat", text="Apply folder") 1367 1368 else: 1369 #Here you add your GUI 1370 row = layout.row() 1371 row.prop(coat3D,"type",text = "") 1372 flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) 1373 1374 row = layout.row() 1375 1376 row.operator("export_applink.pilgway_3d_coat", text="Send") 1377 row.operator("getback.pilgway_3d_coat", text="GetBack") 1378 1379 1380class ObjectButtonsPanel(): 1381 bl_space_type = 'PROPERTIES' 1382 bl_region_type = 'WINDOW' 1383 bl_context = "object" 1384 1385class SCENE_PT_Settings(ObjectButtonsPanel,bpy.types.Panel): 1386 bl_label = "3D-Coat Applink Settings" 1387 bl_space_type = "PROPERTIES" 1388 bl_region_type = "WINDOW" 1389 bl_context = "scene" 1390 1391 def draw(self, context): 1392 pass 1393 1394class MaterialButtonsPanel(): 1395 bl_space_type = 'PROPERTIES' 1396 bl_region_type = 'WINDOW' 1397 bl_context = "material" 1398 1399class SCENE_PT_Material(MaterialButtonsPanel,bpy.types.Panel): 1400 bl_label = "3D-Coat Applink" 1401 bl_space_type = "PROPERTIES" 1402 bl_region_type = "WINDOW" 1403 bl_context = "material" 1404 1405 def draw(self, context): 1406 pass 1407 1408class SCENE_PT_Material_Import(MaterialButtonsPanel, bpy.types.Panel): 1409 bl_label = "Import Textures:" 1410 bl_parent_id = "SCENE_PT_Material" 1411 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 1412 1413 def draw(self, context): 1414 layout = self.layout 1415 layout.use_property_split = False 1416 coat3D = bpy.context.active_object.active_material 1417 1418 layout.active = True 1419 1420 flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) 1421 1422 col = flow.column() 1423 col.prop(coat3D, "coat3D_diffuse", text="Diffuse") 1424 col.prop(coat3D, "coat3D_metalness", text="Metalness") 1425 col.prop(coat3D, "coat3D_roughness", text="Roughness") 1426 col.prop(coat3D, "coat3D_ao", text="AO") 1427 col = flow.column() 1428 col.prop(coat3D, "coat3D_normal", text="NormalMap") 1429 col.prop(coat3D, "coat3D_displacement", text="Displacement") 1430 col.prop(coat3D, "coat3D_emissive", text="Emissive") 1431 col.prop(coat3D, "coat3D_alpha", text="Alpha") 1432 1433 1434 1435class SCENE_PT_Settings_Update(ObjectButtonsPanel, bpy.types.Panel): 1436 bl_label = "Update" 1437 bl_parent_id = "SCENE_PT_Settings" 1438 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 1439 1440 def draw(self, context): 1441 layout = self.layout 1442 layout.use_property_split = False 1443 coat3D = bpy.context.scene.coat3D 1444 1445 layout.active = True 1446 1447 flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) 1448 1449 col = flow.column() 1450 col.prop(coat3D, "importmesh", text="Update Mesh/UV") 1451 col = flow.column() 1452 col.prop(coat3D, "createnodes", text="Create Extra Nodes") 1453 col = flow.column() 1454 col.prop(coat3D, "importtextures", text="Update Textures") 1455 col = flow.column() 1456 col.prop(coat3D, "exportmod", text="Export with modifiers") 1457 1458class SCENE_PT_Bake_Settings(ObjectButtonsPanel, bpy.types.Panel): 1459 bl_label = "Bake" 1460 bl_parent_id = "SCENE_PT_Settings" 1461 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 1462 1463 def draw(self, context): 1464 layout = self.layout 1465 layout.use_property_split = False 1466 coat3D = bpy.context.scene.coat3D 1467 1468 layout.active = True 1469 1470 flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) 1471 1472 col = flow.column() 1473 col.prop(coat3D, "bake_resolution", text="Resolution") 1474 col = flow.column() 1475 col.prop(coat3D, "bake_diffuse", text="Diffuse") 1476 col = flow.column() 1477 col.prop(coat3D, "bake_ao", text="AO") 1478 col = flow.column() 1479 col.prop(coat3D, "bake_normal", text="Normal") 1480 col = flow.column() 1481 col.prop(coat3D, "bake_roughness", text="Roughness") 1482 1483class SCENE_PT_Settings_Folders(ObjectButtonsPanel, bpy.types.Panel): 1484 bl_label = "Folders" 1485 bl_parent_id = "SCENE_PT_Settings" 1486 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 1487 1488 def draw(self, context): 1489 layout = self.layout 1490 layout.use_property_split = False 1491 coat3D = bpy.context.scene.coat3D 1492 1493 layout.active = True 1494 1495 flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) 1496 1497 col = flow.column() 1498 col.prop(coat3D, "exchangeFolder", text="Exchange folder") 1499 1500 col = flow.column() 1501 col.prop(coat3D, "defaultfolder", text="Object/Texture folder") 1502 1503 col = flow.column() 1504 col.prop(coat3D, "folder_size", text="Max count in Applink folder") 1505 1506class SCENE_PT_Settings_DeleteNodes(ObjectButtonsPanel, bpy.types.Panel): 1507 bl_label = "Delete 3DC nodes from selected..." 1508 bl_parent_id = "SCENE_PT_Settings" 1509 COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} 1510 1511 def draw(self, context): 1512 layout = self.layout 1513 layout.use_property_split = False 1514 coat3D = bpy.context.scene.coat3D 1515 1516 layout.active = True 1517 1518 flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) 1519 1520 col = flow.column() 1521 col.operator("delete_material_nodes.pilgway_3d_coat", text="Material") 1522 1523 col.operator("delete_object_nodes.pilgway_3d_coat", text="Object(s)") 1524 1525 col = flow.column() 1526 col.operator("delete_collection_nodes.pilgway_3d_coat", text="Collection") 1527 1528 col.operator("delete_scene_nodes.pilgway_3d_coat", text="Scene") 1529 1530 col = flow.column() 1531 col.prop(coat3D, "delete_images", text="Delete nodes images") 1532 1533 1534 1535 1536# 3D-Coat Dynamic Menu 1537class VIEW3D_MT_Coat_Dynamic_Menu(bpy.types.Menu): 1538 bl_label = "3D-Coat Applink Menu" 1539 1540 def draw(self, context): 1541 layout = self.layout 1542 1543 layout.operator_context = 'INVOKE_REGION_WIN' 1544 1545 ob = context 1546 if ob.mode == 'OBJECT': 1547 if(len(context.selected_objects) > 0): 1548 layout.operator("import_applink.pilgway_3d_coat", 1549 text="Update Scene") 1550 layout.separator() 1551 1552 layout.operator("export_applink.pilgway_3d_coat", 1553 text="Transfer to 3D-Coat") 1554 layout.separator() 1555 1556 if(context.selected_objects[0].coat3D.applink_3b_path != ''): 1557 layout.operator("open_3dcoat.pilgway_3d_coat", 1558 text="Open " +context.selected_objects[0].coat3D.applink_3b_just_name) 1559 layout.separator() 1560 1561 else: 1562 layout.operator("import_applink.pilgway_3d_coat", 1563 text="Update Scene") 1564 layout.separator() 1565 1566 if (len(context.selected_objects) > 0): 1567 layout.operator("delete_material_nodes.pilgway_3d_coat", 1568 text="Delete 3D-Coat nodes from active material") 1569 1570 layout.operator("delete_object_nodes.pilgway_3d_coat", 1571 text="Delete 3D-Coat nodes from selected objects") 1572 1573 layout.operator("delete_collection_nodes.pilgway_3d_coat", 1574 text="Delete 3D-Coat nodes from active collection") 1575 1576 layout.operator("delete_scene_nodes.pilgway_3d_coat", 1577 text="Delete all 3D-Coat nodes") 1578 layout.separator() 1579 1580 1581 1582class ObjectCoat3D(PropertyGroup): 1583 1584 obj_mat: StringProperty( 1585 name="Object_Path", 1586 default='' 1587 ) 1588 applink_address: StringProperty( 1589 name="Object_Applink_address" 1590 ) 1591 applink_index: StringProperty( 1592 name="Object_Applink_address" 1593 ) 1594 applink_3b_path: StringProperty( 1595 name="Object_3B_Path" 1596 ) 1597 applink_name: StringProperty( 1598 name="Applink object name" 1599 ) 1600 applink_3b_just_name: StringProperty( 1601 name="Applink object name" 1602 ) 1603 applink_firsttime: BoolProperty( 1604 name="FirstTime", 1605 description="FirstTime", 1606 default=True 1607 ) 1608 retopo: BoolProperty( 1609 name="Retopo object", 1610 description="Retopo object", 1611 default=False 1612 ) 1613 delete_proxy_mesh: BoolProperty( 1614 name="FirstTime", 1615 description="FirstTime", 1616 default=False 1617 ) 1618 applink_onlyone: BoolProperty( 1619 name="FirstTime", 1620 description="FirstTime", 1621 default=False 1622 ) 1623 type: StringProperty( 1624 name="type", 1625 description="shows type", 1626 default='' 1627 ) 1628 import_mesh: BoolProperty( 1629 name="ImportMesh", 1630 description="ImportMesh", 1631 default=False 1632 ) 1633 applink_mesh: BoolProperty( 1634 name="ImportMesh", 1635 description="ImportMesh", 1636 default=False 1637 ) 1638 applink_old: BoolProperty( 1639 name="OldObject", 1640 description="Old Object", 1641 default=False 1642 ) 1643 applink_export: BoolProperty( 1644 name="FirstTime", 1645 description="Object is from 3d-ocat", 1646 default=False 1647 ) 1648 objecttime: StringProperty( 1649 name="ObjectTime", 1650 subtype="FILE_PATH" 1651 ) 1652 path3b: StringProperty( 1653 name="3B Path", 1654 subtype="FILE_PATH" 1655 ) 1656 dime: FloatVectorProperty( 1657 name="dime", 1658 description="Dimension" 1659 ) 1660 applink_scale: FloatVectorProperty( 1661 name="Scale", 1662 description="Scale" 1663 ) 1664 1665class SceneCoat3D(PropertyGroup): 1666 defaultfolder: StringProperty( 1667 name="FilePath", 1668 subtype="DIR_PATH", 1669 ) 1670 deleteMode: StringProperty( 1671 name="FilePath", 1672 subtype="DIR_PATH", 1673 default='' 1674 ) 1675 coat3D_exe: StringProperty( 1676 name="FilePath", 1677 subtype="FILE_PATH", 1678 ) 1679 exchangeFolder: StringProperty( 1680 name="FilePath", 1681 subtype="DIR_PATH" 1682 ) 1683 bring_retopo: BoolProperty( 1684 name="Import window", 1685 description="Allows to skip import dialog", 1686 default=False 1687 ) 1688 foundExchangeFolder: BoolProperty( 1689 name="found Exchange Folder", 1690 description="found Excahnge folder", 1691 default=False 1692 ) 1693 delete_images: BoolProperty( 1694 name="Import window", 1695 description="Allows to skip import dialog", 1696 default=True 1697 ) 1698 bring_retopo_path: StringProperty( 1699 name="FilePath", 1700 subtype="DIR_PATH", 1701 ) 1702 remove_path: BoolProperty( 1703 name="Import window", 1704 description="Allows to skip import dialog", 1705 default=False 1706 ) 1707 exchange_found: BoolProperty( 1708 name="Exchange Found", 1709 description="Alert if Exchange folder is not found", 1710 default=True 1711 ) 1712 exportfile: BoolProperty( 1713 name="No Import File", 1714 description="Add Modifiers and export", 1715 default=False 1716 ) 1717 importmod: BoolProperty( 1718 name="Remove Modifiers", 1719 description="Import and add modifiers", 1720 default=False 1721 ) 1722 exportmod: BoolProperty( 1723 name="Modifiers", 1724 description="Export modifiers", 1725 default=False 1726 ) 1727 importtextures: BoolProperty( 1728 name="Bring Textures", 1729 description="Import Textures", 1730 default=True 1731 ) 1732 createnodes: BoolProperty( 1733 name="Bring Textures", 1734 description="Import Textures", 1735 default=True 1736 ) 1737 importlevel: BoolProperty( 1738 name="Multires. Level", 1739 description="Bring Specific Multires Level", 1740 default=False 1741 ) 1742 importmesh: BoolProperty( 1743 name="Mesh", 1744 description="Import Mesh", 1745 default=True 1746 ) 1747 1748 # copy location 1749 1750 loca: FloatVectorProperty( 1751 name="location", 1752 description="Location", 1753 subtype="XYZ", 1754 default=(0.0, 0.0, 0.0) 1755 ) 1756 rota: FloatVectorProperty( 1757 name="location", 1758 description="Location", 1759 subtype="EULER", 1760 default=(0.0, 0.0, 0.0) 1761 ) 1762 scal: FloatVectorProperty( 1763 name="location", 1764 description="Location", 1765 subtype="XYZ", 1766 default=(0.0, 0.0, 0.0) 1767 ) 1768 dime: FloatVectorProperty( 1769 name="dimension", 1770 description="Dimension", 1771 subtype="XYZ", 1772 default=(0.0, 0.0, 0.0) 1773 ) 1774 type: EnumProperty( 1775 name="Export Type", 1776 description="Different Export Types", 1777 items=(("ppp", "Per-Pixel Painting", ""), 1778 ("mv", "Microvertex Painting", ""), 1779 ("ptex", "Ptex Painting", ""), 1780 ("uv", "UV-Mapping", ""), 1781 ("ref", "Reference Mesh", ""), 1782 ("retopo", "Retopo mesh as new layer", ""), 1783 ("vox", "Mesh As Voxel Object", ""), 1784 ("alpha", "Mesh As New Pen Alpha", ""), 1785 ("prim", "Mesh As Voxel Primitive", ""), 1786 ("curv", "Mesh As a Curve Profile", ""), 1787 ("autopo", "Mesh For Auto-retopology", ""), 1788 ("update", "Update mesh/uvs", ""), 1789 ), 1790 default="ppp" 1791 ) 1792 bake_resolution: EnumProperty( 1793 name="Bake Resolution", 1794 description="Bake resolution.", 1795 items=(("res_64", "64 x 64", ""), 1796 ("res_128", "128 x 128", ""), 1797 ("res_256", "256 x 256", ""), 1798 ("res_512", "512 x 512", ""), 1799 ("res_1024", "1024 x 1024", ""), 1800 ("res_2048", "2048 x 2048", ""), 1801 ("res_4096", "4096 x 4096", ""), 1802 ("res_8192", "8192 x 8192", ""), 1803 ), 1804 default="res_1024" 1805 ) 1806 folder_size: EnumProperty( 1807 name="Applink folder size", 1808 description="Applink folder size.", 1809 items=(("10", "10", ""), 1810 ("100", "100", ""), 1811 ("500", "500", ""), 1812 ("1000", "1000", ""), 1813 ("5000", "5000", ""), 1814 ("10000", "10000", ""), 1815 ), 1816 default="500" 1817 ) 1818 bake_textures: BoolProperty( 1819 name="Bake all textures", 1820 description="Add Modifiers and export", 1821 default=False 1822 ) 1823 bake_diffuse: BoolProperty( 1824 name="Bake diffuse texture", 1825 description="Add Modifiers and export", 1826 default=False 1827 ) 1828 bake_ao: BoolProperty( 1829 name="Bake AO texture", 1830 description="Add Modifiers and export", 1831 default=False 1832 ) 1833 bake_roughness: BoolProperty( 1834 name="Bake roughness texture", 1835 description="Add Modifiers and export", 1836 default=False 1837 ) 1838 bake_metalness: BoolProperty( 1839 name="Bake metalness texture", 1840 description="Add Modifiers and export", 1841 default=False 1842 ) 1843 bake_emissive: BoolProperty( 1844 name="Bake emissive texture", 1845 description="Add Modifiers and export", 1846 default=False 1847 ) 1848 bake_normal: BoolProperty( 1849 name="Bake normal texture", 1850 description="Add Modifiers and export", 1851 default=False 1852 ) 1853 bake_displacement: BoolProperty( 1854 name="Bake displacement", 1855 description="Add Modifiers and export", 1856 default=False 1857 ) 1858 1859class MeshCoat3D(PropertyGroup): 1860 applink_address: StringProperty( 1861 name="ApplinkAddress", 1862 # subtype="APPLINK_ADDRESS", 1863 ) 1864 1865class MaterialCoat3D(PropertyGroup): 1866 name: StringProperty( 1867 name="ApplinkAddress", 1868 # subtype="APPLINK_ADDRESS", 1869 default='' 1870 ) 1871 bring_diffuse: BoolProperty( 1872 name="Import diffuse texture", 1873 description="Import diffuse texture", 1874 default=True 1875 ) 1876 bring_metalness: BoolProperty( 1877 name="Import diffuse texture", 1878 description="Import diffuse texture", 1879 default=True 1880 ) 1881 bring_roughness: BoolProperty( 1882 name="Import diffuse texture", 1883 description="Import diffuse texture", 1884 default=True 1885 ) 1886 bring_normal: BoolProperty( 1887 name="Import diffuse texture", 1888 description="Import diffuse texture", 1889 default=True 1890 ) 1891 bring_displacement: BoolProperty( 1892 name="Import diffuse texture", 1893 description="Import diffuse texture", 1894 default=True 1895 ) 1896 bring_emissive: BoolProperty( 1897 name="Import diffuse texture", 1898 description="Import diffuse texture", 1899 default=True 1900 ) 1901 bring_gloss: BoolProperty( 1902 name="Import diffuse texture", 1903 description="Import diffuse texture", 1904 default=True 1905 ) 1906 1907classes = ( 1908 SCENE_PT_Main, 1909 SCENE_PT_Settings, 1910 SCENE_PT_Material, 1911 SCENE_PT_Settings_Update, 1912 SCENE_PT_Bake_Settings, 1913 SCENE_PT_Settings_DeleteNodes, 1914 SCENE_PT_Settings_Folders, 1915 SCENE_PT_Material_Import, 1916 SCENE_OT_folder, 1917 SCENE_OT_opencoat, 1918 SCENE_OT_export, 1919 SCENE_OT_getback, 1920 SCENE_OT_delete_material_nodes, 1921 SCENE_OT_delete_object_nodes, 1922 SCENE_OT_delete_collection_nodes, 1923 SCENE_OT_delete_scene_nodes, 1924 VIEW3D_MT_Coat_Dynamic_Menu, 1925 ObjectCoat3D, 1926 SceneCoat3D, 1927 MeshCoat3D, 1928 MaterialCoat3D, 1929 ) 1930 1931def register(): 1932 1933 bpy.types.Material.coat3D_diffuse = BoolProperty( 1934 name="Import diffuse texture", 1935 description="Import diffuse texture", 1936 default=True 1937 ) 1938 bpy.types.Material.coat3D_roughness = BoolProperty( 1939 name="Import diffuse texture", 1940 description="Import diffuse texture", 1941 default=True 1942 ) 1943 bpy.types.Material.coat3D_metalness = BoolProperty( 1944 name="Import diffuse texture", 1945 description="Import diffuse texture", 1946 default=True 1947 ) 1948 bpy.types.Material.coat3D_normal = BoolProperty( 1949 name="Import diffuse texture", 1950 description="Import diffuse texture", 1951 default=True 1952 ) 1953 bpy.types.Material.coat3D_displacement = BoolProperty( 1954 name="Import diffuse texture", 1955 description="Import diffuse texture", 1956 default=True 1957 ) 1958 bpy.types.Material.coat3D_emissive = BoolProperty( 1959 name="Import diffuse texture", 1960 description="Import diffuse texture", 1961 default=True 1962 ) 1963 bpy.types.Material.coat3D_ao = BoolProperty( 1964 name="Import diffuse texture", 1965 description="Import diffuse texture", 1966 default=True 1967 ) 1968 bpy.types.Material.coat3D_alpha = BoolProperty( 1969 name="Import alpha texture", 1970 description="Import alpha texture", 1971 default=True 1972 ) 1973 bpy.types.Material.coat3D_gloss = BoolProperty( 1974 name="Import alpha texture", 1975 description="Import alpha texture", 1976 default=True 1977 ) 1978 1979 1980 1981 1982 from bpy.utils import register_class 1983 for cls in classes: 1984 register_class(cls) 1985 1986 bpy.types.Object.coat3D = PointerProperty(type=ObjectCoat3D) 1987 bpy.types.Scene.coat3D = PointerProperty(type=SceneCoat3D) 1988 bpy.types.Mesh.coat3D = PointerProperty(type=MeshCoat3D) 1989 bpy.types.Material.coat3D = PointerProperty(type=MaterialCoat3D) 1990 bpy.app.handlers.load_post.append(load_handler) 1991 1992 kc = bpy.context.window_manager.keyconfigs.addon 1993 1994 if kc: 1995 km = kc.keymaps.new(name="3D View", space_type="VIEW_3D") 1996 kmi = km.keymap_items.new('wm.call_menu', 'Q', 'PRESS', shift=True) 1997 kmi.properties.name = "VIEW3D_MT_Coat_Dynamic_Menu" 1998 1999def unregister(): 2000 2001 import bpy 2002 from bpy.utils import unregister_class 2003 2004 del bpy.types.Object.coat3D 2005 del bpy.types.Scene.coat3D 2006 del bpy.types.Material.coat3D 2007 bpy.types.Material.coat3D_diffuse 2008 bpy.types.Material.coat3D_metalness 2009 bpy.types.Material.coat3D_roughness 2010 bpy.types.Material.coat3D_normal 2011 bpy.types.Material.coat3D_displacement 2012 bpy.types.Material.coat3D_emissive 2013 bpy.types.Material.coat3D_alpha 2014 2015 kc = bpy.context.window_manager.keyconfigs.addon 2016 if kc: 2017 km = kc.keymaps.get('3D View') 2018 for kmi in km.keymap_items: 2019 if kmi.idname == 'wm.call_menu': 2020 if kmi.properties.name == "VIEW3D_MT_Coat_Dynamic_Menu": 2021 km.keymap_items.remove(kmi) 2022 2023 for cls in reversed(classes): 2024 unregister_class(cls) 2025