Skip to content

Outfits: dressing a mannequin in the colours a player picks

kke::Outfit (kke/Outfit.h) is a humanoid's clothes as four colours: the skin, a top, the trousers and the shoes. kke::dressModel paints them onto any skinned humanoid (the UAL mannequin, a Synty character) by which bone moves each part of the mesh, so no textures or extra meshes are needed. Climb Race and Tennis use it for their start menus.

How it works

  • Each bone belongs to a region (kke::regionOfBone): head, neck and hands are skin; spine, clavicles and upper arms are the top (forearms too with sleeves); pelvis and legs are the trousers; feet and toes are the shoes. Names go through canonicalBoneName, so Mixamo, UE and Synty rigs work.
  • dressModel(model, outfit) splits every skinned mesh into one mesh per region. A triangle goes to the region holding most of its vertices' weight, so seams follow the joints. Each region gets a material of its own (Outfit_Skin, Outfit_Top, Outfit_Bottom, Outfit_Shoes) in the outfit's colour; textures are dropped. Static meshes are left alone.
  • The dressed copy draws the same triangles as the plain model, so an outfit costs nothing per frame.

Using it in a game

#include "kke/Outfit.h"

kke::Outfit o;
o.skin = kke::skinTones()[6].rgb;
o.top = { 0.35f, 0.65f, 1.0f };
o.bottom = kke::clothColours()[3].rgb;

// One dressed copy per outfit, shared by everyone wearing it.
const std::string key = kke::outfitKey(o);
ModelModule::ModelId id = models.add(kke::dressModel(baseModel, o), "mygame/person/" + key);
models.spawn(id, transform); // no tint: the colours are the materials'

To change clothes, remove the instance and spawn the new outfit's model with the same transform; the animator and bone locals carry on.

kke::skinTones() is nine tones from Porcelain to Ebony (lightest first), so everyone can play as themselves. kke::clothColours() is twelve clothing colours. Climb Race and Tennis add them as start-menu look fields (Skin, Trousers, Shoes; the existing Colour row is the top):

kke::Lobby::LookField skin{ "skin", "Skin", {}, {} };
for (const kke::NamedColour& c : kke::skinTones()) {
    skin.choices.push_back(c.name);
    skin.swatches.push_back(c.rgb);
}
lobby.addLookField(std::move(skin));

Online

A player's look travels as their NetModule character, look:a.b.c.d.e|... (NETWORKING.md "Names and looks that change"). Every screen turns it back into an outfit with Lobby::lookFromText, so a new pick in the menu shows on every screen at once. CPU players' clothes come from their name, so they look the same everywhere too.

Synty people

When the POLYGON City Characters pack is installed, Climb Race and Tennis add a Body row: the mannequin, or one of eleven City people (Jock, Tourist, Firefighter, Paramedic, Grandpa, Grandma, Hipster, Punk, Beachgoer, Roadworker, Hot dog). kke::PeopleLibrary (kke/PeopleLibrary.h) finds the pack and loads a person the first time someone picks them.

The game keeps animating its mannequin, hidden, with all its clips and IK (hands on holds, the racket in the hand), and each frame kke::PoseRetarget (kke/AnimRig.h) copies that pose onto the person:

kke::PeopleLibrary people;
people.scan("MyGame");
if (const kke::PeopleLibrary::Body* b = people.body(person, models, mannequin)) {
    personInstance = models.spawn(b->model);
    // every frame, after the mannequin's pose is in rigLocals:
    kke::PeopleLibrary::follow(models, personInstance, *b, rigLocals, mannequinTransform);
}

The person keeps its own textures, so the outfit rows don't change it. A machine without the pack draws a person picked elsewhere as the mannequin. The Body row is the last look field, so the other rows keep their place in the look text whether or not a machine has the pack.