105 lines
3.3 KiB
C#
105 lines
3.3 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Playables;
|
|
using UnityEngine.Timeline;
|
|
|
|
namespace Streamingle.Gaze
|
|
{
|
|
/// <summary>
|
|
/// Describes a camera/target gaze request on a Timeline track.
|
|
/// The track mixer combines requests and submits the result to a
|
|
/// <see cref="BlendshapeGazeDriver"/>; clips never write blendshapes directly.
|
|
/// </summary>
|
|
public sealed class BlendshapeGazeClip : PlayableAsset, ITimelineClipAsset
|
|
{
|
|
[SerializeField]
|
|
[Tooltip("Optional world-space target. When empty, the Driver Target Camera is used before Camera.main.")]
|
|
private ExposedReference<Transform> target;
|
|
|
|
[SerializeField, Range(0f, 1f)]
|
|
[Tooltip("Maximum gaze influence contributed by this clip.")]
|
|
private float strength = 1f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Allow optional eyelid/corrective channels from the calibration profile.")]
|
|
private bool enableCorrectives;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Override the bound driver's camera-cut response while this clip is dominant.")]
|
|
private bool overrideCutResponse;
|
|
|
|
[SerializeField]
|
|
private GazeCutResponse cutResponse;
|
|
|
|
[SerializeField, Min(0f)]
|
|
[Tooltip("Transition duration used by cut-response modes that smooth between cameras.")]
|
|
private float cutTransitionDuration = 0.1f;
|
|
|
|
public ExposedReference<Transform> Target
|
|
{
|
|
get => target;
|
|
set => target = value;
|
|
}
|
|
|
|
public float Strength
|
|
{
|
|
get => strength;
|
|
set => strength = SanitizeStrength(value);
|
|
}
|
|
|
|
public bool EnableCorrectives
|
|
{
|
|
get => enableCorrectives;
|
|
set => enableCorrectives = value;
|
|
}
|
|
|
|
public bool OverrideCutResponse
|
|
{
|
|
get => overrideCutResponse;
|
|
set => overrideCutResponse = value;
|
|
}
|
|
|
|
public GazeCutResponse CutResponse
|
|
{
|
|
get => cutResponse;
|
|
set => cutResponse = value;
|
|
}
|
|
|
|
public float CutTransitionDuration
|
|
{
|
|
get => cutTransitionDuration;
|
|
set => cutTransitionDuration = SanitizeDuration(value);
|
|
}
|
|
|
|
public ClipCaps clipCaps => ClipCaps.Blending;
|
|
|
|
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
|
|
{
|
|
var playable = ScriptPlayable<BlendshapeGazeBehaviour>.Create(graph);
|
|
var behaviour = playable.GetBehaviour();
|
|
|
|
behaviour.Target = target.Resolve(graph.GetResolver());
|
|
behaviour.Strength = SanitizeStrength(strength);
|
|
behaviour.EnableCorrectives = enableCorrectives;
|
|
behaviour.OverrideCutResponse = overrideCutResponse;
|
|
behaviour.CutResponse = cutResponse;
|
|
behaviour.CutTransitionDuration = SanitizeDuration(cutTransitionDuration);
|
|
|
|
return playable;
|
|
}
|
|
|
|
private static float SanitizeStrength(float value)
|
|
{
|
|
return float.IsNaN(value) || float.IsInfinity(value)
|
|
? 0f
|
|
: Mathf.Clamp01(value);
|
|
}
|
|
|
|
private static float SanitizeDuration(float value)
|
|
{
|
|
return float.IsNaN(value) || float.IsInfinity(value)
|
|
? 0f
|
|
: Mathf.Max(0f, value);
|
|
}
|
|
}
|
|
}
|