using System;
using System.Collections.Generic;
using UnityEngine;
namespace Streamingle.Gaze
{
///
/// Row-major layout of the calibration grid. Down/Up describe gaze pitch and
/// Left/Right describe gaze yaw from the character's point of view.
///
public enum GazeCalibrationPoint
{
DownLeft = 0,
DownCenter = 1,
DownRight = 2,
CenterLeft = 3,
Center = 4,
CenterRight = 5,
UpLeft = 6,
UpCenter = 7,
UpRight = 8
}
public enum GazeChannelUsage
{
EyeLook = 0,
Corrective = 1
}
public enum GazeCorrectiveBlendMode
{
AdditiveFromCenter = 0,
Override = 1
}
public enum GazeCutResponse
{
Snap = 0,
Smooth = 1
}
[Serializable]
public sealed class GazeBlendShapeChannel
{
[SerializeField]
private string blendShapeName;
[SerializeField]
private GazeChannelUsage usage;
[SerializeField]
[Tooltip("Corrective channels normally add their direction-dependent delta from the Center sample to the live facial value.")]
private GazeCorrectiveBlendMode correctiveBlendMode;
public GazeBlendShapeChannel(
string blendShapeName,
GazeChannelUsage usage = GazeChannelUsage.EyeLook,
GazeCorrectiveBlendMode correctiveBlendMode = GazeCorrectiveBlendMode.AdditiveFromCenter)
{
this.blendShapeName = blendShapeName;
this.usage = usage;
this.correctiveBlendMode = correctiveBlendMode;
}
public string BlendShapeName
{
get => blendShapeName;
set => blendShapeName = value;
}
public GazeChannelUsage Usage
{
get => usage;
set => usage = value;
}
public GazeCorrectiveBlendMode CorrectiveBlendMode
{
get => correctiveBlendMode;
set => correctiveBlendMode = value;
}
}
[Serializable]
public sealed class GazeCalibrationSample
{
[SerializeField]
private GazeCalibrationPoint point;
[SerializeField]
private bool captured;
[SerializeField]
private float[] weights = Array.Empty();
public GazeCalibrationSample(GazeCalibrationPoint point)
{
this.point = point;
}
public GazeCalibrationPoint Point => point;
public bool Captured => captured;
public IReadOnlyList Weights => weights;
internal float GetWeight(int index)
{
return weights != null && index >= 0 && index < weights.Length ? weights[index] : 0f;
}
internal void SetWeights(IReadOnlyList values, int channelCount)
{
var count = Mathf.Max(0, channelCount);
if (weights == null || weights.Length != count)
weights = new float[count];
for (var i = 0; i < count; i++)
weights[i] = values != null && i < values.Count ? values[i] : 0f;
captured = true;
}
internal void Resize(int channelCount)
{
var count = Mathf.Max(0, channelCount);
if (weights != null && weights.Length == count)
return;
var resized = new float[count];
if (weights != null)
Array.Copy(weights, resized, Mathf.Min(weights.Length, resized.Length));
weights = resized;
captured = false;
}
internal void Invalidate()
{
captured = false;
}
internal void SetPoint(GazeCalibrationPoint value)
{
point = value;
}
}
///
/// Command passed from Timeline (or a future real-time source) to the final
/// LateUpdate blendshape writer.
///
public struct GazeTimelineState
{
public Vector3 TargetPosition;
public bool HasTargetPosition;
public Vector3 TargetDirection;
public bool HasTargetDirection;
public Transform Target;
public bool UseMainCamera;
public float Influence;
public bool EnableCorrectives;
public bool OverrideCutResponse;
public GazeCutResponse CutResponse;
public float CutTransitionDuration;
public bool ResetSmoothing;
public bool Deterministic;
}
public readonly struct GazeDirectionResult
{
public GazeDirectionResult(
Vector3 worldDirection,
Vector3 localDirection,
float rawYaw,
float rawPitch,
float clampedYaw,
float clampedPitch,
float normalizedYaw,
float normalizedPitch)
{
WorldDirection = worldDirection;
LocalDirection = localDirection;
RawYaw = rawYaw;
RawPitch = rawPitch;
ClampedYaw = clampedYaw;
ClampedPitch = clampedPitch;
NormalizedYaw = normalizedYaw;
NormalizedPitch = normalizedPitch;
}
public Vector3 WorldDirection { get; }
public Vector3 LocalDirection { get; }
public float RawYaw { get; }
public float RawPitch { get; }
public float ClampedYaw { get; }
public float ClampedPitch { get; }
public float NormalizedYaw { get; }
public float NormalizedPitch { get; }
public bool WasClamped => !Mathf.Approximately(RawYaw, ClampedYaw)
|| !Mathf.Approximately(RawPitch, ClampedPitch);
}
}