mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-08-01 08:18:20 -04:00
// SkinnedModelRenderer - the only new entry point for speaking
SoundHandle SpeakSound( SoundEvent sound, GameObject mouth = null )
SoundHandle SpeakSound( SoundFile sound, float volume = 1, float pitch = 1, GameObject mouth = null )
// SoundFile - the authored lipsync track, read from the compiled vsnd
VisemeTrack Visemes { get; } // null = no track (or not loaded yet, see IsValidForPlayback)
// VisemeTrack - visemes over time, authored in the sound editor
IReadOnlyList<VisemeFrame> Frames { get; }
float Duration { get; }
bool Sample( float time, Span<float> weights )
// VisemeFrame - one viseme span (struct: Viseme, StartTime, EndTime)
// Visemes - the standard 15-viseme table, OVR order
static IReadOnlyList<string> MorphNames { get; }
static int Count { get; }
// MorphCollection - the one shared viseme blend (sounds, voice chat, editor preview)
void ApplyVisemes( ReadOnlySpan<float> visemeWeights, float scale = 1, float smoothTime = 0 )
// ModelMorphs - per-model viseme weight table, cached managed-side (no interop on lookups)
float GetVisemeMorph( int viseme, int morph )
float GetVisemeMorph( string viseme, int morph )
// ResourceCompileContext - inject managed data into natively-compiled resources
void WriteBlock( string blockName, ReadOnlySpan<byte> data ) // four-char block names, eg "LIPS"
void WriteBlockJson( string blockName, object obj )
JsonObject ReadMeta() // the asset's .meta, registers a compile dependency
T ReadMeta<T>( string key, T defaultValue = default )
// ResourceLoadContext - read blocks back when the resource loads (Resource.OnLoaded, engine-internal for now)
// public ref struct, only valid during the load callback
bool Exists( string blockName )
ReadOnlySpan<byte> ReadData( string blockName )
string ReadString( string blockName )
T ReadJson<T>( string blockName, T defaultValue = default )
127 lines
3.4 KiB
C#
127 lines
3.4 KiB
C#
namespace Sandbox;
|
|
|
|
/// <summary>
|
|
/// Used to access and manipulate morphs.
|
|
/// </summary>
|
|
public abstract class MorphCollection
|
|
{
|
|
/// <summary>
|
|
/// Reset all morphs to their default values.
|
|
/// </summary>
|
|
public abstract void ResetAll();
|
|
|
|
/// <summary>
|
|
/// Reset all morphs to their default values.
|
|
/// </summary>
|
|
public abstract void ResetAll( float fadeTime );
|
|
|
|
/// <summary>
|
|
/// Reset morph number i to its default value.
|
|
/// </summary>
|
|
public abstract void Reset( int i );
|
|
|
|
/// <summary>
|
|
/// Reset morph number i to its default value.
|
|
/// </summary>
|
|
public abstract void Reset( int i, float fadeTime );
|
|
|
|
/// <summary>
|
|
/// Reset named morph to its default value.
|
|
/// </summary>
|
|
public abstract void Reset( string name );
|
|
|
|
/// <summary>
|
|
/// Reset named morph to its default value.
|
|
/// </summary>
|
|
public abstract void Reset( string name, float fadeTime );
|
|
|
|
/// <summary>
|
|
/// Set indexed morph to this value.
|
|
/// </summary>
|
|
public abstract void Set( int i, float weight );
|
|
|
|
/// <summary>
|
|
/// Set named morph to this value.
|
|
/// </summary>
|
|
public abstract void Set( string name, float weight );
|
|
|
|
/// <summary>
|
|
/// Set indexed morph to this value.
|
|
/// </summary>
|
|
public abstract void Set( int i, float weight, float fadeTime );
|
|
|
|
/// <summary>
|
|
/// Set named morph to this value.
|
|
/// </summary>
|
|
public abstract void Set( string name, float weight, float fadeTime );
|
|
|
|
/// <summary>
|
|
/// Get indexed morph value (Note: Currently, this only gets the override morph value)
|
|
/// </summary>
|
|
public abstract float Get( int i );
|
|
|
|
/// <summary>
|
|
/// Get named morph value (Note: Currently, this only gets the override morph value)
|
|
/// </summary>
|
|
public abstract float Get( string name );
|
|
|
|
/// <summary>
|
|
/// Retrieve name of a morph at given index.
|
|
/// </summary>
|
|
public abstract string GetName( int index );
|
|
|
|
/// <summary>
|
|
/// Amount of morphs.
|
|
/// </summary>
|
|
public abstract int Count { get; }
|
|
|
|
/// <summary>
|
|
/// The model these morphs belong to, if known.
|
|
/// </summary>
|
|
internal virtual Model Model => null;
|
|
|
|
/// <summary>
|
|
/// Drive the model's viseme morphs from a set of viseme weights, one per entry
|
|
/// in <see cref="Visemes.MorphNames"/>. Only the morphs that visemes affect are
|
|
/// touched. This is the one blend everything shares - speaking sounds, voice
|
|
/// chat, the sound editor preview - so the same weights make the same mouth
|
|
/// everywhere. A <paramref name="smoothTime"/> above zero eases each morph
|
|
/// toward its target instead of snapping.
|
|
/// </summary>
|
|
public void ApplyVisemes( ReadOnlySpan<float> visemeWeights, float scale = 1.0f, float smoothTime = 0.0f )
|
|
{
|
|
var model = Model;
|
|
if ( model is null )
|
|
return;
|
|
|
|
var modelMorphs = model.Morphs;
|
|
var indices = modelMorphs.VisemeMorphIndices;
|
|
|
|
for ( var j = 0; j < indices.Length; j++ )
|
|
{
|
|
// Blend the viseme morph weights by how strong each viseme is right now
|
|
var target = 0.0f;
|
|
for ( var v = 0; v < Visemes.Count && v < visemeWeights.Length; v++ )
|
|
{
|
|
if ( visemeWeights[v] <= 0.0f )
|
|
continue;
|
|
|
|
target += (modelMorphs.GetVisemeMorphWeight( j, v ) - target) * visemeWeights[v];
|
|
}
|
|
|
|
target = (target * scale).Clamp( 0.0f, 1.0f );
|
|
|
|
var morphIndex = indices[j];
|
|
|
|
if ( smoothTime > 0.0f )
|
|
{
|
|
var current = Get( morphIndex );
|
|
current = MathX.ExponentialDecay( current, target, smoothTime * 0.17f, Time.Delta );
|
|
target = Math.Max( 0.0f, current );
|
|
}
|
|
|
|
Set( morphIndex, target );
|
|
}
|
|
}
|
|
}
|