diff --git a/VRCFaceTracking.Core/Params/Data/Mutation/Correctors.cs b/VRCFaceTracking.Core/Params/Data/Mutation/Correctors.cs index 3530c7dd..5a5970cb 100644 --- a/VRCFaceTracking.Core/Params/Data/Mutation/Correctors.cs +++ b/VRCFaceTracking.Core/Params/Data/Mutation/Correctors.cs @@ -18,6 +18,11 @@ public class Correctors : TrackingMutation public bool mouthClosedFix = true; [MutationProperty("LipSuck Limiter", true)] public bool lipSuckFix = true; + + // How much "influence" the opposite eye has on openness + [MutationProperty("EyeLid Blend", true)] + public float eyeLidBlend = 0.0f; // 0.00f meaning zero influence, 1.00f meaning the value of each eyelid is the median of both + public override void MutateData(ref UnifiedTrackingData data) { @@ -32,14 +37,31 @@ public override void MutateData(ref UnifiedTrackingData data) if (lipSuckFix) { - data.Shapes[(int)UnifiedExpressions.LipSuckLowerLeft].Weight = - data.Shapes[(int)UnifiedExpressions.LipSuckLowerLeft].Weight * (1f - data.Shapes[(int)UnifiedExpressions.MouthLowerDownLeft].Weight); - data.Shapes[(int)UnifiedExpressions.LipSuckLowerRight].Weight = - data.Shapes[(int)UnifiedExpressions.LipSuckLowerRight].Weight * (1f - data.Shapes[(int)UnifiedExpressions.MouthLowerDownRight].Weight); - data.Shapes[(int)UnifiedExpressions.LipSuckUpperLeft].Weight = - data.Shapes[(int)UnifiedExpressions.LipSuckUpperLeft].Weight * (1f - data.Shapes[(int)UnifiedExpressions.MouthUpperUpLeft].Weight); - data.Shapes[(int)UnifiedExpressions.LipSuckUpperRight].Weight = - data.Shapes[(int)UnifiedExpressions.LipSuckUpperRight].Weight * (1f - data.Shapes[(int)UnifiedExpressions.MouthUpperUpRight].Weight); + data.Shapes[(int)UnifiedExpressions.LipSuckLowerLeft].Weight *= (1f - data.Shapes[(int)UnifiedExpressions.MouthLowerDownLeft].Weight); + data.Shapes[(int)UnifiedExpressions.LipSuckLowerRight].Weight *= (1f - data.Shapes[(int)UnifiedExpressions.MouthLowerDownRight].Weight); + data.Shapes[(int)UnifiedExpressions.LipSuckUpperLeft].Weight *= (1f - data.Shapes[(int)UnifiedExpressions.MouthUpperUpLeft].Weight); + data.Shapes[(int)UnifiedExpressions.LipSuckUpperRight].Weight *= (1f - data.Shapes[(int)UnifiedExpressions.MouthUpperUpRight].Weight); + } + + if (eyeLidBlend > 0.00f) + { + // Half the blend because we don't want users swapping eyes unintentionally + var blend = eyeLidBlend * 0.5f; + var inverseBlend = 1.0f - blend; + + // Pre-calculate what our parameters would end up using internally + var leftCalculated = data.Eye.Left.Openness * 0.75f + data.Shapes[(int)UnifiedExpressions.EyeWideLeft].Weight * 0.25f; + var rightCalculated = data.Eye.Right.Openness * 0.75f + data.Shapes[(int)UnifiedExpressions.EyeWideRight].Weight * 0.25f; + + // Actual blending logic + var leftResultant = leftCalculated * inverseBlend + rightCalculated * blend; + var rightResultant = rightCalculated * inverseBlend + leftCalculated * blend; + + // Solve for our original values + data.Eye.Left.Openness = Math.Clamp(leftResultant, 0.0f, 1.0f); + data.Shapes[(int)UnifiedExpressions.EyeWideLeft].Weight = Math.Clamp(leftResultant, 0.0f, 1.0f); + data.Eye.Right.Openness = Math.Clamp(rightResultant, 0.0f, 1.0f); + data.Shapes[(int)UnifiedExpressions.EyeWideRight].Weight = Math.Clamp(rightResultant, 0.0f, 1.0f); } } }