Random color_map/material_map, is it possible?

I have a little mob that I want to have random colors. Instead of making multiple models, I created a color_map and material_map with different color combinations.

It works only for the first mob. All other mobs are just copying whatever color was chosen from the first mob.
So when the first spawns with blue colors, all other are blue. Restart the game and maybe it now spawns in red, but then everyone will spawn in red…

I used this in its json:

{
	"type": "entity",
	"mixins": "stonehearth:mixins:mob",
	"components": {
		"render_info": {
			...
			"color_map": "/archipelago_biome/data/materials/color_maps/fish_color_map.json",
			"material_maps": [
				{
					"type": "one_of",
					"items": [
						"/archipelago_biome/data/materials/material_maps/fish/blue_body.json",
						...
						/archipelago_biome/data/materials/material_maps/fish/yellow_body.json"
					]
				},
				{
					"type": "one_of",
					"items": [
						"/archipelago_biome/data/materials/material_maps/fish/blue_tail.json",
						...
						"/archipelago_biome/data/materials/material_maps/fish/yellow_tail.json"
					]
				}
			]
		...

… was used to summarize the code with unnecessary info

Is this bugged or I’m using it wrong?

4 Likes

I’m so happy that you’re using this stuff. :slight_smile:

I’m not sure if we’ve ever used colormaps like this. Instead, we use them to say: hey, there’s 1 model, but we’d like 2 variations on it, the RC variation, and the Ascendancy variation.

Perhaps @albert can comment more.

Uhm, then it is probably intentional behavior.
Another way to achieve what I want would be to use random models, those are random each time.
But then, I will need a lot of models… The little fish I made had 6 body colors and 6 tail colors, so 36 combinations :sweat_smile:

2 Likes

Perhaps it depends on how they generate? :thinking:
My candy cane trees seem to have the same problem that Bruno mentions, but the lollipop ones do not (they have random color between two options):

1 Like

Well im working on a mod and i changed some of the skin colors, since the factions is going to be ork inspired:

i have in the file male_1.json :
“skin_color”: {
“weights”: {
“light_green” : 2,
“green”: 3,
“dark_green” : 2,
“brown” : 1,
“gray” : 1,
“black” : 1
}
}

and a file male_customizations:

“skin_color”: {
“type”: “material_map”,
“values”: {
“light_green”: “/moarmod/main/data/materials/material_maps/skin_light_green_material_map.json”,
“green”: “/moarmod/main/data/materials/material_maps/skin_green_material_map.json”,
“dark_green”: “/moarmod/main/data/materials/material_maps/skin_dark_green_material_map.json”,
“brown”: “/moarmod/main/data/materials/material_maps/skin_brown_material_map.json”,
“gray”: “/moarmod/main/data/materials/material_maps/skin_gray_material_map.json”,
“black”: “/moarmod/main/data/materials/material_maps/skin_black_material_map.json”
}
}

this is the same way skin colours work with the normal humans.

i think the main difference is the the line: “type”: “material_map”, instead of the “type”: “one of”

i dont know if it works different with mobs tho

Thanks for the suggestion. I had actually tried that too but it didn’t had any effect, staying with the default *.qb model colors. I guess it only works for citizens and at the embarkation screen where you customize your settlers. Anyway, this is the code I used for that:

		"stonehearth:customization_variants" : {
			"customization_options": "file(fish_customizations.json)",
			"root": {
				"body_and_tail_color": {
					"weights": {
						"body_and_tail_color": 1
					}
				}
			},
			"packages": {
				"body_and_tail_color": {
					"body": {
						"weights": {
							"blue":1,
							"cyan":1,
							"green":1,
							"magenta":1,
							"red":1,
							"yellow":1
						}
					},
					"tail": {
						"weights": {
							"blue":1,
							"cyan":1,
							"green":1,
							"magenta":1,
							"red":1,
							"yellow":1
						}
					}
				}
			}
		},

And then on the fish_customizations.json:

{
	"type": "index",
	"categories": {
		"body": ["body"],
		"tail": ["tail"]
	},
	"styles": {
		"body": {
			"type": "material_map",
			"values": {
				"blue":"/archipelago_biome/data/materials/material_maps/fish/blue_body.json",
				"cyan":"/archipelago_biome/data/materials/material_maps/fish/cyan_body.json",
				"green":"/archipelago_biome/data/materials/material_maps/fish/green_body.json",
				"magenta":"/archipelago_biome/data/materials/material_maps/fish/magenta_body.json",
				"red":"/archipelago_biome/data/materials/material_maps/fish/red_body.json",
				"yellow":"/archipelago_biome/data/materials/material_maps/fish/yellow_body.json"
			}
		},
		"tail": {
			"type": "material_map",
			"values": {
				"blue":"/archipelago_biome/data/materials/material_maps/fish/blue_tail.json",
				"cyan":"/archipelago_biome/data/materials/material_maps/fish/cyan_tail.json",
				"green":"/archipelago_biome/data/materials/material_maps/fish/green_tail.json",
				"magenta":"/archipelago_biome/data/materials/material_maps/fish/magenta_tail.json",
				"red":"/archipelago_biome/data/materials/material_maps/fish/red_tail.json",
				"yellow":"/archipelago_biome/data/materials/material_maps/fish/yellow_tail.json"
			}
		}
	}
}
Hey, Bruno,

Try mixing this into your ghost:

{
   "components":{
      "render_info":{
         "cache_model_geometry":false
     }
   }
}

Works for my mod where I am playing similar color map tricks. One caveat is that when using the debug tools item stamper you’ll run into the same issue you’re seeing now where first color variant fixes all instances of the same item, even after this fix.

I’d be interested to see if you notice any performance issues if you create a ton of items like this. I assume that turning caching on is somehow optimizing memory and taking this route may save the model information for every item of that type. I’m too busy working on my mod to have tested that deeply yet.

1 Like

also an idea, maybe you need to mixinto a fish in the roles of the animal kingdom located: stonehearth/services/server/population/data

since kingdoms can use mat_maps, it might work that way.

it also works in the human_npc_population:

{
   "type": "kingdom",
   "kingdom_name": "Human NPCs",
   "kingdom_id": "human_npcs",
   "amenity_to_strangers": "neutral",
   "roles": {
      "default": {
         "male": {
            "uri": [
               "stonehearth:male_npc_1"
            ],
            "given_names": [
               "Amiot",
               "Joren",
               "Thorald",
               "Lycus",
               "Odin",
               "Tristen",
               "Ur",
               "Lyell",
               "Vitel",
               "Josepe",
               "Rollo",
               "Osmond",
               "Hamett"
            ]
         },
         "female": {
            "uri": [
               "stonehearth:female_npc_1"
            ],
            "given_names": [
               "Acelina",
               "Elisot",
               "Lucette",
               "Joy",
               "Anna",
               "Sisilla",
               "Erta",
               "Alice",
               "Cecely",
               "Ladina",
               "Santia",
               "Elene",
               "Felicia",
               "Odela"
            ]
         },
         "surnames": [
            "Garin",
            "Corot",
            "Kramer",
            "Essig",
            "Bergen",
            "de Meo",
            "Piller",
            "Kumblin",
            "Coste",
            "Magica",
            "Raev",
            "Mediate",
            "Armbruster",
            "Arts",
            "Arbied",
            "Boon",
            "Borbely",
            "Knopf",
            "Koeman",
            "Marchand",
            "Paqet",
            "Sanna",
            "Polzin",
            "Mercier",
            "Zsoldos"
         ]
      },
      "task_groups": {}
   }
}

and in the male_npc_1:

{
   "type" : "entity",
   "mixins": "stonehearth:mixins:base_human_npc", 
   "components": {
      "render_info" : {
         "animation_table" : "stonehearth:skeletons:humanoid:male",
         "material_maps": [
              {
               "type": "one_of",
               "items": [
                  {
                     "type": "each_of",
                     "items": [
                       "/stonehearth/data/materials/material_maps/skin_white_material_map.json",
                       {
                       "type": "one_of",
                          "items": [
                             "/stonehearth/data/materials/material_maps/hair_platinum_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_blonde_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_sandy_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_red_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_black_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_black_material_map.json",
                             "/stonehearth/data/materials/material_maps/hair_black_material_map.json"
                          ]
                       }
                     ]
                  },
                  {
                     "type": "each_of",
                     "items": [
                        "/stonehearth/data/materials/material_maps/skin_brown1_material_map.json",
                        {
                           "type": "one_of",
                           "items": [
                              "/stonehearth/data/materials/material_maps/hair_sandy_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_black_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_black_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_black_material_map.json"
                           ]
                        }
                     ]
                  },
                  {
                     "type": "each_of",
                     "items": [
                        "/stonehearth/data/materials/material_maps/skin_brown2_material_map.json",
                        {
                           "type": "one_of",
                           "items": [
                              "/stonehearth/data/materials/material_maps/hair_brown_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_black_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_black_material_map.json",
                              "/stonehearth/data/materials/material_maps/hair_black_material_map.json"
                           ]
                        }
                     ]
                  }
               ]
            }
         ]
      },
      "model_variants": {
         "default": {
            "models": [
               "file(head.qb)",
               "file(body.qb)"
            ]
         }
      }
   },
   "entity_data" : {
      "stonehearth:customization_variants" : {
         "customization_options": "stonehearth:humans:male:customizations",
         "root": {
            "hair_and_skin_color": {
               "weights": {
                  "white_color": 1,
                  "brown_1_color": 1,
                  "brown_2_color": 1
               }
            },
            "age": {
               "weights": {
                  "young": 3,
                  "old": 1
               }
            }
         },
         "packages": {
            "white_color": {
               "hair_color": {
                  "weights": {
                     "black": 3,
                     "brown": 3,
                     "red": 1,
                     "sandy": 1,
                     "blonde": 1,
                     "platinum": 1
                  }
               },
               "skin_color": {
                  "weights": {
                     "white": 1
                  }
               }
            },
            "brown_1_color": {
               "hair_color": {
                  "weights": {
                     "black": 3,
                     "brown": 3,
                     "sandy": 1
                  }
               },
               "skin_color": {
                  "weights": {
                     "brown_1": 1
                  }
               }
            },
            "brown_2_color": {
               "hair_color": {
                  "weights": {
                     "black": 3,
                     "brown": 1
                  }
               },
               "skin_color": {
                  "weights": {
                     "brown_2": 1
                  }
               }
            },
            "young": {
               "eyebrows": {
                  "weights": {
                     "[none]": 1,
                     "straight_eyebrows": 1
                  }
               },
               "facial_hair": {
                  "weights": {
                     "[none]": 3,
                     "chops": 2,
                     "chin_beard": 1,
                     "beard": 1
                  }
               },
               "head_hair": {
                  "weights": {
                     "male_hair_1": 1,
                     "male_hair_2": 1,
                     "male_hair_3": 1,
                     "male_hair_4": 1
                  }
               }
            },
            "old": {
               "eyebrows": {
                  "weights": {
                     "[none]": 1,
                     "straight_eyebrows": 1
                  }
               },
               "facial_hair": {
                  "weights": {
                     "chops": 2,
                     "chin_beard": 1,
                     "beard": 1
                  }
               },
               "head_hair": {
                  "weights": {
                     "male_hair_old_1": 1,
                     "male_hair_old_2": 1
                  }
               }
            }
         }
      }
   }
}

@Stivomali, thanks that actually worked. That problem you mentioned with the debug tool didn’t happen to me though. Both debug and the in-game normal spawn were spawning random colors.

I searched for instances of that cache_model_geometry and only found it in the json of humans (and npc humans), so I guess it is something done in C++ instead of Lua.
So I have no idea about its performance implications. I guess I’m safe though, as the player will probably have way less fish then citizens, and they are way simpler than the hearthlings anyway…

@Oldra Thanks! That will probably work too, though I would need to adapt a few other things too and I’m too lazy :wink:

Is it funny (or sad?) to go through all this just to realize you didn’t really like the effect? :sweat_smile:

7 Likes

I may be mis-remembering the problem with the stamper. I thought there was an issue with the stamper making items without going through the ghost like they do when they’re crafted then placed. If your fish are meant to spawn on the map, and you don’t have a separate ghost file, perhaps that would explain it.

Hearthling hair is exactly where I saw this cache thing, too. At the time I was looking to reuse models with color maps, hair was the only thing that I saw that was re-skinning models. I just flipped that switch because it was done in hair, and saw that it works. My concern about the memory is purely from the name of that property. I could see that if you do cache details about a model, it could be saved as a single object at the C++ level, and every one of your fish would point to that the same chunk of memory. My hunch is that if you actually re-color the model and use “one of” say 7 varieties with caching turned on, you could have 50 fish on your map each just pointing to 1 of 7 models. However, using the “one of” on the color map may be saving the model info for every individual fish (50 “model geometry” objects instead of 7).

I would appreciate it if any of the devs could comment as to whether my guess is correct. My mod is just using maps to allow for variety of 5-6 “flavors” of items. If it really is a memory hog to do this, I’d probably re-factor my mod to do the color swaps in Qbicle (5X size of .qb files in my .smod rather than many times memory being used in-game).

I like those fish, @BrunoSupremo! :slight_smile: And that they will vary on coloring. Nice!

Is the thing you didn’t like the fact that you ended up with a purple fish with green fins?

You could always set up complimentary sets. For example, green fish have fins selected from several shades ranging from gold through blue, but purple fish have fins from blue to red.

Glad to hear you got the “behind the scenes” working!

As for the current prototype, I think your major issue is that the fins and body are each one big block of colour. It doesn’t show off the full potential of the technology you’re using; I reckon you’d be much happier with the more advanced uses.

For example, you could split the body into multiple sections, allowing for stripes or some similar pattern. Those stripes could, presumably, be rigged to use the same colour selection as the fins, so you at least get some consistency even though the colours are random.Or rather than stripes, it could simply be another area of the body (such as the belly or cheeks) which changes colour, so the fin colour is used elsewhere on the fish and looks less “tacked on.”

I presume it’s also possible to go the opposite way, adding a riot of different colours – striped body, fins with different stripe colours, polka-dots… it comes down to how the body is modelled, doesn’t it? If so, the potential is nearly limitless; it’s just a matter of how much work seems reasonable.

And one other thought, which I’m not so sure on (I believe it’s possible but no idea how you’d go about it) would be to have a “modifier” applied to the selected colour based on the bodypart it uses – so the fish only picks up one colour from the colour map, but that colour is then applied to the body while the fins get a lighter shade, and maybe there’s also some shading on the belly.

Ultimately, while the prototype might not be the most attractive, once again you’ve hit upon a really inspiring use of something that other modders can around with.

Don’t worry about it. It is just that I’m never sure about the quality, I have some bias for things I made myself. I find it hard to know if something is good or I’m just proud to have created it. Or the opposite, if it is bad or I’m being too much of a perfectionist.

And nice ideas @YetiChow!

This:

And this:

Are similar, but I’m not worried about it for now. If there is a really bad color combination I will eventually hate it and change :wink:

Looks cool!
And they’re animated! Great to see you got the hang of it!

Also, just curiouse, did you actually manage to get them to spawn in water? Or was it the stamper?

Not yet. What I did is that the little bobber in the water will spawn the fish around it.
I know, super lame… I’m avoiding showing much of what I’m doing because I’m afraid people will go ultra hype mode about it and then get disappointed with the simplicity of the mechanics.
(There is room to improve later, as always)

2 Likes

i like how your fishies peaks above the waterline :slight_smile: Great work so far Bruno.

1 Like