Skip to content

Commit

Permalink
Changes to Materials and Logic
Browse files Browse the repository at this point in the history
- Added AutoSave before generation functionality to Other panel
- Removed strip_empty_exclude function
- Modified Exporter to work with new Material Randomizer layout
- Added Enable Materials option in logicafyDNAsingle function in preparation for Material Randomizer Logic
- Materials are no longer formatted like Variants, the Material List is now a dictionary where the keys are the names of the Materials and the values are the Rarity percentages. Each Variant in the Materials.json file can have a different list with different rarity values that are selected for only that variant.

Material file format:
```
{
    "Variant Name": {
        "Material List": {
            "Material Name 1": 90,
            "Material Name 2": 5,
            "Material Name 3": 1,
            "Material Name 4": 4
        },
        "Variant Objects": []
    }
}
```
  • Loading branch information
torrinworx committed Jun 6, 2022
1 parent 17cbf3a commit 3cb2a69
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 67 deletions.
14 changes: 14 additions & 0 deletions __init__.py
Expand Up @@ -376,6 +376,8 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
)

# Other Panel:
enableAutoSave: bpy.props.BoolProperty(name="Auto Save Before Generation")


# API Panel properties:
apiKey: bpy.props.StringProperty(name="API Key", subtype='PASSWORD')
Expand Down Expand Up @@ -478,6 +480,11 @@ class exportNFTs(bpy.types.Operator):
name="Reverse Order")

def execute(self, context):

enableAutoSave = bpy.context.scene.input_tool.enableAutoSave
if enableAutoSave:
bpy.ops.wm.save_mainfile()

class input:
nftName = bpy.context.scene.input_tool.nftName
save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path)
Expand Down Expand Up @@ -923,10 +930,17 @@ def draw(self, context):
input_tool_scene = scene.input_tool

"""
Other:
A place to store miscellaneous settings, features, and external links that the user may find useful but doesn't
want to get in the way of their work flow.
Export Settings:
This panel gives the user the option to export all settings from the Blend_My_NFTs addon into a config file. Settings
will be read from the config file when running heedlessly.
"""

row = layout.row()
row.prop(input_tool_scene, "enableAutoSave")

layout.label(text=f"Running Blend_My_NFTs Headless:")

save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path)
Expand Down
46 changes: 9 additions & 37 deletions main/DNA_Generator.py
Expand Up @@ -123,47 +123,18 @@ def attributeData(attributeVariants):

return hierarchy

def strip_empty_exclude(hierarchy):
"""
Strips Empty Exclude variants from the hierarchy.
"""
excluded_var_dict = {}

for a in hierarchy:
empty_variant = ""
empty_var_count = 0
variant_list = list(hierarchy[a].keys())
# empty_var_count and raise() prevents this for from causing breaking stuff:

for b in variant_list:
if b.split("_")[1] == "0":
empty_variant = b
empty_var_count += 1
if empty_var_count > 1:
raise Exception(
f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n"
f"The Attribute collection '{a}' has more than one Empty variant.\n"
f"Attributes can only have a maximum of 1 Empty variant, please review the documentation here:\n{bcolors.RESET}"
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
)

if len(empty_variant.split("_")) == 4 and empty_variant.split("_")[3] == "Exclude":
excluded_var_dict[a] = empty_variant
del hierarchy[a][empty_variant]

return hierarchy, excluded_var_dict

def generateNFT_DNA(collectionSize, enableRarity, enableLogic, logicFile, enableMaterials, materialsFile):
"""
Returns batchDataDictionary containing the number of NFT combinations, hierarchy, and the DNAList.
"""

hierarchy, excluded_var_dict = strip_empty_exclude(get_hierarchy())
hierarchy = get_hierarchy()

# DNA random, Rarity and Logic methods:
DataDictionary = {}

def createDNArandom():
def createDNArandom(hierarchy):
"""Creates a single DNA randomly without Rarity or Logic."""
dnaStr = ""
dnaStrList = []
Expand Down Expand Up @@ -195,20 +166,22 @@ def singleCompleteDNA():
singleDNA = ""
# Comments for debugging random, rarity, logic, and materials.
if not enableRarity:
singleDNA = createDNArandom()
singleDNA = createDNArandom(hierarchy)
# print("============")
# print(f"Original DNA: {singleDNA}")
if enableRarity:
singleDNA = Rarity.createDNArarity(hierarchy)
# print(f"Rarity DNA: {singleDNA}")

if enableMaterials:
singleDNA = Material_Generator.apply_materials(hierarchy, singleDNA, materialsFile, enableRarity)
# print(f"Materials DNA: {singleDNA}")

if enableLogic:
singleDNA = Logic.logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_var_dict)
singleDNA = Logic.logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, enableMaterials)
# print(f"Logic DNA: {singleDNA}")

if enableMaterials:
singleDNA = Material_Generator.apply_materials(hierarchy, singleDNA, materialsFile)
# print(f"Materials DNA: {singleDNA}")

# print("============\n")

return singleDNA
Expand Down Expand Up @@ -246,7 +219,6 @@ def create_DNAList():

# Data stored in batchDataDictionary:
DataDictionary["numNFTsGenerated"] = len(DNAList)
DataDictionary["excludedVariants"] = excluded_var_dict
DataDictionary["hierarchy"] = hierarchy
DataDictionary["DNAList"] = DNAList

Expand Down
10 changes: 6 additions & 4 deletions main/Exporter.py
Expand Up @@ -177,12 +177,14 @@ def match_materialDNA_to_Material(single_dna, material_dna, materialsFile):
if hierarchy[attribute][var]['number'] == variant:
variant = var

if material != '0':
if material != '0': # If material is not empty
for variant_m in materialsFile:
if variant == variant_m:
for mat in materialsFile[variant_m]["Material List"]:
if mat.split('_')[1] == material:
material = mat
# Getting Materials name from Materials index in the Materials List
materials_list = list(materialsFile[variant_m]["Material List"].keys())

material = materials_list[int(material) - 1] # Subtract 1 because '0' means empty mat
break

full_dna_dict[variant] = material

Expand Down
7 changes: 3 additions & 4 deletions main/Logic.py
Expand Up @@ -15,7 +15,7 @@ def reconstructDNA(deconstructedDNA):
return ''.join(reconstructed_DNA.split('-', 1))


def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity, excluded_var_dict):
def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity):

# Check if Variants in if_dict are in deconstructed_DNA, if so return if_list_selected = True:
if_list_selected = False
Expand Down Expand Up @@ -221,7 +221,7 @@ def get_var_info(variant):
return dict(items_returned)


def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_var_dict):
def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, enableMaterials):

deconstructed_DNA = singleDNA.split("-")
didReconstruct = True
Expand All @@ -236,7 +236,6 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_va
# Items from 'THEN' key for a given rule
then_dict = create_dicts(hierarchy, logicFile[rule]["THEN"])

# save_result(then_dict)
violates_rule, if_bool, then_bool, full_att_bool = get_rule_break_type(hierarchy, deconstructed_DNA,
if_dict, then_dict)
if deconstructed_DNA[3] != "1":
Expand All @@ -249,7 +248,7 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_va
print(f"======={deconstructed_DNA} VIOLATES RULE======")

deconstructed_DNA = apply_rules_to_dna(
hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity, excluded_var_dict
hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity
)

newDNA = reconstructDNA(deconstructed_DNA)
Expand Down
53 changes: 31 additions & 22 deletions main/Material_Generator.py
Expand Up @@ -9,34 +9,42 @@
import random


def select_material(materialList):
def select_material(materialList, enableRarity):
"""Selects a material from a passed material list. """

number_List_Of_i = []
material_List_Of_i = [] # List of Material names instead of order numbers
rarity_List_Of_i = []
ifZeroBool = None

for material in materialList:
# Material Order Number comes from index in the Material List in materials.json for a given Variant.
# material_order_num = list(materialList.keys()).index(material)

material_order_num = material.split("_")[1]
number_List_Of_i.append(material_order_num)
material_List_Of_i.append(material)

material_rarity_percent = material.split("_")[1]
material_rarity_percent = materialList[material]
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
print(f"MATERIAL_LIST_OF_I:{material_List_Of_i}")
print(f"RARITY_LIST_OF_I:{rarity_List_Of_i}")

if enableRarity:
ifZeroBool = None

for x in rarity_List_Of_i:
if x == 0:
ifZeroBool = True
break
elif x != 0:
ifZeroBool = False

if ifZeroBool:
selected_material = random.choices(material_List_Of_i, k=1)
elif not ifZeroBool:

selected_material = random.choices(material_List_Of_i, weights=rarity_List_Of_i, k=1)

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)
else:
selected_material = random.choices(material_List_Of_i, k=1)

return selected_material[0]
return selected_material[0], materialList

def get_variant_att_index(variant, hierarchy):
variant_attribute = None
Expand Down Expand Up @@ -69,7 +77,7 @@ def match_DNA_to_Variant(hierarchy, singleDNA):
dnaDictionary.update({x: k})
return dnaDictionary

def apply_materials(hierarchy, singleDNA, materialsFile):
def apply_materials(hierarchy, singleDNA, materialsFile, enableRarity):
"""
DNA with applied material example: "1-1:1-1" <Normal DNA>:<Selected Material for each Variant>
Expand All @@ -85,8 +93,9 @@ def apply_materials(hierarchy, singleDNA, materialsFile):
complete = False
for b in materialsFile:
if singleDNADict[a] == b:
mat = select_material(materialsFile[b]['Material List'])
deconstructed_MaterialDNA[a] = mat
material_name, materialList, = select_material(materialsFile[b]['Material List'], enableRarity)
material_order_num = list(materialList.keys()).index(material_name) # Gets the Order Number of the Material
deconstructed_MaterialDNA[a] = str(material_order_num + 1)
complete = True
if not complete:
deconstructed_MaterialDNA[a] = "0"
Expand Down

3 comments on commit 3cb2a69

@nonym2
Copy link

@nonym2 nonym2 commented on 3cb2a69 Apr 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I'm trying from 4 days to make is work the script is not loading or taking material from the material lists, Please let me know how I can it done because I'm stuck in between the project.
Literally watching your video 12th time.

@solidyx
Copy link

@solidyx solidyx commented on 3cb2a69 Apr 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same situation here, trying all day and still can’t make it work

@nonym2
Copy link

@nonym2 nonym2 commented on 3cb2a69 Apr 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got to know it will work on Blender 3.1.2

and try this form of material conditioning

`{
"Torus Small_1_0": {
"Material List": {
"Red_2":50
},
"Variant Objects": []
},

"CubeSmall_2_40": {
    "Material List": {
        "Blue_1":3
    
    },
    "Variant Objects": []
}

}

`

Use 0 as the reality for random condition

Please sign in to comment.