Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions VRCFaceTracking/Params/Eye/EyeTrackingParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,37 @@ public static class EyeTrackingParams

#endregion

#region Convergence

new EParam(v2 => v2.ConvergencePlaneDistance20M, "ConvergencePlaneDistance20M"),
new EParam(v2 => v2.ConvergencePlaneDistance10M, "ConvergencePlaneDistance10M"),
new EParam(v2 => v2.ConvergencePlaneDistance5M, "ConvergencePlaneDistance5M"),
new EParam(v2 => v2.ConvergencePlaneDistance2M, "ConvergencePlaneDistance2M"),
new EParam(v2 => v2.ConvergencePlaneDistance1M, "ConvergencePlaneDistance1M"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 0.1f, "ConvergencePlaneDistanceUnder10CM"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 0.2f, "ConvergencePlaneDistanceUnder20CM"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 0.5f, "ConvergencePlaneDistanceUnder50CM"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 1f, "ConvergencePlaneDistanceUnder1M"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 2f, "ConvergencePlaneDistanceUnder2M"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 5f, "ConvergencePlaneDistanceUnder5M"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 10f, "ConvergencePlaneDistanceUnder10M"),
new BoolParameter(v2 => v2.ConvergencePlaneDistanceRawM < 20f, "ConvergencePlaneDistanceUnder20M"),
new EParam(v2 => v2.ConvergencePointDistance20M, "ConvergencePointDistance20M"),
new EParam(v2 => v2.ConvergencePointDistance10M, "ConvergencePointDistance10M"),
new EParam(v2 => v2.ConvergencePointDistance5M, "ConvergencePointDistance5M"),
new EParam(v2 => v2.ConvergencePointDistance2M, "ConvergencePointDistance2M"),
new EParam(v2 => v2.ConvergencePointDistance1M, "ConvergencePointDistance1M"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 0.1f, "ConvergencePointDistanceUnder10CM"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 0.2f, "ConvergencePointDistanceUnder20CM"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 0.5f, "ConvergencePointDistanceUnder50CM"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 1f, "ConvergencePointDistanceUnder1M"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 2f, "ConvergencePointDistanceUnder2M"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 5f, "ConvergencePointDistanceUnder5M"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 10f, "ConvergencePointDistanceUnder10M"),
new BoolParameter(v2 => v2.ConvergencePointDistanceRawM < 20f, "ConvergencePointDistanceUnder20M"),

#endregion

#region Widen

new EParam(v2 => v2.Left.Widen > v2.Right.Widen ? v2.Left.Widen : v2.Right.Widen, "EyesWiden"),
Expand Down
102 changes: 102 additions & 0 deletions VRCFaceTracking/UnifiedTrackingData.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ViveSR.anipal.Eye;
using ViveSR.anipal.Lip;
Expand Down Expand Up @@ -47,6 +48,18 @@ public class EyeTrackingData

// Custom parameter
public float EyesPupilDiameter;
public float ConvergencePlaneDistance20M;
public float ConvergencePlaneDistance10M;
public float ConvergencePlaneDistance5M;
public float ConvergencePlaneDistance2M;
public float ConvergencePlaneDistance1M;
public float ConvergencePlaneDistanceRawM;
public float ConvergencePointDistance20M;
public float ConvergencePointDistance10M;
public float ConvergencePointDistance5M;
public float ConvergencePointDistance2M;
public float ConvergencePointDistance1M;
public float ConvergencePointDistanceRawM;

public void UpdateData(EyeData_v2 eyeData)
{
Expand Down Expand Up @@ -78,6 +91,95 @@ public void UpdateData(EyeData_v2 eyeData)
EyesDilation = (dilation - _minDilation) / (_maxDilation - _minDilation);
EyesPupilDiameter = dilation > 10 ? 1 : dilation / 10;
}

if (
eyeData.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY)
&& eyeData.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY)
)
{
UpdateEyeConvergence(eyeData);
}
}

private void UpdateEyeConvergence(EyeData_v2 eyeData)
{
// In radians
var leftGazeAngle = -Math.Asin(eyeData.verbose_data.left.gaze_direction_normalized.x);
var rightGazeAngle = Math.Asin(eyeData.verbose_data.right.gaze_direction_normalized.x);

// Form the base of the triangle
var leftComp = Math.PI / 2 - leftGazeAngle;
var rightComp = Math.PI / 2 - rightGazeAngle;

// The gaze angles are based on the gaze origin, located at the center of the cornea sphere.
// These cornea spheres move, and both get closer to each other when the eyes converge.
// This is effectively the dynamic IPD needed for these calculations, rather than the HMD lenses IPD.
var dynamicIpdMillimeters = eyeData.verbose_data.left.gaze_origin_mm.x - eyeData.verbose_data.right.gaze_origin_mm.x;

if (leftComp + rightComp >= Math.PI)
{
// Either gazing at infinite distance, or diverging (strabismus)
ConvergencePlaneDistance20M = 1f;
ConvergencePlaneDistance10M = 1f;
ConvergencePlaneDistance5M = 1f;
ConvergencePlaneDistance2M = 1f;
ConvergencePlaneDistance1M = 1f;
ConvergencePlaneDistanceRawM = 10000f;
ConvergencePointDistance20M = 1f;
ConvergencePointDistance10M = 1f;
ConvergencePointDistance5M = 1f;
ConvergencePointDistance2M = 1f;
ConvergencePointDistance1M = 1f;
ConvergencePointDistanceRawM = 10000f;
}
else
{
// Basic trigonometry
// - Calculate the left side of the triangle where leftComp, rightComp, and IPD form the base.
var leftSideMillimetres = Math.Sin(rightComp) * dynamicIpdMillimeters / Math.Sin(Math.PI - leftComp - rightComp);

// Handle two different interpretations of convergence distance. This is more relevant for objects reaching into the intimate space.
// (In both cases, the convergence distance is not factored by looking up, straight, or down)
{
// # Distance to the convergence plane (triangle height)
// This convergence distance corresponds to the distance between the convergence point
// and an infinite line passing through the two gaze origins (note: gaze origin is not the center of eyeballs).

// - Calculate the height of the right triangle where leftComp is the angle opposite to the convergence distance
var convergenceDistanceMillimetres = leftSideMillimetres * Math.Sin(leftComp);

var convergenceDistanceMetres = (float)convergenceDistanceMillimetres / 1000f;
ConvergencePlaneDistance20M = Saturate(convergenceDistanceMetres / 20f);
ConvergencePlaneDistance10M = Saturate(convergenceDistanceMetres / 10f);
ConvergencePlaneDistance5M = Saturate(convergenceDistanceMetres / 5f);
ConvergencePlaneDistance2M = Saturate(convergenceDistanceMetres / 2f);
ConvergencePlaneDistance1M = Saturate(convergenceDistanceMetres / 1f);
ConvergencePlaneDistanceRawM = convergenceDistanceMetres;
}
{
// # Distance to the convergence point (length of median line segment)
// This convergence distance corresponds to the distance between the convergence point
// and the point between the two gaze origins (also known as combined gaze origin).

// - Calculate the right side of the triangle where leftComp, rightComp, and IPD form the base.
var rightSideMillimetres = Math.Sin(leftComp) * dynamicIpdMillimeters / Math.Sin(Math.PI - leftComp - rightComp);
// - The median length is the average of the two triangle sides
var convergenceDistanceMillimetres = (leftSideMillimetres + rightSideMillimetres) / 2;

var convergenceDistanceMetres = (float)convergenceDistanceMillimetres / 1000f;
ConvergencePointDistance20M = Saturate(convergenceDistanceMetres / 20f);
ConvergencePointDistance10M = Saturate(convergenceDistanceMetres / 10f);
ConvergencePointDistance5M = Saturate(convergenceDistanceMetres / 5f);
ConvergencePointDistance2M = Saturate(convergenceDistanceMetres / 2f);
ConvergencePointDistance1M = Saturate(convergenceDistanceMetres / 1f);
ConvergencePointDistanceRawM = convergenceDistanceMetres;
}
}
}

private float Saturate(float convergenceDistance)
{
return convergenceDistance > 1f ? 1f : convergenceDistance;
}

private void UpdateMinMaxDilation(float readDilation)
Expand Down