Merge pull request #94 from torrinworx/Material_Randomizer_Metapanda

Further integration and creation of the Material_Generator.py
pull/110/head
Torrin Leonard 2022-04-20 18:10:51 -04:00 zatwierdzone przez GitHub
commit 3e0908bfb3
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
4 zmienionych plików z 281 dodań i 69 usunięć

Wyświetl plik

@ -8,7 +8,6 @@ bl_info = {
"category": "Development",
}
# ======== Import handling ======== #
import bpy
@ -34,15 +33,16 @@ from main import \
HeadlessUtil, \
loading_animation, \
Logic, \
Material_Generator, \
Metadata, \
Rarity, \
Refactorer
from UILists import \
Custom_Metadata_UIList, \
Logic_UIList
if "bpy" in locals():
modules = {
"Batch_Sorter": Batch_Sorter,
"Checks": Checks,
@ -52,6 +52,7 @@ if "bpy" in locals():
"HeadlessUtil": HeadlessUtil,
"loading_animation": loading_animation,
"Logic": Logic,
"Material_Generator": Material_Generator,
"Metadata": Metadata,
"Rarity": Rarity,
"Refactorer": Refactorer,
@ -69,6 +70,7 @@ if "bpy" in locals():
combinations: int = 0
recommended_limit: int = 0
@persistent
def Refresh_UI(dummy1, dummy2):
"""
@ -79,7 +81,7 @@ def Refresh_UI(dummy1, dummy2):
global recommended_limit
combinations = (get_combinations.get_combinations())
recommended_limit = int(round(combinations/2))
recommended_limit = int(round(combinations / 2))
# Add panel classes that require refresh to this refresh_panels tuple:
refresh_panel_classes = (
@ -96,6 +98,7 @@ def Refresh_UI(dummy1, dummy2):
redraw_panel(refresh_panel_classes)
bpy.app.handlers.depsgraph_update_post.append(Refresh_UI)
@ -115,10 +118,12 @@ def make_directories(save_path):
os.makedirs(nftBatch_save_path)
return Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path
def runAsHeadless():
"""
For use when running from the command line.
"""
def dumpSettings(settings):
output = (
f"nftName={settings.nftName}\n"
@ -142,6 +147,8 @@ def runAsHeadless():
f"solana_description={settings.solana_description}\n"
f"enableCustomFields={str(settings.enableCustomFields)}\n"
f"customfieldsFile={settings.customfieldsFile}\n"
f"enableMaterials={str(settings.customfieldsFile)}\n"
f"materialsFile={settings.materialsFile}\n"
)
print(output)
@ -179,6 +186,8 @@ def runAsHeadless():
settings.solanaDescription = pairs[18][1]
settings.enableCustomFields = pairs[19][1] == 'True'
settings.customfieldsFile = pairs[20][1]
settings.enableMaterials = pairs[21][1] == 'True'
settings.materialsFile = pairs[22][1]
if args.save_path:
settings.save_path = args.save_path
@ -199,10 +208,13 @@ def runAsHeadless():
enableRarity = settings.enableRarity
enableLogic = settings.enableLogic
enableMaterials = settings.enableMaterials
materialsFile = settings.materialsFile
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile,
Blend_My_NFTs_Output)
enableMaterials, materialsFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, maxNFTs, nftsPerBatch, save_path, batch_json_save_path)
elif args.operation == 'generate-nfts':
@ -255,7 +267,6 @@ def runAsHeadless():
# ======== User input Property Group ======== #
class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
# Create NFT Data Panel:
nftName: bpy.props.StringProperty(name="NFT Name")
@ -264,11 +275,11 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
nftsPerBatch: bpy.props.IntProperty(name="NFTs Per Batch", default=1, min=1) # max=(combinations - offset)
save_path: bpy.props.StringProperty(
name="Save Path",
description="Save path for NFT files",
default="",
maxlen=1024,
subtype="DIR_PATH"
name="Save Path",
description="Save path for NFT files",
default="",
maxlen=1024,
subtype="DIR_PATH"
)
enableRarity: bpy.props.BoolProperty(name="Enable Rarity")
@ -276,18 +287,27 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
enableLogic: bpy.props.BoolProperty(name="Enable Logic")
enable_Logic_Json: bpy.props.BoolProperty(name="Use Logic.json instead")
logicFile: bpy.props.StringProperty(
name="Logic File Path",
description="Path where Logic.json is located.",
default="",
maxlen=1024,
subtype="FILE_PATH"
name="Logic File Path",
description="Path where Logic.json is located.",
default="",
maxlen=1024,
subtype="FILE_PATH"
)
enableMaterials: bpy.props.BoolProperty(name="Enable Materials")
materialsFile: bpy.props.StringProperty(
name="Materials File",
description="Path where Materials.json is located.",
default="",
maxlen=1024,
subtype="FILE_PATH"
)
# Generate NFTs Panel:
imageBool: bpy.props.BoolProperty(name="Image")
imageEnum: bpy.props.EnumProperty(
name="Image File Format",
description="Select Image file format",
name="Image File Format",
description="Select Image file format",
items=[
('PNG', ".PNG", "Export NFT as PNG"),
('JPEG', ".JPEG", "Export NFT as JPEG")
@ -296,8 +316,8 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
animationBool: bpy.props.BoolProperty(name="Animation")
animationEnum: bpy.props.EnumProperty(
name="Animation File Format",
description="Select Animation file format",
name="Animation File Format",
description="Select Animation file format",
items=[
('AVI_JPEG', '.avi (AVI_JPEG)', 'Export NFT as AVI_JPEG'),
('AVI_RAW', '.avi (AVI_RAW)', 'Export NFT as AVI_RAW'),
@ -308,21 +328,24 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
modelBool: bpy.props.BoolProperty(name="3D Model")
modelEnum: bpy.props.EnumProperty(
name="3D Model File Format",
description="Select 3D Model file format",
name="3D Model File Format",
description="Select 3D Model file format",
items=[
('GLB', '.glb', 'Export NFT as .glb'),
('GLTF_SEPARATE', '.gltf + .bin + textures', 'Export NFT as .gltf with separated textures in .bin + textures.'),
('GLTF_SEPARATE', '.gltf + .bin + textures',
'Export NFT as .gltf with separated textures in .bin + textures.'),
('GLTF_EMBEDDED', '.gltf', 'Export NFT as embedded .gltf file that contains textures.'),
('FBX', '.fbx', 'Export NFT as .fbx'),
('OBJ', '.obj', 'Export NFT as .obj'),
('X3D', '.x3d', 'Export NFT as .x3d'),
('STL', '.stl', 'Export NFT as .stl'),
('VOX', '.vox (Experimental)', 'Export NFT as .vox, requires the voxwriter add on: https://github.com/Spyduck/voxwriter')
('VOX', '.vox (Experimental)',
'Export NFT as .vox, requires the voxwriter add on: https://github.com/Spyduck/voxwriter')
]
)
batchToGenerate: bpy.props.IntProperty(name="Batch To Generate", default=1, min=1) # max=(collectionSize / nftsPerBatch)
batchToGenerate: bpy.props.IntProperty(name="Batch To Generate", default=1,
min=1)
# Refactor Batches & Create Metadata Panel:
cardanoMetaDataBool: bpy.props.BoolProperty(name="Cardano Cip")
@ -336,11 +359,11 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
enableCustomFields: bpy.props.BoolProperty(name="Enable Custom Metadata Fields")
customfieldsFile: bpy.props.StringProperty(
name="Custom Fields File",
description="Path where Custom_Fields.json is located.",
default="",
maxlen=1024,
subtype="FILE_PATH"
name="Custom Fields File",
description="Path where Custom_Fields.json is located.",
default="",
maxlen=1024,
subtype="FILE_PATH"
)
# Other Panel:
@ -361,19 +384,19 @@ class createData(bpy.types.Operator):
name="Reverse Order")
def execute(self, context):
nftName = bpy.context.scene.input_tool.nftName
collectionSize = bpy.context.scene.input_tool.collectionSize
nftsPerBatch = bpy.context.scene.input_tool.nftsPerBatch
save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path)
logicFile = bpy.path.abspath(bpy.context.scene.input_tool.logicFile) # Logic_Dict will replace this, remove the open(logicFile)
enableRarity = bpy.context.scene.input_tool.enableRarity
enableLogic = bpy.context.scene.input_tool.enableLogic
enable_Logic_Json = bpy.context.scene.input_tool.enable_Logic_Json
logicFile = bpy.path.abspath(bpy.context.scene.input_tool.logicFile)
Logic_Dict = {}
enableMaterials = bpy.context.scene.input_tool.enableMaterials
materialsFile = bpy.path.abspath(bpy.context.scene.input_tool.materialsFile)
# Handling Custom Fields UIList input:
if enableLogic:
@ -381,9 +404,10 @@ class createData(bpy.types.Operator):
logicFile = json.load(open(logicFile))
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic,
logicFile, Blend_My_NFTs_Output)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile,
enableMaterials, materialsFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, collectionSize, nftsPerBatch, save_path, batch_json_save_path)
if enable_Logic_Json and not logicFile:
self.report({'ERROR'}, f"No Logic.json file path set. Please set the file path to your Logic.json file.")
@ -405,9 +429,8 @@ class createData(bpy.types.Operator):
}
num += 1
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity,
enableLogic,
logicFile, Blend_My_NFTs_Output)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile,
enableMaterials, materialsFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, collectionSize, nftsPerBatch, save_path, batch_json_save_path)
else:
logicFile = {}
@ -423,19 +446,19 @@ class createData(bpy.types.Operator):
}
num += 1
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity,
enableLogic,
logicFile, Blend_My_NFTs_Output)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile,
enableMaterials, materialsFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, collectionSize, nftsPerBatch, save_path, batch_json_save_path)
if not enableLogic:
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic,
logicFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, collectionSize, nftsPerBatch, save_path, batch_json_save_path)
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile,
enableMaterials, materialsFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, collectionSize, nftsPerBatch, save_path, batch_json_save_path)
self.report({'INFO'}, f"NFT Data created!")
return {"FINISHED"}
class exportNFTs(bpy.types.Operator):
bl_idname = 'exporter.nfts'
bl_label = 'Export NFTs'
@ -459,21 +482,27 @@ class exportNFTs(bpy.types.Operator):
enableModelsBlender = bpy.context.scene.input_tool.modelBool
modelFileFormat = bpy.context.scene.input_tool.modelEnum
enableMaterials = bpy.context.scene.input_tool.enableMaterials
materialsFile = bpy.path.abspath(bpy.context.scene.input_tool.materialsFile)
# 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, collectionSize, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
Exporter.render_and_save_NFTs(nftName, collectionSize, batchToGenerate, batch_json_save_path,
nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index,
enableMaterials, materialsFile
)
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'
@ -500,7 +529,8 @@ class resume_failed_batch(bpy.types.Operator):
enableModelsBlender = batch["Generation Save"][-1]["Render_Settings"]["enableModelsBlender"]
modelFileFormat = batch["Generation Save"][-1]["Render_Settings"]["modelFileFormat"]
Exporter.render_and_save_NFTs(nftName, collectionSize, failed_batch, batch_json_save_path, nftBatch_save_path, enableImages,
Exporter.render_and_save_NFTs(nftName, collectionSize, failed_batch, batch_json_save_path, nftBatch_save_path,
enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
)
@ -509,6 +539,7 @@ class resume_failed_batch(bpy.types.Operator):
return {"FINISHED"}
class refactor_Batches(bpy.types.Operator):
"""Refactor your collection? This action cannot be undone."""
bl_idname = 'refactor.batches'
@ -563,6 +594,7 @@ class refactor_Batches(bpy.types.Operator):
def invoke(self, context, event):
return context.window_manager.invoke_confirm(self, event)
class export_settings(bpy.types.Operator):
"""Export your settings into a configuration file."""
bl_idname = 'export.settings'
@ -621,6 +653,10 @@ class export_settings(bpy.types.Operator):
"#Enable Custom Fields\n"
f"enableCustomFields={str(settings.enableCustomFields)}\n"
f"customfieldsFile={settings.customfieldsFile}\n"
"\n"
"#Enable Materials\n"
f"enableMaterials={str(settings.enableMaterials)}\n"
f"materialsFile={settings.materialsFile}\n"
)
print(output, file=config)
@ -696,9 +732,17 @@ class BMNFTS_PT_CreateData(bpy.types.Panel):
row = layout.row()
row.prop(input_tool_scene, "logicFile")
row = layout.row()
row.prop(input_tool_scene, "enableMaterials")
if bpy.context.scene.input_tool.enableMaterials:
row = layout.row()
row.prop(input_tool_scene, "materialsFile")
row = layout.row()
self.layout.operator("create.data", icon='DISCLOSURE_TRI_RIGHT', text="Create Data")
class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
bl_label = "Generate NFTs"
bl_idname = "BMNFTS_PT_GenerateNFTs"
@ -751,6 +795,7 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
row = layout.row()
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")
class BMNFTS_PT_Refactor(bpy.types.Panel):
bl_label = "Refactor Batches & Create Metadata"
bl_idname = "BMNFTS_PT_Refactor"
@ -825,6 +870,7 @@ class BMNFTS_PT_Refactor(bpy.types.Panel):
row = layout.row()
self.layout.operator("refactor.batches", icon='FOLDER_REDIRECT', text="Refactor Batches & Create Metadata")
class BMNFTS_PT_Other(bpy.types.Panel):
bl_label = "Other"
bl_idname = "BMNFTS_PT_Other"
@ -853,6 +899,11 @@ class BMNFTS_PT_Other(bpy.types.Panel):
row = layout.row()
layout.label(text=f"**Set a Save Path in Create NFT Data to Export Settings")
row = layout.row()
row = layout.row()
layout.label(text=f"Looking for help?")
row = layout.row()
row.operator("wm.url_open", text="Blend_My_NFTs Documentation",
icon='URL').url = "https://github.com/torrinworx/Blend_My_NFTs"
@ -860,7 +911,6 @@ class BMNFTS_PT_Other(bpy.types.Panel):
row = layout.row()
row.operator("wm.url_open", text="YouTube Tutorials",
icon='URL').url = "https://www.youtube.com/watch?v=ygKJYz4BjRs&list=PLuVvzaanutXcYtWmPVKu2bx83EYNxLRsX"
row = layout.row()
row.operator("wm.url_open", text="Join Our Discord Community!",
icon='URL').url = "https://discord.gg/UpZt5Un57t"
@ -885,6 +935,7 @@ classes = (
BMNFTS_PT_Other,
) + Custom_Metadata_UIList.classes_Custom_Metadata_UIList + Logic_UIList.classes_Logic_UIList
def register():
for cls in classes:
bpy.utils.register_class(cls)
@ -897,7 +948,6 @@ def register():
bpy.types.Scene.logic_fields = CollectionProperty(type=Logic_UIList.CUSTOM_logic_objectCollection)
bpy.types.Scene.logic_fields_index = IntProperty()
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)

Wyświetl plik

@ -10,7 +10,7 @@ import json
import random
from functools import partial
from .loading_animation import Loader
from . import Rarity, Logic, Checks
from . import Rarity, Logic, Checks, Material_Generator
from .Constants import bcolors, removeList, remove_file_by_extension
@ -126,7 +126,7 @@ def get_hierarchy():
return hierarchy
def generateNFT_DNA(collectionSize, logicFile, enableRarity, enableLogic):
def generateNFT_DNA(collectionSize, enableRarity, enableLogic, logicFile, enableMaterials, materialsFile):
"""
Returns batchDataDictionary containing the number of NFT combinations, hierarchy, and the DNAList.
"""
@ -172,8 +172,14 @@ def generateNFT_DNA(collectionSize, logicFile, enableRarity, enableLogic):
if enableLogic:
singleDNA = Logic.logicafyDNAsingle(hierarchy, singleDNA, logicFile)
# print(f"Logic DNA: {singleDNA}")
# print("============\n")
print(f"Original DNA: {singleDNA}")
print("============\n")
if enableMaterials:
singleDNA = Material_Generator.apply_materials(hierarchy, singleDNA, materialsFile)
print(f"Materials DNA: {singleDNA}")
print("============\n")
return singleDNA
def create_DNAList():
@ -202,7 +208,8 @@ def generateNFT_DNA(collectionSize, logicFile, enableRarity, enableLogic):
return DataDictionary
def send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile, Blend_My_NFTs_Output):
def send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile, enableMaterials,
materialsFile, Blend_My_NFTs_Output):
"""
Creates NFTRecord.json file and sends "batchDataDictionary" to it. NFTRecord.json is a permanent record of all DNA
you've generated with all attribute variants. If you add new variants or attributes to your .blend file, other scripts
@ -232,7 +239,8 @@ def send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, e
def create_nft_data():
try:
DataDictionary = generateNFT_DNA(collectionSize, logicFile, enableRarity, enableLogic)
DataDictionary = generateNFT_DNA(collectionSize, enableRarity, enableLogic, logicFile, enableMaterials,
materialsFile)
NFTRecord_save_path = os.path.join(Blend_My_NFTs_Output, "NFTRecord.json")
# Checks:

Wyświetl plik

@ -18,7 +18,9 @@ def save_batch(batch, file_name):
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,
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))
@ -51,14 +53,14 @@ def save_generation_state(batchToGenerate, batch_json_save_path, nftBatch_save_p
save_batch(batch, file_name)
def save_completed(single_dna, a, x, batch_json_save_path, batchToGenerate):
def save_completed(full_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["BatchDNAList"][index][full_single_dna]["Complete"] = True
batch["Generation Save"][-1]["DNA Generated"] = x
save_batch(batch, file_name)
@ -79,17 +81,19 @@ def getBatchData(batchToGenerate, batch_json_save_path):
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, fail_state, failed_batch, failed_dna, failed_dna_index
):
def render_and_save_NFTs(nftName, collectionSize, batchToGenerate, batch_json_save_path,
nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index,
enableMaterials, materialsFile):
"""
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)
materialsFile = json.load(open(materialsFile))
time_start_1 = time.time()
if fail_state:
@ -104,7 +108,9 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
x = 1
for a in BatchDNAList:
single_dna = list(a.keys())[0]
full_single_dna = list(a.keys())[0]
single_dna, material_dna = full_single_dna.split(':')
for i in hierarchy:
for j in hierarchy[i]:
bpy.data.collections[j].hide_render = True
@ -129,19 +135,67 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
dnaDictionary.update({x: k})
return dnaDictionary
def match_materialDNA_to_Material(single_dna, material_dna):
"""
Matches the Material DNA to it's selected Materials unless a 0 is present meaning no material for that variant was selected.
"""
listAttributes = list(hierarchy.keys())
listDnaDecunstructed = single_dna.split('-')
listMaterialDNADeconstructed = material_dna.split('-')
full_dna_dict = {}
for attribute, variant, material in zip(listAttributes, listDnaDecunstructed, listMaterialDNADeconstructed):
for var in hierarchy[attribute]:
if hierarchy[attribute][var]['number'] == variant:
variant = var
if material != '0':
for variant_m in materialsFile:
if variant == variant_m:
for mat in materialsFile[variant_m]["Material List"]:
if mat.split('_')[1] == material:
material = mat
full_dna_dict[variant] = material
return full_dna_dict
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:{single_dna}")
if enableMaterials:
materialdnaDictionary = match_materialDNA_to_Material(single_dna, material_dna)
for var_mat in list(materialdnaDictionary.keys()):
if materialdnaDictionary[var_mat] != '0':
if not materialsFile[var_mat]['Variant Objects']:
"""
If objects to apply material to not specified, apply to all objects in Variant collection.
"""
for obj in bpy.data.collections[var_mat].all_objects:
selected_object = bpy.data.objects.get(obj.name)
selected_object.active_material = bpy.data.materials[materialdnaDictionary[var_mat]]
if materialsFile[var_mat]['Variant Objects']:
"""
If objects to apply material to are specified, apply material only to objects specified withing the Variant collection.
"""
for obj in materialsFile[var_mat]['Variant Objects']:
selected_object = bpy.data.objects.get(obj)
selected_object.active_material = bpy.data.materials[materialdnaDictionary[var_mat]]
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))
@ -292,7 +346,7 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
print(f"Completed {name} render in {time.time() - time_start_2}s")
save_completed(single_dna, a, x, batch_json_save_path, batchToGenerate)
save_completed(full_single_dna, a, x, batch_json_save_path, batchToGenerate)
x += 1

Wyświetl plik

@ -0,0 +1,100 @@
# Purpose:
# The purpose of this file is to apply the materials a user sets in a given .json file to the Variant collection objects
# also specified in the .json file. The Materialized DNA is then returned in the following format: 1-1-1:1-1-1
# Where the numbers right of the ":" are the material numbers applied to the respective Variants to the left of the ":"
import bpy
import json
import random
def select_material(materialList):
"""Selects a material from a passed material list. """
number_List_Of_i = []
rarity_List_Of_i = []
ifZeroBool = None
for material in materialList:
material_order_num = material.split("_")[1]
number_List_Of_i.append(material_order_num)
material_rarity_percent = material.split("_")[1]
rarity_List_Of_i.append(float(material_rarity_percent))
for x in rarity_List_Of_i:
if x == 0:
ifZeroBool = True
break
elif x != 0:
ifZeroBool = False
if ifZeroBool:
selected_material = random.choices(number_List_Of_i, k=1)
elif not ifZeroBool:
selected_material = random.choices(number_List_Of_i, weights=rarity_List_Of_i, k=1)
return selected_material[0]
def get_variant_att_index(variant, hierarchy):
variant_attribute = None
for attribute in hierarchy:
for variant_h in hierarchy[attribute]:
if variant_h == variant:
variant_attribute = attribute
attribute_index = list(hierarchy.keys()).index(variant_attribute)
variant_order_num = variant.split("_")[1]
return attribute_index, variant_order_num
def match_DNA_to_Variant(hierarchy, singleDNA):
"""
Matches each DNA number separated by "-" to its attribute, then its variant.
"""
listAttributes = list(hierarchy.keys())
listDnaDecunstructed = singleDNA.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
def apply_materials(hierarchy, singleDNA, materialsFile):
"""
DNA with applied material example: "1-1:1-1" <Normal DNA>:<Selected Material for each Variant>
The Material DNA will select the material for the Variant order number in the NFT DNA based on the Variant Material
list in the Variant_Material.json file.
"""
singleDNADict = match_DNA_to_Variant(hierarchy, singleDNA)
materialsFile = json.load(open(materialsFile))
deconstructed_MaterialDNA = {}
for a in singleDNADict:
complete = False
for b in materialsFile:
if singleDNADict[a] == b:
mat = select_material(materialsFile[b]['Material List'])
deconstructed_MaterialDNA[a] = mat
complete = True
if not complete:
deconstructed_MaterialDNA[a] = "0"
material_DNA = ""
for a in deconstructed_MaterialDNA:
num = "-" + str(deconstructed_MaterialDNA[a])
material_DNA += num
material_DNA = ''.join(material_DNA.split('-', 1))
return f"{singleDNA}:{material_DNA}"