This is the programming guide to the Multilayer sticker projection system in Mutable, intended to complement the guide for artists and designers Multilayer projection on switchable parts, which should also be read by the programmers. It also contains an optimization section at the end.
The Multilayer system in Mutable introduces a new concept, ranged parameters (multi-value parameters). Whereas a normal parameter can only have one value, ranged parameters can have up to N values. You can think of them as an array of N values, all related to the same parameter, and you can access them with an index that goes from 0 to N - 1.
For the programmer's convenience, when using the "Group Projector Parameter" node Mutable manage nearly everything. It will automatically create several ranged parameters to control the stickers, and the programmer will only have to set their values to create the desired sticker design over the character.
Let's assume that the following "Group Projector Parameter" node is placed in the mutable graph:
The following controls for the "ShirtProjector" parameter will appear in the Mutable Editor preview viewport:
They let the developer add and remove layers of stickers, select them and move them around, choose which sticker appears in each layer, their opacity, etc. But all this only works in the editor, how to do it in-game from C++? What parameters have to be changed?
The Mutable compiler automatically creates a set of parameters that let the programmer have the same control with the Mutable C++ API. Here is the list of the parameters that are automatically created for a "StickerName" node (assuming the Projector Parameter name is "StickerName", change it to your own projector name) and that the programmer has to set:
All of them are ranged parameters, except (1) "StickerName_NumLayers" which is a normal scalar parameter with only one value (the number of layers of the sticker). All the others will need to be set for multiple ranged values with the new features of the API. Here is an example on how to set each parameter:
It's used just to tell Mutable how many layers this Projector will have, up to a maximum of 5. To set 2 layers call the funcion:
To completely disable the projector, just set it to 0 layers:
This parameter controls the location, orientation, scale and projection type of the projector. Since it's a ranged parameter, you have to specify which layer you are changing with a LayerIndex int parameter (look at the example below). Please make sure the layer you are changing is consistent with the number of layers set in the previous parameter. The valid values for LayerIndex go from 0 to StickerName_NumLayers - 1.
CustomizableObjectInstance->SetProjectorValue("StickerName", posX, posY, posZ, dirX, dirY, dirZ, upX, upY, upZ, scaleX, scaleY, scaleZ, angle, projectionType, LayerIndex );
This controls which texture will be used for the sticker image of the layer. It's also a ranged parameter, so you have to specify which layer you are changing with the LayerIndex int parameter. OptionName is a string that comes from the "Option Images" property from the projector node in the Mutable graph:
CustomizableObjectInstance->SetIntParameterSelectedOption("StickerName_SelectedImages", OptionName , LayerIndex);
This controls the opacity of each sticker. It's also a ranged parameter, so you have to specify which layer you are changing with the LayerIndex int parameter. Set it to 0 for a completely transparent sticker layer and to 1 for a complete opaque one. To set a half opaque one, call this function:
CustomizableObjectInstance->SetFloatParameterSelectedOption("StickerName_Opacity", 0.5f, LayerIndex);
Multilayer stickers can have up to 5 stickers, and a separate multilayer sticker can be applied to each part of the character such as backpacks, jackets, helmets, etc. This means that the number of stickers and layers can grow very quickly and become expensive to compute in realtime in the customization lobby.
One way to improve this is to separate each sticker parameter into a different optimization state, so that the programmer can tell Mutable that only one sticker parameter is going to be changed at a time. Mutable will then optimize the computation for only that sticker and not recompute the other ones.
This can be achieved in the "Base Object" node of the base Mutable graph (ex: Bandit_forFPS). There you can create a state for each sticker node that exists in the character:
In the screenshot you can see two states, one for gameplay and one for one projector (only for the lobby). Please note that in the sticker state you have to fill in in the names of the parameters that control the projector. In addition, texture compression has been disabled and only the first LOD is build, which is very important for realtime performance in the customization lobby.
To switch states, in the editor you do it with the following button:
And from C++ it's done with the following function:
It's very important to remember to set the correct state during gameplay, because the states optimized for projectors spend much more memory.