Bladeren bron

Smooth dynamic vignetting

Marcel Zickler 3 jaren geleden
bovenliggende
commit
efd5a95fc6

+ 1 - 1
Assembly-CSharp.csproj

@@ -267,6 +267,7 @@
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\AntManager.cs" />
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\Fit\FieldDefinition.cs" />
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\Fit\Profile\Types\RiderPositionType.cs" />
+     <Compile Include="Assets\Scripts\SicknessReduction\Visual\Vignetting\RestrictionSuggestor.cs" />
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\Fit\Profile\Types\SportBits3.cs" />
      <Compile Include="Assets\AdvancedAnt\DEMO PREFABS\PrefabDemoDisplay.cs" />
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\Fit\Profile\Types\LeftRightBalance100.cs" />
@@ -311,7 +312,6 @@
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\Fit\Profile\Types\StrokeType.cs" />
      <Compile Include="Assets\AdvancedAnt\Scripts\SpeedDisplay.cs" />
      <Compile Include="Assets\AdvancedAnt\Plugins\Ant\Fit\Mesg.cs" />
-     <Compile Include="Assets\Scripts\SicknessReduction\Visual\Vignetting\RestrictionSuggestor.cs" />
      <None Include="Assets\TextMesh Pro\Shaders\TMPro.cginc" />
      <None Include="Assets\TextMesh Pro\Shaders\TMP_SDF-Mobile Overlay.shader" />
      <None Include="Assets\AdvancedAnt\Plugins\Ant\License.txt" />

+ 2 - 2
Assets/Materials/Vignette.mat

@@ -58,10 +58,10 @@ Material:
     - _GlossMapScale: 0
     - _Glossiness: 0
     - _GlossyReflections: 0
-    - _IFOV: 0.19999997
+    - _IFOV: 0.34450415
     - _InnerRadius: 0.15
     - _Metallic: 0
-    - _OFOV: 0.39999998
+    - _OFOV: 0.44450414
     - _OcclusionStrength: 1
     - _QueueOffset: 0
     - _ReceiveShadows: 1

+ 8 - 8
Assets/Scenes/MainScene.unity

@@ -208532,11 +208532,11 @@ MonoBehaviour:
   forwardRenderer: {fileID: 11400000, guid: 4a8e21d5c33334b11b34a596161b9360, type: 2}
   bikeController: {fileID: 201820990}
   hmd: {fileID: 1119305144}
-  minRestriction: 0
-  maxRestriction: 80
-  angularVelocityThreshold: 20
-  steerAngleThreshold: 15
-  leanAngleThreshold: 20
+  vignettingSource: 1
+  minRestriction: 0.55
+  maxRestriction: 0.65
+  maxRestrictionChangePerSecond: 1.2
+  threshold: 12
 --- !u!4 &868699605
 Transform:
   m_ObjectHideFlags: 0
@@ -208544,7 +208544,7 @@ Transform:
   m_PrefabInstance: {fileID: 0}
   m_PrefabAsset: {fileID: 0}
   m_GameObject: {fileID: 868699603}
-  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
   m_LocalPosition: {x: 0, y: 0, z: 0}
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_Children: []
@@ -454119,7 +454119,7 @@ PrefabInstance:
     - target: {fileID: 4988978072042319893, guid: 3b07d6594636ab04d9c1fac04c1cde7e,
         type: 3}
       propertyPath: steer
-      value: 0
+      value: 1
       objectReference: {fileID: 0}
     - target: {fileID: 4988978072042319893, guid: 3b07d6594636ab04d9c1fac04c1cde7e,
         type: 3}
@@ -454159,7 +454159,7 @@ PrefabInstance:
     - target: {fileID: 4988978072042319979, guid: 3b07d6594636ab04d9c1fac04c1cde7e,
         type: 3}
       propertyPath: steer
-      value: 1
+      value: 0
       objectReference: {fileID: 0}
     - target: {fileID: 4988978072042319979, guid: 3b07d6594636ab04d9c1fac04c1cde7e,
         type: 3}

+ 10 - 0
Assets/Scripts/Helpers.cs

@@ -66,9 +66,19 @@ public class Helpers
         if (vector.y <= vector.x && vector.y <= vector.z) return vector.y;
         return vector.z;
     }
+    
+    public static float GetMaxComponent(Vector3 vector)
+    {
+        if (vector.x > vector.y && vector.x > vector.z) return vector.x;
+        if (vector.y > vector.x && vector.y > vector.z) return vector.y;
+        return vector.z;
+    }
 
     public static long RoundToLong(float f)
     {
         return (long) Mathf.Round(f);
     }
+
+    public static Vector3 Vector3Abs(Vector3 value) =>
+        new Vector3(Mathf.Abs(value.x), Mathf.Abs(value.y), Mathf.Abs(value.z));
 }

+ 60 - 12
Assets/Scripts/SicknessReduction/Visual/Vignetting/DynamicVignetting.cs

@@ -6,57 +6,105 @@ using UnityEngine.Rendering.Universal;
 
 namespace SicknessReduction.Visual.Vignetting
 {
+    public enum VignettingSource
+    {
+        AngularVelocity,
+        SteerAngle
+    }
+
     public class DynamicVignetting : MonoBehaviour
     {
         //TODO: cite https://www.researchgate.net/publication/326760789_Assessing_vignetting_as_a_means_to_reduce_VR_sickness_during_amplified_head_rotations
-        //TODO: there is a patent for this (WTF) https://patents.google.com/patent/US9645395B2/en
+        //TODO: there is a patent for this https://patents.google.com/patent/US9645395B2/en
         //TODO: check Fernandes & Feiner
 
-        private const float DIST_IFOV_OVOF = .2f;
+        private const float DIST_IFOV_OVOF = .10f;
 
         [Header("Unity Objects")] public ForwardRendererData forwardRenderer;
         public RbBicycleController bikeController;
         public Transform hmd;
 
-        [Header("Restriction Data")] public float minRestriction = 0f; //from Fernandes & Feiner
-        public float maxRestriction = 80f; //from Fernandes & Feiner
-        public float angularVelocityThreshold = 20f; //deg/sec check in Fernandes & Feiner
-        public float steerAngleThreshold = 15f; //deg/sec check in Fernandes & Feiner
-        public float leanAngleThreshold = 20f; //deg/sec check in Fernandes & Feiner
+        [Header("Restriction Data")] public VignettingSource vignettingSource;
+        [Range(0, 1)] public float minRestriction = 0.3f;
+        [Range(0, 1)] public float maxRestriction = 0.7f;
+        public float maxRestrictionChangePerSecond = 0.8f;
+
+        [Tooltip("Depending on Vignetting source -> deg or deg/s")]
+        public float threshold = 20f;
 
         //TODO: figure out what angular velocity means in my context
         private MaterialBlitFeature blitFeature;
         private Material blitFeatureMaterial;
         private bool blitFeatureAvailable;
 
-        private QueueBasedRestrictionSuggestor leaningAngleSuggestor;
-        private QueueBasedRestrictionSuggestor hmdAngleSuggestor;
+        private ValueBasedRestrictionSuggestor steerAngleSuggestor;
+        private QueueBasedRestrictionSuggestorVector3 angularVelocitySuggestor;
+        private float currentRestriction;
 
         private void Start()
         {
             blitFeature = (MaterialBlitFeature) forwardRenderer.rendererFeatures.FirstOrDefault(f =>
                 f is MaterialBlitFeature && f.name.Equals("VignetteBlitFilter"));
             blitFeatureAvailable = blitFeature != null;
+
             if (!blitFeatureAvailable) return;
+            // ReSharper disable once PossibleNullReferenceException
             blitFeatureMaterial = blitFeature.settings.MaterialToBlit;
+
+            if (vignettingSource == VignettingSource.AngularVelocity)
+            {
+                angularVelocitySuggestor =
+                    new QueueBasedRestrictionSuggestorVector3(threshold, minRestriction, maxRestriction, 180f); //deg/s 
+            }
+            else if (vignettingSource == VignettingSource.SteerAngle)
+            {
+                steerAngleSuggestor =
+                    new ValueBasedRestrictionSuggestor(threshold: threshold, minRestriction, maxRestriction,
+                        bikeController.maxSteeringAngle); //deg
+            }
         }
 
         private void Update()
         {
             if (!blitFeatureAvailable) return;
-            if (Mathf.Abs(bikeController.CurrentSteerAngle) >= steerAngleThreshold)
+
+            float desiredRestriction;
+
+            if (vignettingSource == VignettingSource.AngularVelocity)
+            {
+                angularVelocitySuggestor.AddValue(bikeController.rigidBody.transform.localEulerAngles);
+                desiredRestriction = angularVelocitySuggestor.Suggestion;
+            }
+            else
+            {
+                steerAngleSuggestor.Value = bikeController.CurrentSteerAngle;
+                desiredRestriction = steerAngleSuggestor.Suggestion;
+            }
+
+            var desiredChange = desiredRestriction - currentRestriction;
+            var maxChange = Time.deltaTime * maxRestrictionChangePerSecond;
+            var change = Mathf.Sign(desiredChange) * Mathf.Min(Mathf.Abs(desiredChange), maxChange);
+            var correctedRestriction = Mathf.Clamp(currentRestriction + change, 0, 1);
+
+            Debug.Log("V: CurrentRestriction = " + currentRestriction);
+            Debug.Log("V: DesiredChange = " + desiredChange);
+            Debug.Log("V: MaxChange = " + maxChange);
+            Debug.Log("V: DesiredRestriction = " + desiredRestriction);
+            Debug.Log("V: CorrectedRestriction = " + correctedRestriction);
+
+            if (correctedRestriction > 0f)
             {
                 blitFeature.SetActive(true);
-                UpdateMaterial(.6f); //TODO: no magic number
+                UpdateMaterial(correctedRestriction);
                 return;
             }
 
-            //TODO: figure out how to combine everything
             blitFeature.SetActive(false);
         }
 
         private void UpdateMaterial(float restriction)
         {
+            currentRestriction = restriction;
             var r = Mathf.Clamp(1 - restriction, 0, 1);
             blitFeatureMaterial.SetFloat("_OFOV", r);
             blitFeatureMaterial.SetFloat("_IFOV", Mathf.Clamp(r - DIST_IFOV_OVOF, 0, 1));

+ 107 - 25
Assets/Scripts/SicknessReduction/Visual/Vignetting/RestrictionSuggestor.cs

@@ -5,18 +5,81 @@ using UnityEngine;
 
 namespace SicknessReduction.Visual.Vignetting
 {
-    public interface RestrictionSuggestor
+    public abstract class RestrictionSuggestor
     {
-        float Suggestion { get; }
+        public abstract float Suggestion { get; }
+
+        protected readonly float threshold;
+        protected readonly float minRestriction;
+        protected readonly float maxRestriction;
+        protected readonly float maxValue;
+
+        protected RestrictionSuggestor(float threshold, float minRestriction, float maxRestriction,
+            float maxValue)
+        {
+            this.threshold = threshold;
+            this.minRestriction = minRestriction;
+            this.maxRestriction = maxRestriction;
+            this.maxValue = maxValue;
+        }
+
+        protected float LerpedSuggestion(float value) => Mathf.Lerp(minRestriction, maxRestriction,
+            (value - threshold) / (maxValue - threshold));
+    }
+
+    public class ValueBasedRestrictionSuggestor : RestrictionSuggestor
+    {
+        public override float Suggestion
+        {
+            get
+            {
+                var abs = Mathf.Abs(Value);
+                return abs < threshold
+                    ? 0f
+                    : LerpedSuggestion(abs);
+            }
+        }
+
+        public float Value { set; get; } = 0f;
+
+
+        public ValueBasedRestrictionSuggestor(float threshold, float minRestriction, float maxRestriction,
+            float maxValue) : base(threshold, minRestriction, maxRestriction, maxValue)
+        {
+        }
     }
 
-    public class QueueBasedRestrictionSuggestor : RestrictionSuggestor
+    public abstract class QueueBasedRestrictionSuggestor<T> : RestrictionSuggestor
     {
-        private Queue<Tuple<float, float>> values;
-        private int bufferSize;
-        private float threshold;
+        protected Queue<Tuple<float, T>> values;
+        protected int bufferSize;
+
+        public QueueBasedRestrictionSuggestor(float threshold, float minRestriction, float maxRestriction,
+            float maxValue, int bufferSize = 10) : base(threshold, minRestriction, maxRestriction, maxValue)
+        {
+            this.bufferSize = bufferSize;
+            values = new Queue<Tuple<float, T>>(bufferSize);
+        }
 
-        public float Suggestion
+        public void AddValue(T value)
+        {
+            if (values.Count >= bufferSize)
+            {
+                values.Dequeue();
+            }
+
+            values.Enqueue(new Tuple<float, T>(Time.time, value));
+        }
+    }
+
+    public class QueueBasedRestrictionSuggestorFloat : QueueBasedRestrictionSuggestor<float>
+    {
+        public QueueBasedRestrictionSuggestorFloat(float threshold, float minRestriction, float maxRestriction,
+            float maxValue, int bufferSize = 10) : base(threshold, minRestriction, maxRestriction, maxValue, bufferSize)
+        {
+        }
+
+        public override float Suggestion
         {
             get
             {
@@ -26,36 +89,55 @@ namespace SicknessReduction.Visual.Vignetting
                 foreach (var value in values)
                 {
                     // ReSharper disable once PossibleNullReferenceException
-                    perSecond[index] = Mathf.Abs(value.Item2 - previousValue.Item2) /
-                                       (value.Item1 - previousValue.Item1);
+                    var timeDif = value.Item1 - previousValue.Item1;
+                    perSecond[index] = timeDif == 0
+                        ? 0f
+                        : Mathf.Abs(value.Item2 - previousValue.Item2) /
+                          timeDif;
+                    previousValue = value;
                     index++;
                 }
 
-                var avg = perSecond.Average();
-                if (avg >= threshold)
-                {
-                    return .5f; //TODO: something better than a magic number
-                }
-
-                return 0f;
+                var avg = perSecond.Length == 0 ? 0f : perSecond.Average();
+                return avg < threshold
+                    ? 0f
+                    : LerpedSuggestion(avg);
             }
         }
+    }
 
-        public QueueBasedRestrictionSuggestor(float threshold, int bufferSize = 10)
+    public class QueueBasedRestrictionSuggestorVector3 : QueueBasedRestrictionSuggestor<Vector3>
+    {
+        public QueueBasedRestrictionSuggestorVector3(float threshold, float minRestriction, float maxRestriction,
+            float maxValue, int bufferSize = 10) : base(threshold, minRestriction, maxRestriction, maxValue, bufferSize)
         {
-            this.bufferSize = bufferSize;
-            this.threshold = threshold;
-            values = new Queue<Tuple<float, float>>(bufferSize);
         }
 
-        public void AddValue(float value)
+        public override float Suggestion
         {
-            if (values.Count >= bufferSize)
+            get
             {
-                values.Dequeue();
-            }
+                var perSecond = new Vector3[values.Count];
+                var index = 0;
+                var previousValue = values.FirstOrDefault();
+                foreach (var value in values)
+                {
+                    // ReSharper disable once PossibleNullReferenceException
+                    var timeDif = value.Item1 - previousValue.Item1;
+                    perSecond[index] = timeDif == 0
+                        ? Vector3.zero
+                        : Helpers.Vector3Abs(value.Item2 - previousValue.Item2) /
+                          timeDif;
+                    previousValue = value;
+                    index++;
+                }
 
-            values.Enqueue(new Tuple<float, float>(Time.time, value));
+                var avg = perSecond.Aggregate(Vector3.zero, (agg, v) => agg + v) / perSecond.Length;
+                var max = Helpers.GetMaxComponent(avg);
+                return max < threshold
+                    ? 0f
+                    : LerpedSuggestion(max);
+            }
         }
     }
 }

BIN
obj/Debug/Assembly-CSharp.csprojAssemblyReference.cache


BIN
obj/Debug/SteamVR_Windows_EditorHelper.csprojAssemblyReference.cache