kopia lustrzana https://github.com/torrinworx/Blend_My_NFTs
rodzic
f90cb38e2b
commit
d5d4c37456
84
__init__.py
84
__init__.py
|
@ -14,11 +14,9 @@ import bpy
|
|||
from bpy.app.handlers import persistent
|
||||
|
||||
import os
|
||||
import json
|
||||
import importlib
|
||||
|
||||
# Import files from main directory:
|
||||
|
||||
importList = ['DNA_Generator', 'Batch_Sorter', 'Exporter', 'Batch_Refactorer', 'get_combinations', 'UIList']
|
||||
|
||||
if bpy in locals():
|
||||
importlib.reload(DNA_Generator)
|
||||
|
@ -26,13 +24,16 @@ if bpy in locals():
|
|||
importlib.reload(Exporter)
|
||||
importlib.reload(Refactorer)
|
||||
importlib.reload(get_combinations)
|
||||
importlib.reload(Checks)
|
||||
|
||||
else:
|
||||
from .main import \
|
||||
DNA_Generator, \
|
||||
Batch_Sorter, \
|
||||
Exporter, \
|
||||
Refactorer, \
|
||||
get_combinations
|
||||
get_combinations, \
|
||||
Checks
|
||||
|
||||
# User input Property Group:
|
||||
class BMNFTS_PGT_MyProperties(bpy.types.PropertyGroup):
|
||||
|
@ -164,6 +165,7 @@ def update_combinations(dummy1, dummy2):
|
|||
|
||||
bpy.app.handlers.depsgraph_update_post.append(update_combinations)
|
||||
|
||||
|
||||
# Main Operators:
|
||||
class createData(bpy.types.Operator):
|
||||
bl_idname = 'create.data'
|
||||
|
@ -214,16 +216,56 @@ class exportNFTs(bpy.types.Operator):
|
|||
enableModelsBlender = bpy.context.scene.my_tool.modelBool
|
||||
modelFileFormat = bpy.context.scene.my_tool.modelEnum
|
||||
|
||||
# fail state variables, set to no fail due to resume_failed_batch() Operator in BMNFTS_PT_GenerateNFTs Panel
|
||||
fail_state = False
|
||||
failed_batch = None
|
||||
failed_dna = None
|
||||
failed_dna_index = None
|
||||
|
||||
Exporter.render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
|
||||
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
|
||||
modelFileFormat
|
||||
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
|
||||
)
|
||||
|
||||
self.report({'INFO'}, f"All NFTs generated for batch {batchToGenerate}!")
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
class resume_failed_batch(bpy.types.Operator):
|
||||
bl_idname = 'exporter.resume_nfts'
|
||||
bl_label = 'Resume Failed Batch'
|
||||
bl_description = 'Failed Batch detected. Generate NFTs where the previous batch failed?'
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
nftName = bpy.context.scene.my_tool.nftName
|
||||
save_path = bpy.path.abspath(bpy.context.scene.my_tool.save_path)
|
||||
batchToGenerate = bpy.context.scene.my_tool.batchToGenerate
|
||||
maxNFTs = bpy.context.scene.my_tool.collectionSize
|
||||
|
||||
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
|
||||
fail_state, failed_batch, failed_dna, failed_dna_index = Checks.check_FailedBatches(batch_json_save_path)
|
||||
|
||||
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
|
||||
batch = json.load(open(file_name))
|
||||
|
||||
nftBatch_save_path = batch["Generation Save"][-1]["Render_Settings"]["nftBatch_save_path"]
|
||||
enableImages = batch["Generation Save"][-1]["Render_Settings"]["enableImages"]
|
||||
imageFileFormat = batch["Generation Save"][-1]["Render_Settings"]["imageFileFormat"]
|
||||
enableAnimations = batch["Generation Save"][-1]["Render_Settings"]["enableAnimations"]
|
||||
animationFileFormat = batch["Generation Save"][-1]["Render_Settings"]["animationFileFormat"]
|
||||
enableModelsBlender = batch["Generation Save"][-1]["Render_Settings"]["enableModelsBlender"]
|
||||
modelFileFormat = batch["Generation Save"][-1]["Render_Settings"]["modelFileFormat"]
|
||||
|
||||
Exporter.render_and_save_NFTs(nftName, maxNFTs, failed_batch, batch_json_save_path, nftBatch_save_path, enableImages,
|
||||
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
|
||||
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
|
||||
)
|
||||
|
||||
self.report({'INFO'}, f"Resuming Failed Batch Generation!")
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
class refactor_Batches(bpy.types.Operator):
|
||||
"""Refactor your collection? This action cannot be undone."""
|
||||
bl_idname = 'refactor.batches'
|
||||
|
@ -337,9 +379,20 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
|
|||
row = layout.row()
|
||||
row.prop(mytool, "batchToGenerate")
|
||||
|
||||
row = layout.row()
|
||||
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")
|
||||
save_path = bpy.path.abspath(bpy.context.scene.my_tool.save_path)
|
||||
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
|
||||
fail_state, failed_batch, failed_dna, failed_dna_index = Checks.check_FailedBatches(batch_json_save_path)
|
||||
if fail_state:
|
||||
row = layout.row()
|
||||
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")
|
||||
|
||||
row = layout.row()
|
||||
row.alert = True
|
||||
row.operator("exporter.resume_nfts", icon='ERROR', text="Resume Failed Batch")
|
||||
|
||||
if not fail_state:
|
||||
row = layout.row()
|
||||
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")
|
||||
# Refactor Batches & create MetaData Panel:
|
||||
class BMNFTS_PT_Refactor(bpy.types.Panel):
|
||||
bl_label = "Refactor Batches & create MetaData"
|
||||
|
@ -426,21 +479,6 @@ class BMNFTS_PT_Documentation(bpy.types.Panel):
|
|||
# scene = context.scene
|
||||
# mytool = scene.my_tool
|
||||
#
|
||||
# # API Panel:
|
||||
# class BMNFTS_PT_API_Panel(bpy.types.Panel):
|
||||
# bl_label = "API"
|
||||
# bl_idname = "BMNFTS_PT_API_Panel"
|
||||
# bl_space_type = 'VIEW_3D'
|
||||
# bl_region_type = 'UI'
|
||||
# bl_category = 'Blend_My_NFTs'
|
||||
#
|
||||
# def draw(self, context):
|
||||
# layout = self.layout
|
||||
# scene = context.scene
|
||||
# mytool = scene.my_tool
|
||||
#
|
||||
# row = layout.row()
|
||||
# row.prop(mytool, "apiKey")
|
||||
|
||||
def redraw_panel():
|
||||
try:
|
||||
|
@ -460,10 +498,10 @@ classes = (
|
|||
|
||||
# Other panels:
|
||||
# BMNFTS_PT_MATERIALS_Panel,
|
||||
# BMNFTS_PT_API_Panel,
|
||||
|
||||
createData,
|
||||
exportNFTs,
|
||||
resume_failed_batch,
|
||||
refactor_Batches,
|
||||
)
|
||||
|
||||
|
|
|
@ -42,7 +42,9 @@ def makeBatches(nftName, maxNFTs, nftsPerBatch, save_path, batch_json_save_path)
|
|||
j = 0
|
||||
while (j < nftsPerBatch) and (DNAList):
|
||||
oneDNA = random.choice(DNAList)
|
||||
BatchDNAList.append(oneDNA)
|
||||
BatchDNAList.append({
|
||||
oneDNA: {"Complete": False}
|
||||
})
|
||||
DNAList.remove(oneDNA)
|
||||
j += 1
|
||||
|
||||
|
@ -57,7 +59,7 @@ def makeBatches(nftName, maxNFTs, nftsPerBatch, save_path, batch_json_save_path)
|
|||
|
||||
i += 1
|
||||
|
||||
if len(DNAList) > 0:
|
||||
if len(DNAList) > 0: # Add to Checks.py
|
||||
print(f"One batch could not be filled completely and will contain {len(DNAList)} NFTs.")
|
||||
|
||||
incompleteBatch = {"NFTs_in_Batch": int(len(DNAList)), "hierarchy": hierarchy, "BatchDNAList": DNAList}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
# This file is provided for transparency. The accuracy of the rarity values you set in your .blend file as outlined in
|
||||
# the README.md file are dependent on the maxNFTs, and the maximum number of combinations of your NFT collection.
|
||||
|
||||
|
||||
import bpy
|
||||
import os
|
||||
import json
|
||||
|
@ -105,6 +104,27 @@ def check_Duplicates(DNAList):
|
|||
|
||||
print(f"NFTRecord.json contains {duplicates} duplicate NFT DNA.")
|
||||
|
||||
def check_FailedBatches(batch_json_save_path):
|
||||
batch_folders = os.listdir(batch_json_save_path)
|
||||
fail_state = False
|
||||
failed_batch = None
|
||||
failed_dna = None
|
||||
failed_dna_index = None
|
||||
|
||||
for i in batch_folders:
|
||||
batch = json.load(open(os.path.join(batch_json_save_path, i)))
|
||||
NFTs_in_Batch = batch["NFTs_in_Batch"]
|
||||
if "Generation Save" in batch:
|
||||
dna_generated = batch["Generation Save"][-1]["DNA Generated"]
|
||||
if dna_generated < NFTs_in_Batch:
|
||||
fail_state = True
|
||||
failed_batch = int(i.removeprefix("Batch").removesuffix(".json"))
|
||||
failed_dna = dna_generated
|
||||
|
||||
|
||||
return fail_state, failed_batch, failed_dna, failed_dna_index
|
||||
|
||||
|
||||
# Raise Errors:
|
||||
def raise_Error_ScriptIgnore():
|
||||
"""Checks if Script_Ignore collection exists, if not raises error."""
|
||||
|
|
|
@ -6,19 +6,74 @@ import bpy
|
|||
import os
|
||||
import time
|
||||
import json
|
||||
import datetime
|
||||
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
|
||||
"""
|
||||
The colour of console messages.
|
||||
"""
|
||||
OK = '\033[92m' # GREEN
|
||||
WARNING = '\033[93m' # YELLOW
|
||||
ERROR = '\033[91m' # RED
|
||||
RESET = '\033[0m' # RESET COLOR
|
||||
|
||||
|
||||
# Save info
|
||||
def save_batch(batch, file_name):
|
||||
saved_batch = json.dumps(batch, indent=1, ensure_ascii=True)
|
||||
|
||||
with open(os.path.join(file_name), 'w') as outfile:
|
||||
outfile.write(saved_batch + '\n')
|
||||
|
||||
def save_generation_state(batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages, imageFileFormat, enableAnimations,
|
||||
animationFileFormat, enableModelsBlender, modelFileFormat):
|
||||
"""Saves date and time of generation start, and generation types; Images, Animations, 3D Models, and the file types for each."""
|
||||
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
|
||||
batch = json.load(open(file_name))
|
||||
|
||||
CURRENT_TIME = datetime.datetime.now().strftime("%H:%M:%S")
|
||||
CURRENT_DATE = datetime.datetime.now().strftime("%d/%m/%Y")
|
||||
LOCAL_TIMEZONE = str(datetime.datetime.now(datetime.timezone.utc))
|
||||
|
||||
if "Generation Save" in batch:
|
||||
batch_save_number = int(batch[f"Generation Save"].index(batch[f"Generation Save"][-1]))
|
||||
else:
|
||||
batch_save_number = 0
|
||||
|
||||
batch["Generation Save"] = list()
|
||||
batch["Generation Save"].append({
|
||||
"Batch Save Number": batch_save_number + 1,
|
||||
"DNA Generated": None,
|
||||
"Generation Start Date and Time": [CURRENT_TIME, CURRENT_DATE, LOCAL_TIMEZONE],
|
||||
"Render_Settings": {
|
||||
"nftBatch_save_path": nftBatch_save_path,
|
||||
"enableImages": enableImages,
|
||||
"imageFileFormat": imageFileFormat,
|
||||
"enableAnimations": enableAnimations,
|
||||
"animationFileFormat": animationFileFormat,
|
||||
"enableModelsBlender": enableModelsBlender,
|
||||
"modelFileFormat": modelFileFormat,
|
||||
},
|
||||
})
|
||||
|
||||
save_batch(batch, file_name)
|
||||
|
||||
def save_completed(single_dna, a, x, batch_json_save_path, batchToGenerate):
|
||||
"""Saves progress of rendering to batch.json file."""
|
||||
|
||||
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
|
||||
batch = json.load(open(file_name))
|
||||
|
||||
index = batch["BatchDNAList"].index(a)
|
||||
batch["BatchDNAList"][index][single_dna]["Complete"] = True
|
||||
batch["Generation Save"][-1]["DNA Generated"] = x
|
||||
|
||||
save_batch(batch, file_name)
|
||||
|
||||
|
||||
# Exporter functions:
|
||||
def getBatchData(batchToGenerate, batch_json_save_path):
|
||||
"""
|
||||
Retrieves a given batches data determined by renderBatch in config.py
|
||||
|
@ -26,7 +81,7 @@ def getBatchData(batchToGenerate, batch_json_save_path):
|
|||
|
||||
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"]
|
||||
|
@ -35,7 +90,7 @@ def getBatchData(batchToGenerate, batch_json_save_path):
|
|||
|
||||
def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
|
||||
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
|
||||
modelFileFormat
|
||||
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
|
||||
):
|
||||
"""
|
||||
Renders the NFT DNA in a Batch#.json, where # is renderBatch in config.py. Turns off the viewport camera and
|
||||
|
@ -46,20 +101,31 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
|
|||
|
||||
time_start_1 = time.time()
|
||||
|
||||
x = 1
|
||||
if fail_state:
|
||||
for a in range(failed_dna):
|
||||
del BatchDNAList[0]
|
||||
x = failed_dna + 1
|
||||
|
||||
else:
|
||||
save_generation_state(batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages, imageFileFormat,
|
||||
enableAnimations,
|
||||
animationFileFormat, enableModelsBlender, modelFileFormat)
|
||||
x = 1
|
||||
|
||||
for a in BatchDNAList:
|
||||
single_dna = list(a.keys())[0]
|
||||
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):
|
||||
def match_DNA_to_Variant(single_dna):
|
||||
"""
|
||||
Matches each DNA number separated by "-" to its attribute, then its variant.
|
||||
"""
|
||||
|
||||
listAttributes = list(hierarchy.keys())
|
||||
listDnaDecunstructed = a.split('-')
|
||||
listDnaDecunstructed = single_dna.split('-')
|
||||
dnaDictionary = {}
|
||||
|
||||
for i, j in zip(listAttributes, listDnaDecunstructed):
|
||||
|
@ -72,11 +138,11 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
|
|||
dnaDictionary.update({x: k})
|
||||
return dnaDictionary
|
||||
|
||||
dnaDictionary = match_DNA_to_Variant(a)
|
||||
dnaDictionary = match_DNA_to_Variant(single_dna)
|
||||
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}")
|
||||
print(f"DNA attribute list:\n{dnaDictionary}\nDNA Code:{single_dna}")
|
||||
|
||||
for c in dnaDictionary:
|
||||
collection = dnaDictionary[c]
|
||||
|
@ -99,7 +165,6 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
|
|||
metaDataFolder = os.path.join(batchFolder, "BMNFT_metaData")
|
||||
|
||||
# Generation/Rendering:
|
||||
|
||||
if enableImages:
|
||||
print(f"{bcolors.OK}---Image---{bcolors.RESET}")
|
||||
|
||||
|
@ -235,6 +300,9 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
|
|||
outfile.write(jsonMetaData + '\n')
|
||||
|
||||
print(f"Completed {name} render in {time.time() - time_start_2}s")
|
||||
|
||||
save_completed(single_dna, a, x, batch_json_save_path, batchToGenerate)
|
||||
|
||||
x += 1
|
||||
|
||||
for i in hierarchy:
|
||||
|
|
Ładowanie…
Reference in New Issue