├── README.md ├── 1 Stable Diffusion Characters ├── character_blank.png ├── character_mask.png └── code.py └── 2 ChatGPT Form Prompting └── prompt.py /README.md: -------------------------------------------------------------------------------- 1 | # Generation Land Tutorial Materials 2 | 3 | Supplemental Material to the Tutorials I make surrounding Generation Land v2 will be uploaded here 4 | -------------------------------------------------------------------------------- /1 Stable Diffusion Characters/character_blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobias17/GenerationLandTutorials/HEAD/1 Stable Diffusion Characters/character_blank.png -------------------------------------------------------------------------------- /1 Stable Diffusion Characters/character_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobias17/GenerationLandTutorials/HEAD/1 Stable Diffusion Characters/character_mask.png -------------------------------------------------------------------------------- /1 Stable Diffusion Characters/code.py: -------------------------------------------------------------------------------- 1 | # combination script 2 | import os 3 | import cv2 4 | import numpy as np 5 | 6 | indir = 'combinations/character' 7 | files = os.listdir(indir) 8 | imgs = [cv2.imread(f'{indir}/{filename}', cv2.IMREAD_UNCHANGED) for filename in files] 9 | 10 | global_img = np.zeros(imgs[0].shape) 11 | for img in imgs: 12 | global_img += img[:,:]/float(len(imgs)) 13 | 14 | bg_img = np.zeros(imgs[0].shape) 15 | bg_img[:,:] = (127, 127, 127, 0) 16 | for c in range(3): 17 | bg_img[:,:,c] *= (255-global_img[:,:,3])/float(255) 18 | bg_img[:,:,3] = 255-global_img[:,:,3] 19 | 20 | global_img = bg_img + global_img 21 | 22 | cv2.imwrite(f'{indir}/output.png', global_img) 23 | 24 | 25 | # prompts used 26 | prompts = [ 27 | "male wizard, tall and thin with a prominent nose and long white beard, draped in flowing blue robes adorned with intricate silver symbols.", 28 | "female paladin, short and muscular with short cropped blonde hair, wearing shiny plate armor and carrying a glowing holy sword.", 29 | "male barbarian, towering and broad-shouldered with a wild mane of red hair, wearing furs and carrying a massive battle-axe.", 30 | "female ranger, tall and slender with long, flowing brunette hair and piercing green eyes, dressed in leather armor and carrying a sleek longbow.", 31 | "male monk, short and wiry with a shaved head and sharp features, wearing loose, flowing robes and carrying a pair of nunchucks.", 32 | "female druid, petite and agile with piercing blue eyes and wild, curly hair, wearing a cloak made of leaves and carrying a staff carved with intricate symbols.", 33 | "male warlock, tall and gaunt with pale skin and dark, piercing eyes, dressed in black robes and carrying a staff with a glowing crystal at the top.", 34 | "female cleric, short and plump with rosy cheeks and long, curly red hair, wearing a flowing white robe and carrying a holy symbol.", 35 | "male fighter, broad-shouldered and muscular with short, cropped hair and a rugged face, dressed in heavy plate armor and carrying a sword and shield.", 36 | "male warlock, tall and thin with dark, gaunt features and long, black hair, dressed in black robes adorned with glowing runes and carrying a staff topped with a glowing crystal.", 37 | "female necromancer, short and slight with pale skin and jet black hair styled in intricate braids, wearing dark, flowing robes and carrying a staff topped with a glowing purple crystal.", 38 | "male sorcerer, tall and lean with piercing green eyes and short, spiky hair, dressed in colorful robes adorned with intricate symbols and carrying a wand topped with a glowing gemstone.", 39 | ] 40 | -------------------------------------------------------------------------------- /2 ChatGPT Form Prompting/prompt.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import re, math 3 | 4 | defaults = { 5 | "theme": "high fantasy, with a Dungeons and Dragons inspiration", 6 | } 7 | 8 | base_prompt = """You will help me fill out certain aspects of a video game I am designing. The theme is %%THEME%%. I need your help filling out %%INITIAL_DESC%%. 9 | 10 | If you see the phrase `describe()` then you are to fill in a list of physical attributes that describe the object. 11 | 12 | If you see `choices=[x, y, z]` then you are to choose one item from that list (x, y, or z in that example). Do not choose more than 1 option. Do not choose something that is not in the list. 13 | 14 | If you see something like: 15 | ``` 16 | Footwear: choices=[sneakers, sandals] 17 | if (choice == sneakers) { 18 | Brand: choices=[Nike, Adidas] 19 | else { 20 | Brand: choices=[Crocs, Teva] 21 | } 22 | ``` 23 | Then you must fill out the items in the if/else block based on the choice you made in the previous item in the form. 24 | 25 | I will now provide examples for the following design sheet for a fruit 26 | ``` 27 | Name: 28 | Description: describe() 29 | Taste: choices=[sweet, sour] 30 | if (choice == sweet) { 31 | Type: choices=[sugary, honeyed] 32 | else { 33 | Kick: choices=[acidic, tart] 34 | } 35 | ``` 36 | 37 | Example 1 shows a good example of a filled out form: 38 | ``` 39 | Name: Apple 40 | Description: apple with smooth red skin, brown stem with 2 bright green leaves 41 | Taste: sweet 42 | Type: sugary 43 | ``` 44 | 45 | Example 2 shows a bad example of a filled out form: 46 | ``` 47 | Name: Lemon 48 | Description: brown 49 | Taste: Sour 50 | Kick: acidic 51 | ``` 52 | This is a bad example because the description both too short and does not describe a lemon 53 | 54 | Example 3 shows another bad example of a filled out form: 55 | ``` 56 | Name: Pear 57 | Description: pear with yellow and orange skin, elongate shape that's narrow at the top and wide at the bottom 58 | Taste: tangy 59 | Kick: tart 60 | ``` 61 | This is a bad example because the Taste attribute was Tangy, which is not from the list of options to choose from, and breaks the conditional option below it. 62 | 63 | Example 4 shows another bad example of a filled out form: 64 | ``` 65 | Name: Banana 66 | Description: yellow skin with speckles of brown creeping in, peel slightly pulled back at the top for a small portion 67 | Taste: sweet 68 | Kick: acidic 69 | ``` 70 | This is a bad example because, while `Kick: acidic` is a valid option, it should only be picked when the taste is sour, not sweet. 71 | 72 | 73 | Please fill out %%COUNT%% form(s) for a %%THEME%% %%FORM_DESC%% in my upcoming video game 74 | %%EXTRA_REQS%% 75 | ``` 76 | %%FORM%% 77 | ``` 78 | 79 | Please fill out %%COUNT%% form(s) exactly%%SPEC_REQS%%""" 80 | 81 | 82 | class DistributionManager: 83 | level_count = 10 84 | 85 | def __init__(self, options, sig): 86 | self.options = options 87 | self.sig = sig 88 | 89 | def get(self, level): 90 | mu = ((level-1) / (self.level_count-1)) * (len(self.options) - 1) 91 | coefs = [1/math.sqrt(2*math.pi*self.sig)*pow(math.e, -1/2*pow((x-mu)/math.sqrt(self.sig), 2)) for x in range(len(self.options))] 92 | dividend = sum(coefs) 93 | coefs = [coef/dividend for coef in coefs] 94 | return np.random.choice(self.options, p=coefs) 95 | 96 | character_sizes = ['small animal', 'small humanoid', 'human sized', 'large humanoid', 'large beast'] 97 | char_dist_man = DistributionManager(character_sizes, 2) 98 | character = { 99 | "initial desc": "a character sheet for an enemy that the player will fight", 100 | "form desc": "enemy that the player will have to fight", 101 | "extra reqs": """ 102 | For the melee attacks: 103 | Claw Swipes is the generic attack for animals, as they can not hold a weapon. Leave the weapon section blank. 104 | Weapon Swing is an attack that has the character swinging the sword from right to left, dealing great damage and knocking the target back slightly. 105 | Weapon Strike is a vertical attack that has the character swinging the sword from above their head to the ground, dealing some damage and stunning the target for some duration. 106 | """, 107 | "form": f"""Size: choices=[{', '.join(character_sizes)}] 108 | Name: 109 | Description: describe() 110 | Attack Style: choices=[melee, ranged] 111 | if (choice == melee) {{ 112 | Attack Type: choices=[claw swipes, weapon swing, weapon strike] 113 | Weapon: describe() 114 | }} else {{ 115 | Projectile type: choices=[arrow, fireball, magic] 116 | Projectile: describe() 117 | }}""", 118 | "spec reqs": (lambda x: 119 | " with the following sizes:\n" + "\n".join(f"{i+1}. {char_dist_man.get(level=x['level'])}" for i in range(x['count'])) 120 | ), 121 | } 122 | 123 | def fill_prompt(root, inputs): 124 | prompt = base_prompt 125 | matches = re.findall(r'%%([A-Z_]+)%%', prompt) 126 | for match in matches: 127 | tag = match.lower().replace('_', ' ') 128 | sub = "" 129 | if tag in inputs: 130 | sub = inputs[tag] 131 | elif tag in root: 132 | sub = root[tag] 133 | elif tag in defaults: 134 | sub = defaults[tag] 135 | else: 136 | raise Exception(f"Could not find '{tag}' in inputs, root, or defaults") 137 | if type(sub) == type(0): 138 | sub = str(sub) 139 | elif type(sub) == type(lambda: 0): 140 | sub = sub(inputs) 141 | prompt = prompt.replace(f'%%{match}%%', sub) 142 | return prompt 143 | 144 | 145 | prompt = fill_prompt(character, {'count': 5, 'level': 7}) 146 | print(prompt) 147 | --------------------------------------------------------------------------------