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