Displacement map prototype (#26709)

Requires https://github.com/space-wizards/RobustToolbox/pull/5023

This uses the new engine features (above) to add a displacement map shader. This allows deforming a sprite based on another sprite.

Primary use case is automatically adapting human clothing sprites to different species, something we want to make species like Vox a reality.

A basic example of wiring this up with Vox has been added. The system is however incredibly simple and **will** need more work by a content developer to select and toggle displacement maps when appropriate. I am leaving that to somebody else. For example right now the displacement map is applied even if a species already has custom-fit sprites for a piece of clothing, such as the grey jumpsuit for Vox.

Basic Aseprite plugins to help with authoring displacement maps have also been made.
This commit is contained in:
Pieter-Jan Briers
2024-04-27 08:03:58 +02:00
committed by GitHub
parent b4212a08f4
commit 2f7d0dedbd
9 changed files with 303 additions and 1 deletions

View File

@@ -11,6 +11,7 @@ using Content.Shared.Item;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Utility;
using static Robust.Client.GameObjects.SpriteComponent;
@@ -46,6 +47,7 @@ public sealed class ClientClothingSystem : ClothingSystem
};
[Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
public override void Initialize()
@@ -265,6 +267,7 @@ public sealed class ClientClothingSystem : ClothingSystem
// temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a
// bookmark to determine where in the list of layers we should insert the clothing layers.
bool slotLayerExists = sprite.LayerMapTryGet(slot, out var index);
var displacementData = inventory.Displacements.GetValueOrDefault(slot);
// add the new layers
foreach (var (key, layerData) in ev.Layers)
@@ -304,10 +307,29 @@ public sealed class ClientClothingSystem : ClothingSystem
// Sprite layer redactor when
// Sprite "redactor" just a week away.
if (slot == Jumpsuit)
layerData.Shader ??= "StencilDraw";
layerData.Shader ??= inventory.JumpsuitShader;
sprite.LayerSetData(index, layerData);
layer.Offset += slotDef.Offset;
if (displacementData != null)
{
var displacementKey = $"{key}-displacement";
if (!revealedLayers.Add(displacementKey))
{
Log.Warning($"Duplicate key for clothing visuals DISPLACEMENT: {displacementKey}.");
continue;
}
var displacementLayer = _serialization.CreateCopy(displacementData.Layer, notNullableOverride: true);
displacementLayer.CopyToShaderParameters!.LayerKey = key;
// Add before main layer for this item.
sprite.AddLayer(displacementLayer, index);
sprite.LayerMapSet(displacementKey, index);
revealedLayers.Add(displacementKey);
}
}
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true);