__init__.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. # ----------------------------------------------------------
  2. # File __init__.py
  3. # ----------------------------------------------------------
  4. # Imports
  5. # Check if this add-on is being reloaded
  6. if "bpy" in locals():
  7. # reloading .py files
  8. import bpy
  9. import importlib
  10. # from . import zs_renderscene as zsrs
  11. # importlib.reload(zsrs)
  12. # or if this is the first load of this add-on
  13. else:
  14. import bpy
  15. import json
  16. from pathlib import Path
  17. # from . import zs_renderscene as zsrs # noqa
  18. # Addon info
  19. bl_info = {
  20. "name": "ZS Stable Diffusion Connection V0.0.1",
  21. "author": "Sergiu <sergiu@zixelise.com>",
  22. "Version": (0, 0, 1),
  23. "blender": (4, 00, 0),
  24. "category": "Scene",
  25. "description": "Stable Diffusion Connection",
  26. }
  27. # -------------------------------------------------------------------
  28. # Functions
  29. # -------------------------------------------------------------------
  30. def load_scene():
  31. print("Loading Scene")
  32. # load scene data
  33. scene_data = load_scene_data()
  34. # create parent collections
  35. create_parent_collections("01_Products")
  36. create_parent_collections("02_Elements")
  37. create_parent_collections("03_Shapes")
  38. # append products
  39. products_data = load_objects_data(scene_data, "product")
  40. for index, product in enumerate(products_data):
  41. append_objects(product, index)
  42. # append elements
  43. # append shapes
  44. # set lighting
  45. # set camera
  46. def load_scene_data():
  47. print("Loading Scene Data")
  48. # load scene data
  49. # to be replaced with actual data
  50. # open scene_info.json
  51. script_path = Path(__file__).resolve()
  52. scene_data_path = script_path.parent / "sample_scene" / "scene_info.json"
  53. with scene_data_path.open() as file:
  54. scene_data = json.load(file)
  55. print(scene_data)
  56. return scene_data
  57. def load_objects_data(scene_data, object_type: str):
  58. print("Loading Assets Data")
  59. # load assets data
  60. objects_data = []
  61. for object in scene_data["scene"]["objects"]:
  62. if object["group_type"] == object_type:
  63. # get additional object data by id and combine with object data
  64. object_data = get_object_data_by_id(object["id"])
  65. object.update(object_data)
  66. objects_data.append(object)
  67. return objects_data
  68. # to be replaced with actual data
  69. def get_object_data_by_id(object_id: str):
  70. print("Getting Object Data")
  71. # open assets_database.json
  72. script_path = Path(__file__).resolve()
  73. assets_data_path = script_path.parent / "sample_scene" / "assets_database.json"
  74. with assets_data_path.open() as file:
  75. assets_data = json.load(file)
  76. # get object data by id
  77. for object in assets_data:
  78. if object["id"] == object_id:
  79. return object
  80. def append_objects(productInfo, index):
  81. print("Appending Objects")
  82. blendFileName = productInfo["name"]
  83. # visibleLayersJSONName = productInfo["Version"]
  84. # activeSwitchMaterials = json.dumps(productInfo["ActiveMaterials"])
  85. collectionName = blendFileName + "_" + str(index)
  86. append_active_layers(collectionName, productInfo)
  87. # replace_switch_materials(shotInfo, productInfo["ActiveMaterials"])
  88. link_collection_to_collection("01_Products", bpy.data.collections[collectionName])
  89. def append_active_layers(newCollectionName, product_info):
  90. utility_collections = ["MaterialLibrary", "Animation_Controller", "Animation_Rig"]
  91. # visible_layers = utility_collections + product_info["VisibleLayers"]
  92. visible_layers = utility_collections
  93. script_path = Path(__file__).resolve().parent
  94. filePath = str(
  95. script_path / product_info["path"] / (product_info["name"] + ".blend")
  96. )
  97. print(filePath)
  98. # delete all objects and collections from product collection
  99. create_parent_collections(newCollectionName)
  100. # append active collections
  101. with bpy.data.libraries.load(filePath) as (data_from, data_to):
  102. data_to.collections = []
  103. for name in data_from.collections:
  104. if name in visible_layers:
  105. data_to.collections.append(name)
  106. if "NonConfigurable" in name:
  107. data_to.collections.append(name)
  108. # link appended colections to newCollection
  109. for collection in data_to.collections:
  110. # try:
  111. # bpy.context.scene.collection.children.link(collection)
  112. # except:
  113. # print(collection)
  114. link_collection_to_collection(newCollectionName, collection)
  115. # hide utility collections
  116. for utilityCollectionName in utility_collections:
  117. if utilityCollectionName in collection.name:
  118. # rename utility collections
  119. collection.name = newCollectionName + "_" + utilityCollectionName
  120. hide_collection(collection)
  121. #
  122. # make all objects in collection local
  123. for obj in bpy.data.collections[newCollectionName].all_objects:
  124. if obj.type == "MESH":
  125. obj.make_local()
  126. obj.data.make_local()
  127. # remove duplicated material slots
  128. mats = bpy.data.materials
  129. for obj in bpy.data.collections[newCollectionName].all_objects:
  130. for slot in obj.material_slots:
  131. part = slot.name.rpartition(".")
  132. if part[2].isnumeric() and part[0] in mats:
  133. slot.material = mats.get(part[0])
  134. def create_parent_collections(group_name: str):
  135. if collection_exists(group_name):
  136. remove_collection_and_objects(group_name)
  137. else:
  138. create_collection(group_name)
  139. # -------------------------------------------------------------------
  140. # Utilities
  141. # -------------------------------------------------------------------
  142. def remove_collection_and_objects(collection_name):
  143. oldObjects = list(bpy.data.collections[collection_name].all_objects)
  144. for obj in oldObjects:
  145. bpy.data.objects.remove(obj, do_unlink=True)
  146. old_collection = bpy.data.collections[collection_name]
  147. if old_collection is not None:
  148. old_collection_names = get_subcollection_names(old_collection)
  149. else:
  150. print("Collection not found.")
  151. # print line break
  152. print("-----------------------------------------------------------------")
  153. print(old_collection_names)
  154. print("-----------------------------------------------------------------")
  155. for old_collection_name in old_collection_names:
  156. for collection in bpy.data.collections:
  157. if collection.name == old_collection_name:
  158. bpy.data.collections.remove(collection)
  159. bpy.ops.outliner.orphans_purge(
  160. do_local_ids=True, do_linked_ids=True, do_recursive=True
  161. )
  162. def get_subcollection_names(collection):
  163. subcollection_names = []
  164. for child in collection.children:
  165. subcollection_names.append(child.name)
  166. subcollection_names.extend(get_subcollection_names(child))
  167. return subcollection_names
  168. def link_collection_to_collection(parentCollectionName, childCollection):
  169. if bpy.context.scene.collection.children:
  170. parentCollection = bpy.context.scene.collection.children.get(
  171. parentCollectionName
  172. )
  173. # Add it to the main collection
  174. # childCollection = bpy.context.scene.collection.children.get(childCollection)
  175. parentCollection.children.link(childCollection)
  176. # if child collection is in scene collection unlink it
  177. if bpy.context.scene.collection.children.get(childCollection.name):
  178. bpy.context.scene.collection.children.unlink(childCollection)
  179. # bpy.context.scene.collection.children.unlink(childCollection)
  180. # link collection to collection
  181. def link_collection_to_collection_old(parentCollectionName, childCollection):
  182. if bpy.context.scene.collection.children:
  183. parentCollection = bpy.context.scene.collection.children.get(
  184. parentCollectionName
  185. )
  186. # Add it to the main collection
  187. try:
  188. childCollection = bpy.data.collections[childCollection]
  189. except:
  190. print("Collection not found.")
  191. return
  192. parentCollection.children.link(childCollection)
  193. bpy.context.scene.collection.children.unlink(childCollection)
  194. # function that checks if a collection exists
  195. def collection_exists(collection_name):
  196. return collection_name in bpy.data.collections
  197. # function that creates a new collection and adds it to the scene
  198. def create_collection(collection_name):
  199. new_collection = bpy.data.collections.new(collection_name)
  200. bpy.context.scene.collection.children.link(new_collection)
  201. def hide_collection(collection):
  202. collection.hide_render = True
  203. collection.hide_viewport = True
  204. # -------------------------------------------------------------------
  205. # Operators
  206. # -------------------------------------------------------------------
  207. # load scene operator
  208. class ZSSD_OT_LoadScene(bpy.types.Operator):
  209. bl_idname = "zs_sd_loader.load_scene"
  210. bl_label = "Load Scene"
  211. bl_description = "Load Scene"
  212. def execute(self, context):
  213. load_scene()
  214. return {"FINISHED"}
  215. # parent class for panels
  216. class ZSSDPanel:
  217. bl_space_type = "VIEW_3D"
  218. bl_region_type = "UI"
  219. bl_category = "ZS SD Loader"
  220. # -------------------------------------------------------------------
  221. # Draw
  222. # -------------------------------------------------------------------
  223. # Panels
  224. class ZSSD_PT_Main(ZSSDPanel, bpy.types.Panel):
  225. bl_label = "SD Loader"
  226. def draw(self, context):
  227. layout = self.layout
  228. scene = context.scene
  229. col = layout.column()
  230. self.is_connected = False
  231. col.label(text="Stable Diffusion Connection")
  232. # load scene button
  233. col.operator("zs_sd_loader.load_scene", text="Load Scene")
  234. # modify after making products
  235. blender_classes = [
  236. ZSSD_PT_Main,
  237. ZSSD_OT_LoadScene,
  238. ]
  239. def register():
  240. # register classes
  241. for blender_class in blender_classes:
  242. bpy.utils.register_class(blender_class)
  243. # Has to be afqter class registering to correctly register property
  244. # register global properties
  245. # register list
  246. # list data
  247. # bpy.types.Scene.zs_product_list = bpy.props.CollectionProperty(
  248. # type=ZS_Product_ListItem)
  249. # current item in list
  250. def unregister():
  251. # unregister classes
  252. for blender_class in blender_classes:
  253. bpy.utils.unregister_class(blender_class)
  254. # unregister global properties
  255. # unregister list items
  256. # del bpy.types.Scene.my_list
  257. # del bpy.types.Scene.product_product_list_index