204 lines
5.6 KiB
C#
204 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Streamingle.Gaze
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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<float>();
|
|
|
|
public GazeCalibrationSample(GazeCalibrationPoint point)
|
|
{
|
|
this.point = point;
|
|
}
|
|
|
|
public GazeCalibrationPoint Point => point;
|
|
|
|
public bool Captured => captured;
|
|
|
|
public IReadOnlyList<float> Weights => weights;
|
|
|
|
internal float GetWeight(int index)
|
|
{
|
|
return weights != null && index >= 0 && index < weights.Length ? weights[index] : 0f;
|
|
}
|
|
|
|
internal void SetWeights(IReadOnlyList<float> 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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Command passed from Timeline (or a future real-time source) to the final
|
|
/// LateUpdate blendshape writer.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|