Blend_3D_collections/main/Exporter.py

247 wiersze
9.5 KiB
Python

# Purpose:
# This file takes a given Batch created by DNA_Generator.py and tells blender to render the image or export a 3D model to
# the NFT_Output folder.
import bpy
import os
import time
import json
from .loading_animation import Loader
class bcolors:
'''
The colour of console messages.
'''
OK = '\033[92m' # GREEN
WARNING = '\033[93m' # YELLOW
ERROR = '\033[91m' # RED
RESET = '\033[0m' # RESET COLOR
def getBatchData(batchToGenerate, batch_json_save_path):
"""
Retrieves a given batches data determined by renderBatch in config.py
"""
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
batch = json.load(open(file_name))
NFTs_in_Batch = batch["NFTs_in_Batch"]
hierarchy = batch["hierarchy"]
BatchDNAList = batch["BatchDNAList"]
return NFTs_in_Batch, hierarchy, BatchDNAList
def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat
):
"""
Renders the NFT DNA in a Batch#.json, where # is renderBatch in config.py. Turns off the viewport camera and
the render camera for all items in hierarchy.
"""
NFTs_in_Batch, hierarchy, BatchDNAList = getBatchData(batchToGenerate, batch_json_save_path)
time_start_1 = time.time()
x = 1
for a in BatchDNAList:
for i in hierarchy:
for j in hierarchy[i]:
bpy.data.collections[j].hide_render = True
bpy.data.collections[j].hide_viewport = True
def match_DNA_to_Variant(a):
"""
Matches each DNA number separated by "-" to its attribute, then its variant.
"""
listAttributes = list(hierarchy.keys())
listDnaDecunstructed = a.split('-')
dnaDictionary = {}
for i, j in zip(listAttributes, listDnaDecunstructed):
dnaDictionary[i] = j
for x in dnaDictionary:
for k in hierarchy[x]:
kNum = hierarchy[x][k]["number"]
if kNum == dnaDictionary[x]:
dnaDictionary.update({x: k})
return dnaDictionary
dnaDictionary = match_DNA_to_Variant(a)
name = nftName + "_" + str(x)
print(f"\n{bcolors.OK}|---Generating NFT {x}/{NFTs_in_Batch} ---|{bcolors.RESET}")
print(f"DNA attribute list:\n{dnaDictionary}\nDNA Code:{a}")
for c in dnaDictionary:
collection = dnaDictionary[c]
if collection != '0':
bpy.data.collections[collection].hide_render = False
bpy.data.collections[collection].hide_viewport = False
time_start_2 = time.time()
batchFolder = os.path.join(nftBatch_save_path, "Batch" + str(batchToGenerate))
imagePath = os.path.join(batchFolder, "Images", name)
animationPath = os.path.join(batchFolder, "Animations", name)
modelPath = os.path.join(batchFolder, "Models", name)
imageFolder = os.path.join(batchFolder, "Images")
animationFolder = os.path.join(batchFolder, "Animations")
modelFolder = os.path.join(batchFolder, "Models")
metaDataFolder = os.path.join(batchFolder, "BMNFT_metaData")
# Generation/Rendering:
if enableImages:
print(f"{bcolors.OK}---Image---{bcolors.RESET}")
image_render_time_start = time.time()
def render_image():
if not os.path.exists(imageFolder):
os.makedirs(imageFolder)
bpy.context.scene.render.filepath = imagePath
bpy.context.scene.render.image_settings.file_format = imageFileFormat
bpy.ops.render.render(write_still=True)
# Loading Animation:
loading = Loader(f'Rendering Image {x}/{NFTs_in_Batch}...', '').start()
render_image()
loading.stop()
image_render_time_end = time.time()
print(
f"{bcolors.OK}Rendered image in {image_render_time_end - image_render_time_start}s.\n{bcolors.RESET}"
)
if enableAnimations:
print(f"{bcolors.OK}---Animation---{bcolors.RESET}")
animation_render_time_start = time.time()
def render_animation():
if not os.path.exists(animationFolder):
os.makedirs(animationFolder)
bpy.context.scene.render.filepath = animationPath
if animationFileFormat == 'MP4':
bpy.context.scene.render.image_settings.file_format = "FFMPEG"
bpy.context.scene.render.ffmpeg.format = 'MPEG4'
bpy.context.scene.render.ffmpeg.codec = 'H264'
bpy.ops.render.render(animation=True)
else:
bpy.context.scene.render.image_settings.file_format = animationFileFormat
bpy.ops.render.render(animation=True)
# Loading Animation:
loading = Loader(f'Rendering Animation {x}/{NFTs_in_Batch}...', '').start()
render_animation()
loading.stop()
animation_render_time_end = time.time()
print(
f"{bcolors.OK}Rendered animation in {animation_render_time_end - animation_render_time_start}s.\n{bcolors.RESET}"
)
if enableModelsBlender:
print(f"{bcolors.OK}---3D Model---{bcolors.RESET}")
model_generation_time_start = time.time()
def generate_models():
if not os.path.exists(modelFolder):
os.makedirs(modelFolder)
for i in dnaDictionary:
coll = dnaDictionary[i]
if coll != '0':
for obj in bpy.data.collections[coll].all_objects:
obj.select_set(True)
for obj in bpy.data.collections['Script_Ignore'].all_objects:
obj.select_set(True)
if modelFileFormat == 'GLB':
bpy.ops.export_scene.gltf(filepath=f"{modelPath}.glb",
check_existing=True,
export_format='GLB',
use_selection=True)
if modelFileFormat == 'GLTF_SEPARATE':
bpy.ops.export_scene.gltf(filepath=f"{modelPath}",
check_existing=True,
export_format='GLTF_SEPARATE',
use_selection=True)
if modelFileFormat == 'GLTF_EMBEDDED':
bpy.ops.export_scene.gltf(filepath=f"{modelPath}.gltf",
check_existing=True,
export_format='GLTF_EMBEDDED',
use_selection=True)
elif modelFileFormat == 'FBX':
bpy.ops.export_scene.fbx(filepath=f"{modelPath}.fbx",
check_existing=True,
use_selection=True)
elif modelFileFormat == 'OBJ':
bpy.ops.export_scene.obj(filepath=f"{modelPath}.obj",
check_existing=True,
use_selection=True, )
elif modelFileFormat == 'X3D':
bpy.ops.export_scene.x3d(filepath=f"{modelPath}.x3d",
check_existing=True,
use_selection=True)
elif modelFileFormat == 'STL':
bpy.ops.export_mesh.stl(filepath=f"{modelPath}.stl",
check_existing=True,
use_selection=True)
elif modelFileFormat == 'VOX':
bpy.ops.export_vox.some_data(filepath=f"{modelPath}.vox")
# Loading Animation:
loading = Loader(f'Rendering Animation {x}/{NFTs_in_Batch}...', '').start()
generate_models()
loading.stop()
model_generation_time_end = time.time()
print(
f"{bcolors.OK}Generated model in {model_generation_time_end - model_generation_time_start}s.\n{bcolors.RESET}"
)
if not os.path.exists(metaDataFolder):
os.makedirs(metaDataFolder)
for b in dnaDictionary:
if dnaDictionary[b] == "0":
dnaDictionary[b] = "Empty"
metaDataDict = {"name": name, "NFT_DNA": a, "NFT_Variants": dnaDictionary}
jsonMetaData = json.dumps(metaDataDict, indent=1, ensure_ascii=True)
with open(os.path.join(metaDataFolder, "Data_" + name + ".json"), 'w') as outfile:
outfile.write(jsonMetaData + '\n')
print(f"Completed {name} render in {time.time() - time_start_2}s")
x += 1
for i in hierarchy:
for j in hierarchy[i]:
bpy.data.collections[j].hide_render = False
bpy.data.collections[j].hide_viewport = False
print(f"\nAll NFTs successfully generated and sent to {nftBatch_save_path}"
f"\nCompleted all renders in Batch{batchToGenerate}.json in {time.time() - time_start_1}s\n")