Static helper for built-in face presets used by the character editor. It defines entries for native and additional faces, creates PhotoFace objects from embedded JSON, finds/selects faces on a CharacterBaseShape, and applies fantasy face morph weights to a SkinnedModelRenderer.
using System;
using System.Text.Json;
namespace CharacterEditor;
/// <summary>Additional standard blend entries reuse the portable fitted-face basis.
/// Original seven-element native arrays and saved photo faces keep their meaning.</summary>
public static partial class BuiltInFaces
{
public sealed record Entry(int Index, string Key, string Label, string Id);
public const int NativeCount = 7, AdditionalCount = 6, Count = NativeCount + AdditionalCount;
public static IReadOnlyList<Entry> Entries { get; } = CreateEntries();
public static bool IsAvailableInRegion(int index, string region) => region != "ears" || index < NativeCount || Entries.Single(entry => entry.Index == index).Key is not ("goblin" or "bovine" or "orc");
public static bool Contains(PhotoFace face) => face is not null && Entries.Any(e => e.Id == face.Id);
public static int CustomCount(CharacterBaseShape shape) => shape?.PhotoFaces.Count(f => !Contains(f)) ?? 0;
public static PhotoFace Get(CharacterBaseShape shape, int index, bool create = false)
{
var entry = Entries.Single(e => e.Index == index);
var face = shape.PhotoFaces.FirstOrDefault(f => f.Id == entry.Id);
if (face is null && create)
{
face = Create(entry.Key);
face.Influence = 0;
shape.PhotoFaces.Add(face);
}
return face;
}
public static PhotoFace Create(string key)
{
var entry = Entries.Single(e => e.Key == key);
var face = JsonSerializer.Deserialize<PhotoFace>(Data(key));
face.Id = entry.Id;
face.Name = entry.Label;
face.Influence = 1;
face.Strength = 1;
return face;
}
public static void Select(CharacterAppearanceData appearance, string key)
{
UnifiedHuman.Enable(appearance);
Array.Fill(appearance.BaseShape.HeadWeights, 0);
appearance.BaseShape.PhotoFaces.Clear();
appearance.BaseShape.Regions.Clear();
appearance.BaseShape.PhotoFaces.Add(Create(key));
}
public static void Apply(SkinnedModelRenderer body, CharacterBaseShape shape)
{
foreach (var key in new[]
{
"goblin",
"bovine",
"orc"
}
)
{
var entry = Entries.Single(e => e.Key == key);
var face = shape.PhotoFaces.FirstOrDefault(f => f.Id == entry.Id);
foreach (var region in FaceRegions.Ids)
{
float amount = face is null ? 0 : Math.Clamp(FaceRegions.PhotoShare(shape, face, region) * face.Strength, 0, 1);
body.Morphs.Set($"ce_fantasy_{key}_{FaceRegions.MorphRegion(region)}", amount, 0);
}
}
}
}