diff --git a/Material.meta b/Material.meta new file mode 100644 index 0000000..a96bd51 --- /dev/null +++ b/Material.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2b82684f307a024d9f7f212473cf36d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Material/QuadMaterial.mat b/Material/QuadMaterial.mat new file mode 100644 index 0000000..3f8a43f --- /dev/null +++ b/Material/QuadMaterial.mat @@ -0,0 +1,79 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: QuadMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Material/QuadMaterial.mat.meta b/Material/QuadMaterial.mat.meta new file mode 100644 index 0000000..7c2c7f6 --- /dev/null +++ b/Material/QuadMaterial.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e4c24c9ee883e1b49a29ee7205d855b9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/DSPVEyeTracking.cs b/Scripts/DSPVEyeTracking.cs deleted file mode 100644 index 0890419..0000000 --- a/Scripts/DSPVEyeTracking.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using UnityEngine; -using ViveSR.anipal.Eye; -using EyeFramework = ViveSR.anipal.Eye.SRanipal_Eye_Framework; - - -namespace Xarphos.Scripts -{ - // [RequireComponent(typeof(DSPV_SimulationController))] - public class DSPVEyeTracking : MonoBehaviour - { - - public enum EyeTrackingConditions - { - GazeIgnored = 0, - SimulationFixedToGaze = 1, - GazeAssistedSampling = 2, - } - - // Added for Eye Tracking Implementation - [SerializeField] private Camera simCam; - internal bool EyeTrackingAvailable { get; private set; } - - private void Start() - { - EyeTrackingAvailable = SRanipal_Eye_Framework.Instance.EnableEye; - } - - private void FixedUpdate() - { - EyeTrackingAvailable = CheckFrameworkStatusErrors(); - } - - internal bool EyeTrackingStep(out Vector2 eyePosition) - { - eyePosition = Vector2.zero; - if (!EyeTrackingAvailable) - { - return false; - } - VerboseData vData; - SRanipal_Eye_v2.GetVerboseData(out vData); - var gazeDir = vData.combined.eye_data.gaze_direction_normalized; - gazeDir.x *= -1; // ToDo: This should not be necessary? Why is ray mirrored? - - RaycastHit hit; - if (Physics.Raycast(simCam.transform.position, gazeDir, out hit)) - { - eyePosition = hit.textureCoord; - return true; - } - - return false; - } - - private bool CheckFrameworkStatusErrors() - { - return EyeFramework.Status == EyeFramework.FrameworkStatus.WORKING && - EyeFramework.Status != EyeFramework.FrameworkStatus.NOT_SUPPORT; - } - - private int Gcf(int a, int b) - { - while (b != 0) - { - int temp = b; - b = a % b; - a = temp; - } - return a; - } - } -} diff --git a/Scripts/EyeTracking.cs b/Scripts/EyeTracking.cs new file mode 100644 index 0000000..f01c0f9 --- /dev/null +++ b/Scripts/EyeTracking.cs @@ -0,0 +1,556 @@ +using System; +using System.Runtime.InteropServices; +using TMPro; +using Unity.VisualScripting; +using UnityEditor; +using UnityEngine; +using UnityEngine.InputSystem; +using ViveSR.anipal; +using ViveSR.anipal.Eye; +using EyeFramework = ViveSR.anipal.Eye.SRanipal_Eye_Framework; + + +namespace Xarphos.Scripts +{ + public class EyeTracking : MonoBehaviour + { + [Header("Debug Toggle")] + public bool DebugGazeRays; + public bool DebugGazeCalcs; + + private static EyeData_v2 eyeData; + public EyeParameter eye_parameter; + public GazeRayParameter gaze; + private static bool eye_callback_registered; + private static UInt64 eye_valid_L, eye_valid_R; // The bits explaining the validity of eye data. + private static float openness_L, openness_R; // The level of eye openness. + private static float pupil_diameter_L, pupil_diameter_R; // Diameter of pupil dilation. + private static Vector2 pos_sensor_L, pos_sensor_R; // Positions of pupils. + private static Vector3 gaze_origin_L, gaze_origin_R; // Position of gaze origin. + private static Vector3 gaze_direct_L, gaze_direct_R; // Direction of gaze ray. + private static float frown_L, frown_R; // The level of user's frown. + private static float squeeze_L, squeeze_R; // The level to show how the eye is closed tightly. + private static float wide_L, wide_R; // The level to show how the eye is open widely. + private static double gaze_sensitive; // The sensitive factor of gaze ray. + private static float distance_C; // Distance from the central point of right and left eyes. + private static bool distance_valid_C; // Validity of combined data of right and left eyes. + + private static int track_imp_cnt = 0; + private static TrackingImprovement[] track_imp_item; + + private static long MeasureTime, CurrentTime, MeasureEndTime; + private static float time_stamp; + private static int frame; + + private PhospheneSimulator sim; + + internal bool EyeTrackingAvailable { get; private set; } + + public enum EyeTrackingConditions { GazeIgnored = 0, SimulationFixedToGaze = 1, GazeAssistedSampling = 2 } + +#region Unity Event Functions + private void Start() + { + // SRanipal_Eye_v2.LaunchEyeCalibration(); // Perform calibration for eye tracking. + Invoke(nameof(SystemCheck), .5f); + Invoke(nameof(RegisterCallback), .5f); + + sim = GetComponent(); + } + + private void FixedUpdate() + { + if (!CheckFrameworkStatusErrors()) + { + EyeTrackingAvailable = false; + // Debug.LogWarning("Framework Responded failure to work."); + } + } + + private void Update() + { + // ToDo: Set camera to only render clip of actual screen + + // Gaze Debugging + GazeTestsUpdate(); + + FocusInfo focusInfo; + if (SRanipal_Eye_v2.Focus(GazeIndex.COMBINE, out _, out focusInfo, 0.01f, 10f, HallwayLayerMask, eyeData)) { } + else if (SRanipal_Eye_v2.Focus(GazeIndex.LEFT, out _, out focusInfo, 0.01f, 10f, HallwayLayerMask, eyeData)) {} + else if (SRanipal_Eye_v2.Focus(GazeIndex.RIGHT, out _, out focusInfo, 0.01f, 10f, HallwayLayerMask, eyeData)) {} + + Vector2 eyePos = sim.targetCamera.WorldToViewportPoint(focusInfo.point); + // ToDo: Update only when valid; Consider gaze smoothing; Play with SrAnipal GazeParameter + sim.SetEyePosition(eyePos); + } +#endregion + +#region EyeData Setup + private void SystemCheck() + { + if (EyeFramework.Status == EyeFramework.FrameworkStatus.NOT_SUPPORT) + { + EyeTrackingAvailable = false; + Debug.LogWarning("Eye Tracking Not Supported"); + return; + } + + + var eyeDataResult = SRanipal_Eye_API.GetEyeData_v2(ref eyeData); + var eyeParamResult = SRanipal_Eye_API.GetEyeParameter(ref eye_parameter); + var resultEyeInit = SRanipal_API.Initial(SRanipal_Eye_v2.ANIPAL_TYPE_EYE_V2, IntPtr.Zero); + + if ( + eyeDataResult != ViveSR.Error.WORK || + eyeParamResult != ViveSR.Error.WORK || + resultEyeInit != ViveSR.Error.WORK + ) + { + Debug.LogError("Inital Check failed.\n" + + $"[SRanipal] Eye Data Call v2 : {eyeDataResult}" + + $"[SRanipal] Eye Param Call v2: {eyeParamResult}" + + $"[SRanipal] Initial Eye v2 : {resultEyeInit}" + ); + EyeTrackingAvailable = false; + return; + } + + EyeTrackingAvailable = true; + } + + private void RegisterCallback() + { + var eyeParameter = new EyeParameter(); + SRanipal_Eye_API.GetEyeParameter(ref eyeParameter); + + if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback && !eye_callback_registered) + { + SRanipal_Eye_v2.WrapperRegisterEyeDataCallback( + Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) + ); + eye_callback_registered = true; + } + + else if (!SRanipal_Eye_Framework.Instance.EnableEyeDataCallback && eye_callback_registered) + { + SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( + Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) + ); + eye_callback_registered = false; + } + } +#endregion + +#region EyeTracking Data Collection + [MonoPInvokeCallback] + private static void EyeCallback(ref EyeData_v2 eyeDataRef) + { + var eyeParameter = new EyeParameter(); + SRanipal_Eye_API.GetEyeParameter(ref eyeParameter); + eyeData = eyeDataRef; + + var fetchResult = SRanipal_Eye_API.GetEyeData_v2(ref eyeData); + if (fetchResult != ViveSR.Error.WORK) return; + + MeasureTime = DateTime.Now.Ticks; + time_stamp = eyeData.timestamp; + frame = eyeData.frame_sequence; + eye_valid_L = eyeData.verbose_data.left.eye_data_validata_bit_mask; + eye_valid_R = eyeData.verbose_data.right.eye_data_validata_bit_mask; + openness_L = eyeData.verbose_data.left.eye_openness; + openness_R = eyeData.verbose_data.right.eye_openness; + pupil_diameter_L = eyeData.verbose_data.left.pupil_diameter_mm; + pupil_diameter_R = eyeData.verbose_data.right.pupil_diameter_mm; + pos_sensor_L = eyeData.verbose_data.left.pupil_position_in_sensor_area; + pos_sensor_R = eyeData.verbose_data.right.pupil_position_in_sensor_area; + gaze_origin_L = eyeData.verbose_data.left.gaze_origin_mm; + gaze_origin_R = eyeData.verbose_data.right.gaze_origin_mm; + gaze_direct_L = eyeData.verbose_data.left.gaze_direction_normalized; + gaze_direct_R = eyeData.verbose_data.right.gaze_direction_normalized; + gaze_sensitive = eyeParameter.gaze_ray_parameter.sensitive_factor; + frown_L = eyeData.expression_data.left.eye_frown; + frown_R = eyeData.expression_data.right.eye_frown; + squeeze_L = eyeData.expression_data.left.eye_squeeze; + squeeze_R = eyeData.expression_data.right.eye_squeeze; + wide_L = eyeData.expression_data.left.eye_wide; + wide_R = eyeData.expression_data.right.eye_wide; + distance_valid_C = eyeData.verbose_data.combined.convergence_distance_validity; + distance_C = eyeData.verbose_data.combined.convergence_distance_mm; + track_imp_cnt = eyeData.verbose_data.tracking_improvements.count; + } + + internal bool EyeTrackingStep(out Vector2 eyePosition) + { + eyePosition = Vector2.zero; + // if (!EyeTrackingAvailable) + // { + // return false; + // } + // VerboseData vData; + // SRanipal_Eye_v2.GetVerboseData(out vData); + // var gazeDir = vData.combined.eye_data.gaze_direction_normalized; + // gazeDir.x *= -1; // ToDo: This should not be necessary? Why is ray mirrored? + // + // RaycastHit hit; + // if (Physics.Raycast(simCam.transform.position, gazeDir, out hit)) + // { + // eyePosition = hit.textureCoord; + // return true; + // } + // + return false; + } + + private bool CheckFrameworkStatusErrors() + { + return EyeFramework.Status == EyeFramework.FrameworkStatus.WORKING; + } +#endregion + + private int Gcf(int a, int b) + { + while (b != 0) + { + int temp = b; + b = a % b; + a = temp; + } + return a; + } + +#region EyeData Clean Up & Necessities + void OnApplicationQuit() + { + Release(); + } + + private void OnDisable() + { + Release(); + } + + + + /// + /// Release callback thread when disabled or quit + /// + private void Release() + { + Debug.Log("Releasing..."); + if (eye_callback_registered) + { + SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( + Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) + ); + eye_callback_registered = false; + } + // Gaze Debugging + if (DebugGazeRays) GazeTestsRelease(); + Debug.Log("Releasing Done."); + } + + /// + /// Required class for IL2CPP scripting backend support + /// + internal class MonoPInvokeCallbackAttribute : Attribute { } +#endregion + + private void GazeTestsUpdate() + { + if (DebugGazeCalcs) + { + GazeIntersection(); + GazeDebugUI(); + } + + if (DebugGazeRays) + { + if (Keyboard.current[Key.F8].wasPressedThisFrame) + { + SetDebugGazeRender(!renderGazeRays); + } + + if (Keyboard.current[Key.F9].wasPressedThisFrame) + { + freezeGazeRays = !freezeGazeRays; + } + + if (renderGazeRays && !freezeGazeRays) + { + UpdateGazeRays(); + } + } + } + + private void GazeTestsRelease() + { + Debug.Log("Destroying"); + if (leftVisual != null) + { + Destroy(leftGazeLine.material); + Destroy(leftVisual); + } + if (rightVisual != null) + { + Destroy(rightGazeLine.material); + Destroy(rightVisual); + } + if (centreVisual != null) + { + Destroy(centreGazeLine.material); + Destroy(centreVisual); + } + } + +#region Debug Gaze Rendering + private static bool renderGazeRays, freezeGazeRays; + private static GameObject leftVisual, rightVisual, centreVisual; + private static LineRenderer leftGazeLine, rightGazeLine, centreGazeLine; + + private static Camera mainCam; + + private void SetDebugGazeRender(bool status) + { + // first acticvation: set up objects and references + if (status && (leftVisual == null || rightVisual == null || centreVisual == null)) + { + mainCam = Camera.main; + leftVisual = new GameObject("LeftGazeRender"); + leftVisual.transform.SetParent(transform, false); + leftVisual.transform.localPosition = Vector3.zero; + rightVisual = new GameObject("RightGazeRender"); + rightVisual.transform.SetParent(transform, false); + rightVisual.transform.localPosition = Vector3.zero; + centreVisual = new GameObject("CentreGazeRender"); + centreVisual.transform.SetParent(transform, false); + centreVisual.transform.localPosition = Vector3.zero; + leftGazeLine = leftVisual.AddComponent(); + { + leftGazeLine.material = new Material(Shader.Find("Standard")); + leftGazeLine.material.SetColor("_Color", Color.green); + // leftGazeLine.startColor = Color.green; + // leftGazeLine.endColor = Color.green; + leftGazeLine.startWidth = 0.005f; + leftGazeLine.endWidth = 0.005f; + } + rightGazeLine = rightVisual.AddComponent(); + { + rightGazeLine.material = new Material(Shader.Find("Standard")); + rightGazeLine.material.SetColor("_Color", Color.red); + rightGazeLine.startWidth = 0.005f; + rightGazeLine.endWidth = 0.005f; + } + centreGazeLine = centreVisual.AddComponent(); + { + centreGazeLine.material = new Material(Shader.Find("Standard")); + centreGazeLine.material.SetColor("_Color", Color.cyan); + centreGazeLine.startWidth = 0.005f; + centreGazeLine.endWidth = 0.005f; + } + } + + renderGazeRays = status; + leftVisual.SetActive(status); + rightVisual.SetActive(status); + centreVisual.SetActive(status); + } + + private void UpdateGazeRays() + { + Vector3 leftOrigin, rightOrigin, centreOrigin, leftDir, rightDir, centreDir; + + // update gaze data + SRanipal_Eye_v2.GetGazeRay(GazeIndex.LEFT, out leftOrigin, out leftDir, eyeData); + SRanipal_Eye_v2.GetGazeRay(GazeIndex.RIGHT, out rightOrigin, out rightDir, eyeData); + SRanipal_Eye_v2.GetGazeRay(GazeIndex.COMBINE, out centreOrigin, out centreDir, eyeData); + + // transform from local space + var t = mainCam.transform; + leftOrigin = t.TransformPoint(leftOrigin); + rightOrigin = t.TransformPoint(rightOrigin); + centreOrigin = t.TransformPoint(centreOrigin); + leftDir = t.TransformDirection(leftDir); + rightDir = t.TransformDirection(rightDir); + centreDir = t.TransformDirection(centreDir); + + bool validityLeft = + eyeData.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_ORIGIN_VALIDITY) && + eyeData.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY); + bool validityRight = + eyeData.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_ORIGIN_VALIDITY) && + eyeData.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY); + bool validityCentre = + eyeData.verbose_data.combined.eye_data.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_ORIGIN_VALIDITY) && + eyeData.verbose_data.combined.eye_data.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY); + + // update render + leftGazeLine.SetPositions( + validityLeft ? new[] { leftOrigin, leftOrigin + leftDir * 20 } : new [] { Vector3.zero, Vector3.zero }); + rightGazeLine.SetPositions( + validityRight ? new [] { rightOrigin, rightOrigin + rightDir * 20 } : new [] { Vector3.zero, Vector3.zero }); + centreGazeLine.SetPositions( + validityCentre ? new[] { centreOrigin, centreOrigin + centreDir * 20 } : new [] { Vector3.zero, Vector3.zero }); + } +#endregion + +#region eye position tests + +[Header("Debug Stuff")] public TMP_Text MinGazeDistText; +public TMP_Text LeftOriginText, RightOriginText, CombOriginText, focusCastRadiusText, GazePointText; +[SerializeField] private LayerMask HallwayLayerMask; + +private Vector3 left2Frustrum, right2Frustrum, comb2Frustrum, combConverged2Screen2Frustrum; +private GameObject FocusSphere = null, ConvergenceSphere = null, ConvergenceLeftPointSphere = null, ConvergenceRightPointSphere = null; +private float focusCastRadius = .01f; + void GazeIntersection() + { + var cam = sim.targetCamera; + var bottomLeft = cam.transform.InverseTransformPoint(cam.ViewportToWorldPoint(new Vector3(0, 0, cam.nearClipPlane))); + var upperLeft = cam.transform.InverseTransformPoint(cam.ViewportToWorldPoint(new Vector3(0, 1, cam.nearClipPlane))); + var upperRight = cam.transform.InverseTransformPoint(cam.ViewportToWorldPoint(new Vector3(1, 1, cam.nearClipPlane))); + Plane clippingPlane = new Plane(upperRight, upperLeft, bottomLeft); + + var eyeOriginLeft = eyeData.verbose_data.left.gaze_origin_mm * .001f; // converted to "m", which is the space unity should be in + var eyeDirLeft = eyeData.verbose_data.left.gaze_direction_normalized; + var eyeOriginRight = eyeData.verbose_data.right.gaze_origin_mm * .001f; + var eyeDirRight = eyeData.verbose_data.right.gaze_direction_normalized; + var eyeOriginCombined = eyeData.verbose_data.combined.eye_data.gaze_origin_mm * .001f; + var eyeDirCombined = eyeData.verbose_data.combined.eye_data.gaze_direction_normalized; + + var gazeRayLeft = new Ray(eyeOriginLeft, eyeDirLeft); + var gazeRayRight = new Ray(eyeOriginRight, eyeDirRight); + var gazeRayCombined = new Ray(eyeOriginCombined, eyeDirCombined); + + clippingPlane.Raycast(gazeRayLeft, out var distLeft); + clippingPlane.Raycast(gazeRayRight, out var distRight); + clippingPlane.Raycast(gazeRayCombined, out var distComb); + + var intersectionLeft = gazeRayLeft.GetPoint(distLeft); + var intersectionRight = gazeRayRight.GetPoint(distRight); + var intersectionCombined = gazeRayCombined.GetPoint(distComb); + + left2Frustrum = cam.transform.TransformPoint(intersectionLeft); + right2Frustrum = cam.transform.TransformPoint(intersectionRight); + comb2Frustrum = cam.transform.TransformPoint(intersectionCombined); + + SRanipal_Eye_v2.Focus(GazeIndex.COMBINE, out _, out var focusInfo, focusCastRadius, 20f, HallwayLayerMask, eyeData); + var frustrumPos = cam.WorldToViewportPoint(focusInfo.point); + frustrumPos.z = cam.nearClipPlane; + combConverged2Screen2Frustrum = cam.ViewportToWorldPoint(frustrumPos); + + if (FocusSphere is null) + { + FocusSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + { + FocusSphere.name = "FocusSphere"; + FocusSphere.transform.parent = this.transform; + FocusSphere.transform.localScale = Vector3.one * .05f; + FocusSphere.GetComponent().material.color = Color.yellow; + } + } + + FocusSphere.transform.position = focusInfo.point; + } + + private void OnDrawGizmosSelected() + { + Gizmos.color = Color.green; + Gizmos.DrawSphere(left2Frustrum, .01f); + Gizmos.color = Color.red; + Gizmos.DrawSphere(right2Frustrum, .01f); + Gizmos.color = Color.cyan; + Gizmos.DrawSphere(comb2Frustrum, .01f); + Gizmos.color = Color.yellow; + Gizmos.DrawSphere(combConverged2Screen2Frustrum, .01f); + } + + float MinDistanceGazeVectors() + { + var cross = Vector3.Cross(eyeData.verbose_data.left.gaze_direction_normalized, + eyeData.verbose_data.right.gaze_direction_normalized); + var d = Vector3.Scale( + eyeData.verbose_data.left.gaze_origin_mm * 0.001f - eyeData.verbose_data.right.gaze_origin_mm * 0.001f, + cross.normalized + ).sqrMagnitude; + + // Point of closest distance + float tL, tR, tP; + var vR = gaze_direct_R; + var vL = gaze_direct_L; + var vP = cross; + var RHS = gaze_origin_R - gaze_origin_L; + tP = (RHS[0] - RHS[2] * vL[0] / vL[2]) / + ( vP[0] - ( vL[0]*vP[2]/vL[2] ) + + ( (vL[0]*vR[2] - vR[0]*vL[2]) / + (vR[2]*vL[1] - vR[1]*vL[2])) * (vL[1]*vP[2]/vL[2]) + ); + tR = (RHS[1] - vL[1]/vL[2] * (RHS[2] - tP * vP[2])) / ((vR[2] * vL[1]) / vL[2] - vR[1]); + tL = RHS[2] + tR * vR[2] - tP * vP[2]; + + if (ConvergenceSphere is null) + { + ConvergenceSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + { + ConvergenceSphere.name = "ConvergenceSphere"; + ConvergenceSphere.transform.parent = transform; + ConvergenceSphere.transform.localScale = Vector3.one * .05f; + ConvergenceSphere.GetComponent().material.color = new Color(.8f, .5f, .2f); + } + ConvergenceLeftPointSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + { + ConvergenceLeftPointSphere.name = "ConvergenceLeftPointSphere"; + ConvergenceLeftPointSphere.transform.parent = transform; + ConvergenceLeftPointSphere.transform.localScale = Vector3.one * .01f; + ConvergenceLeftPointSphere.GetComponent().material.color = Color.green; + } + ConvergenceRightPointSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); + { + ConvergenceRightPointSphere.name = "ConvergenceRightPointSphere"; + ConvergenceRightPointSphere.transform.parent = transform; + ConvergenceRightPointSphere.transform.localScale = Vector3.one * .01f; + ConvergenceRightPointSphere.GetComponent().material.color = Color.red; + } + } + + ConvergenceLeftPointSphere.transform.position = gaze_origin_L + tL * vL; + ConvergenceRightPointSphere.transform.position = gaze_origin_R + tR * vR; + ConvergenceSphere.transform.position = gaze_origin_R + tR * vR + tP / 2f * vP; + + return Mathf.Sqrt(d); + } + + void GazeDebugUI() + { + if (Keyboard.current.upArrowKey.isPressed) + { + focusCastRadius += .01f; + } else if (Keyboard.current.downArrowKey.isPressed) + { + focusCastRadius += -0.01f; + } + + var gaze_origin_C = eyeData.verbose_data.combined.eye_data.gaze_origin_mm; + MinGazeDistText.text = $"minD_LR: {MinDistanceGazeVectors() * 1000f:F}mm"; + LeftOriginText.text = $"Left : {gaze_origin_L.x:F1},{gaze_origin_L.y:F1},{gaze_origin_L.z:F1}"; + RightOriginText.text = $"Right: {gaze_origin_R.x:F1},{gaze_origin_R.y:F1},{gaze_origin_R.z:F1}"; + CombOriginText.text = $"Comb : {gaze_origin_C.x:F1},{gaze_origin_C.y:F1},{gaze_origin_C.z:F1}"; + focusCastRadiusText.text = $"FocusRayR: {focusCastRadius:F}mm"; + + + + var tmp1 = gaze_origin_L - gaze_origin_R + Vector3.Cross(gaze_direct_L.normalized, gaze_direct_R.normalized); + var tmp2 = gaze_direct_R - gaze_direct_L; + var t = tmp1.x / tmp2.x; + var PL = gaze_origin_L + t * gaze_direct_L; + var PR = gaze_origin_R + t * gaze_direct_R; + var posL = ConvergenceLeftPointSphere.transform.position; + var posR = ConvergenceRightPointSphere.transform.position; + var posC = ConvergenceSphere.transform.position; + GazePointText.text = $"L:{posL.x:F1},{posL.y:F1},{posL.z:F1}\n" + + $"R:{posR.x:F1},{posR.y:F1},{posR.z:F1}\n" + + $"C:{posC.x:F1},{posC.y:F1},{posC.z:F1}"; + } + + #endregion + } +} diff --git a/Scripts/DSPVEyeTracking.cs.meta b/Scripts/EyeTracking.cs.meta similarity index 100% rename from Scripts/DSPVEyeTracking.cs.meta rename to Scripts/EyeTracking.cs.meta diff --git a/Scripts/PhospheneSimulator.cs b/Scripts/PhospheneSimulator.cs index c886495..1995648 100644 --- a/Scripts/PhospheneSimulator.cs +++ b/Scripts/PhospheneSimulator.cs @@ -1,236 +1,233 @@ using UnityEngine; -using Rect = UnityEngine.Rect; -using OpenCVForUnity; -using System; -using System.IO; -using System.Collections.Generic; -using OpenCVForUnity.CoreModule; -using OpenCVForUnity.ImgprocModule; -using OpenCVForUnity.UnityUtils; -using static ImageSynthesis; using UnityEngine.InputSystem; -using System.Collections; namespace Xarphos.Scripts { - // [RequireComponent(typeof(Renderer))] - public class PhospheneSimulator : MonoBehaviour { + public Camera targetCamera; + public bool manualEyePos; // Image processing settings - float phospheneFiltering = 0.0f; - float edgeDetection = 0.0f; + private float _phospheneFiltering; + private float _edgeDetection; // EyeTracking - protected Vector2 eyePosition; + protected Vector2 EyePosition; + protected int GazeLocking; // used as boolean (sent to shader) + protected bool CamLocking; // Image processing settings - [SerializeField] protected DSPVEyeTracking.EyeTrackingConditions eyeTrackingCondition; + [SerializeField] protected EyeTracking.EyeTrackingConditions eyeTrackingCondition; [SerializeField] protected SurfaceReplacement.ReplacementModes surfaceReplacementMode; + private readonly int _nSurfaceModes = System.Enum.GetValues(typeof(SurfaceReplacement.ReplacementModes)).Length; + private readonly int _nEyeTrackingModes = System.Enum.GetValues(typeof(EyeTracking.EyeTrackingConditions)).Length; [SerializeField] protected Vector2Int resolution; [SerializeField] protected Vector2 FOV; // Render textures - protected RenderTexture inputRT; - protected RenderTexture activationMask; - protected RenderTexture phospheneRT; + protected RenderTexture ActivationMask; // For reading phosphene configuration from JSON - [SerializeField] string phospheneConfigFile; - private Phosphene[] phosphenes; - int nPhosphenes; - ComputeBuffer phospheneBuffer; + [SerializeField] private string phospheneConfigFile; + private Phosphene[] _phosphenes; + private int _nPhosphenes; + private ComputeBuffer _phospheneBuffer; // Shaders and materials - protected Material imageProcessingMaterial; - protected Material phospheneMaterial; + protected Material ImageProcessingMaterial; + protected Material PhospheneMaterial; [SerializeField] protected Shader phospheneShader; [SerializeField] protected Shader imageProcessingShader; - [SerializeField] protected ComputeShader temporalDynamicsCS; + [SerializeField] protected ComputeShader temporalDynamicsCs; // stimulation parameters - [SerializeField] float input_effect = 0.7f;// The factor by which stimulation accumulates to phosphene activation - [SerializeField] float intensity_decay = 0.8f; // The factor by which previous activation still influences current activation - [SerializeField] float trace_increase = 0.1f; // The habituation strength: the factor by which stimulation leads to buildup of memory trace - [SerializeField] float trace_decay = 0.9f; // The factor by which the stimulation memory trace decreases + [SerializeField] + private float inputEffect = 0.7f;// The factor by which stimulation accumulates to phosphene activation + [SerializeField] + private float intensityDecay = 0.8f; // The factor by which previous activation still influences current activation + [SerializeField] + private float traceIncrease = 0.1f; // The habituation strength: the factor by which stimulation leads to buildup of memory trace + [SerializeField] + private float traceDecay = 0.9f; // The factor by which the stimulation memory trace decreases + + #region Shader Properties Name-To-Int + private static readonly int PhosMatMask = Shader.PropertyToID("_ActivationMask"); + private static readonly int PhosMatPhosphenes = Shader.PropertyToID("phosphenes"); + private static readonly int PhosMatNPhosphenes = Shader.PropertyToID("_nPhosphenes"); + private static readonly int PhosMatFilter = Shader.PropertyToID("_PhospheneFilter"); + private static readonly int PhosMatPosition = Shader.PropertyToID("_EyePosition"); + private static readonly int PhosMatGazeLocked = Shader.PropertyToID("_GazeLocked"); + + private static readonly int TempDynResolution = Shader.PropertyToID("resolution"); + private static readonly int TempDynMask = Shader.PropertyToID("ActivationMask"); + private static readonly int TempDynInputEffect = Shader.PropertyToID("input_effect"); + private static readonly int TempDynIntensityDecay = Shader.PropertyToID("intensity_decay"); + private static readonly int TempDynTraceIncrease = Shader.PropertyToID("trace_increase"); + private static readonly int TempDynTraceDecay = Shader.PropertyToID("trace_decay"); + private static readonly int TempDynPhosphenes = Shader.PropertyToID("phosphenes"); + private static readonly int TempDynGazeAssistedSampling = Shader.PropertyToID("gazeAssistedSampling"); + + private static readonly int ImgProcMode = Shader.PropertyToID("_Mode"); + private static readonly int ImgMatMainTex = Shader.PropertyToID("_MainTex"); + + #endregion protected void Awake() { - // Initialize the array of phosphenes - phosphenes = PhospheneConfig.InitPhosphenesFromJSON(phospheneConfigFile, FOV); - nPhosphenes = phosphenes.Length; + targetCamera ??= GetComponent(); - print(phosphenes[0]); - phospheneBuffer = new ComputeBuffer(nPhosphenes, sizeof(float)*5); - phospheneBuffer.SetData(phosphenes); + // Initialize the array of phosphenes + _phosphenes = PhospheneConfig.InitPhosphenesFromJSON(phospheneConfigFile, FOV); + _nPhosphenes = _phosphenes.Length; + _phospheneBuffer = new ComputeBuffer(_nPhosphenes, sizeof(float)*5); + _phospheneBuffer.SetData(_phosphenes); // Initialize materials with shaders - phospheneMaterial = new Material(phospheneShader); - imageProcessingMaterial = new Material(imageProcessingShader);// TODO + PhospheneMaterial = new Material(phospheneShader); + ImageProcessingMaterial = new Material(imageProcessingShader);// TODO // Initialize the render textures - inputRT = new RenderTexture(resolution.x, resolution.y, 24); - activationMask = new RenderTexture(resolution.x, resolution.y, 24); - activationMask.enableRandomWrite = true; - activationMask.Create(); - phospheneRT = new RenderTexture(resolution.x, resolution.y, 24); + ActivationMask = new RenderTexture(resolution.x, resolution.y, 24); + ActivationMask.enableRandomWrite = true; + ActivationMask.Create(); + ImageProcessingMaterial.SetTexture(ImgMatMainTex, ActivationMask); // Set the shaders with the shared render textures - imageProcessingMaterial.SetTexture("_MainTex", inputRT); - temporalDynamicsCS.SetInts("resolution", new int[]{resolution.x, resolution.y}); - temporalDynamicsCS.SetTexture(0,"ActivationMask", activationMask); - phospheneMaterial.SetTexture("_ActivationMask", activationMask); + temporalDynamicsCs.SetInts(TempDynResolution, new int[] {resolution.x, resolution.y}); + temporalDynamicsCs.SetTexture(0,TempDynMask, ActivationMask); + PhospheneMaterial.SetTexture(PhosMatMask, ActivationMask); // Set the compute shader with the temporal dynamics variables - temporalDynamicsCS.SetFloat("input_effect", input_effect); - temporalDynamicsCS.SetFloat("intensity_decay", intensity_decay); - temporalDynamicsCS.SetFloat("trace_increase", trace_increase); - temporalDynamicsCS.SetFloat("trace_decay", trace_decay); + temporalDynamicsCs.SetFloat(TempDynInputEffect, inputEffect); + temporalDynamicsCs.SetFloat(TempDynIntensityDecay, intensityDecay); + temporalDynamicsCs.SetFloat(TempDynTraceIncrease, traceIncrease); + temporalDynamicsCs.SetFloat(TempDynTraceDecay, traceDecay); // Set the shader properties with the shared phosphene buffer - phospheneMaterial.SetBuffer("phosphenes", phospheneBuffer); - phospheneMaterial.SetInt("_nPhosphenes", nPhosphenes); - phospheneMaterial.SetFloat("_PhospheneFilter", phospheneFiltering); - temporalDynamicsCS.SetBuffer(0,"phosphenes", phospheneBuffer); - + PhospheneMaterial.SetBuffer(PhosMatPhosphenes, _phospheneBuffer); + PhospheneMaterial.SetInt(PhosMatNPhosphenes, _nPhosphenes); + PhospheneMaterial.SetFloat(PhosMatFilter, _phospheneFiltering); + temporalDynamicsCs.SetBuffer(0,TempDynPhosphenes, _phospheneBuffer); // Set the default EyeTrackingCondition (Ignore Gaze) - phospheneMaterial.SetInt("_GazeLocked", 0); - temporalDynamicsCS.SetInt("gazeAssistedSampling", 0); + PhospheneMaterial.SetInt(PhosMatGazeLocked, 0); + temporalDynamicsCs.SetInt(TempDynGazeAssistedSampling, 0); + } + private void OnRenderImage(RenderTexture src, RenderTexture target) + { + // Compute Phosphene Activity + if ((int)_phospheneFiltering == 1) + { + Graphics.Blit(src, ActivationMask, ImageProcessingMaterial); // using imageProcessingShader + temporalDynamicsCs.Dispatch(0, _phosphenes.Length / 10, 1, 1); + // Simulate the phosphenes (based on the shared phosphene buffer) + Graphics.Blit(null, target, PhospheneMaterial); + } + else + { + Graphics.Blit(src, target, ImageProcessingMaterial); + } } - void computePhospheneActivity(){ - // Perform image processing and compute the phosphene activity - Graphics.Blit(inputRT, activationMask, imageProcessingMaterial); // using imageProcessingshader - temporalDynamicsCS.Dispatch(0,phosphenes.Length/10,1,1); + private void OnDisable(){ + _phospheneBuffer.Release(); } - void OnPreRender() { - // Render to the input render texture - Camera.main.targetTexture = inputRT; + public void NextSurfaceReplacementMode(InputAction.CallbackContext ctx) => NextSurfaceReplacementMode(); + + private void NextSurfaceReplacementMode(){ + surfaceReplacementMode = (SurfaceReplacement.ReplacementModes)((int)(surfaceReplacementMode + 1) % _nSurfaceModes); + // Replace surfaces with the surface replacement shader + SurfaceReplacement.ActivateReplacementShader(targetCamera, surfaceReplacementMode); } + public void NextEyeTrackingCondition(InputAction.CallbackContext ctx) => NextEyeTrackingCondition(); - IEnumerator blitToScreen() + private void NextEyeTrackingCondition() { - // Wait until all reder textures are rendered - yield return new WaitForEndOfFrame(); + eyeTrackingCondition = (EyeTracking.EyeTrackingConditions)((int)(eyeTrackingCondition + 1) % _nEyeTrackingModes); - // Target tex has to be (temporarilty) set to null - Camera.main.targetTexture = null; + switch (eyeTrackingCondition) + { + // reset and don't use gaze info + case EyeTracking.EyeTrackingConditions.GazeIgnored: + PhospheneMaterial.SetInt(PhosMatGazeLocked, 0); + temporalDynamicsCs.SetInt(TempDynGazeAssistedSampling, 0); + break; + // add lock to gaze + case EyeTracking.EyeTrackingConditions.SimulationFixedToGaze: + PhospheneMaterial.SetInt(PhosMatGazeLocked, 1); + temporalDynamicsCs.SetInt(TempDynGazeAssistedSampling, 0); + break; + // add gaze assisted sampling on top + case EyeTracking.EyeTrackingConditions.GazeAssistedSampling: + PhospheneMaterial.SetInt(PhosMatGazeLocked, 1); + temporalDynamicsCs.SetInt(TempDynGazeAssistedSampling, 1); + break; + } + } - // Simulate the phosphenes (based on the shared phosphene buffer) - Graphics.Blit(null as RenderTexture, phospheneRT, phospheneMaterial); + public void TogglePhospheneSim(InputAction.CallbackContext ctx) => TogglePhospheneSim(); - // Blit to the screen - Graphics.Blit(phospheneRT, null as RenderTexture); - yield return null; + public void TogglePhospheneSim() + { + _phospheneFiltering = 1-_phospheneFiltering; + PhospheneMaterial.SetFloat(PhosMatFilter, _phospheneFiltering); } - void OnDisable(){ - phospheneBuffer.Release(); - } + public void ToggleEdgeDetection(InputAction.CallbackContext ctx) => ToggleEdgeDetection(); - void nextSurfaceReplacementMode(){ - var nModes = System.Enum.GetValues(typeof(SurfaceReplacement.ReplacementModes)).Length; - surfaceReplacementMode += 1; + private void ToggleEdgeDetection() + { + _edgeDetection = 1-_edgeDetection; + ImageProcessingMaterial.SetFloat(ImgProcMode, _edgeDetection); + } + + public void ToggleCamLocking(InputAction.CallbackContext ctx) => ToggleCamLocking(); - if((int)surfaceReplacementMode < nModes){ - // Replace surfaces with the surface replacement shader - SurfaceReplacement.ActivateReplacementShader(surfaceReplacementMode); - } - else{ - // If cycled through all modes -> set back to first element - surfaceReplacementMode = 0; - SurfaceReplacement.DeactivateReplacementShader(); // (first mode is no surface replacement) - } + public void ToggleCamLocking() + { + CamLocking = !CamLocking; } + + public void ToggleGazeLocking(InputAction.CallbackContext ctx) => ToggleGazeLocking(); - void nextEyeTrackingCondition(){ - var nModes = System.Enum.GetValues(typeof(DSPVEyeTracking.EyeTrackingConditions)).Length; - eyeTrackingCondition += 1; - if ((int)eyeTrackingCondition >= nModes) - { - //cycled through all modes -> set back to first element - // GazeIgnored - eyeTrackingCondition = 0; - phospheneMaterial.SetInt("_GazeLocked", 0); - temporalDynamicsCS.SetInt("gazeAssistedSampling", 0); - } - else if ((int)eyeTrackingCondition == 1) - { - // SimulationFixedToGaze - phospheneMaterial.SetInt("_GazeLocked", 1); - temporalDynamicsCS.SetInt("gazeAssistedSampling", 0); - } - else if ((int)eyeTrackingCondition == 2) - { - // GazeAssistedSampling - phospheneMaterial.SetInt("_GazeLocked", 1); - temporalDynamicsCS.SetInt("gazeAssistedSampling", 1); - } + public void ToggleGazeLocking() + { + GazeLocking = 1-GazeLocking; + PhospheneMaterial.SetInt(PhosMatGazeLocked, GazeLocking); } + public void SetEyePosition(Vector2 pos) + { + EyePosition = pos; + PhospheneMaterial.SetVector(PhosMatPosition, EyePosition); + } protected void Update() { - computePhospheneActivity(); - StartCoroutine(blitToScreen()); - - - if (Keyboard.current[Key.U].isPressed || Keyboard.current[Key.J].isPressed) - { - if (Keyboard.current[Key.U].isPressed) {eyePosition.y = 0.8f;} - if (Keyboard.current[Key.J].isPressed) {eyePosition.y = 0.2f;} - } - else - { - eyePosition.y = 0.5f; - } - - if (Keyboard.current[Key.H].isPressed || Keyboard.current[Key.K].isPressed) - { - if (Keyboard.current[Key.H].isPressed) {eyePosition.x = 0.2f;} - if (Keyboard.current[Key.K].isPressed) {eyePosition.x = 0.8f;} - } - else - { - eyePosition.x = 0.5f; - } - - - if (Keyboard.current[Key.C].isPressed) - { - nextEyeTrackingCondition(); - print("Condition: " + eyeTrackingCondition); - } - - if (Keyboard.current[Key.T].isPressed) - { - nextSurfaceReplacementMode(); - print("Surface replacement mode: " + surfaceReplacementMode); - } - - if (Keyboard.current[Key.E].isPressed) - { - edgeDetection = 1-edgeDetection; - imageProcessingMaterial.SetFloat("_Mode", edgeDetection); - print("Post processing: " + ((edgeDetection==1)? "Sobel edge-detection": "None")); - } - - if (Keyboard.current[Key.P].isPressed) - { - phospheneFiltering = 1-phospheneFiltering; - phospheneMaterial.SetFloat("_PhospheneFilter", phospheneFiltering); - print("Phosphene filter: " + ((phospheneFiltering==1)? "Yes" : "No") ); - } - - phospheneMaterial.SetVector("_EyePosition", eyePosition); - temporalDynamicsCS.SetVector("_EyePosition", eyePosition); - } + if (manualEyePos) + { + var eyePos = Vector2.zero; + if (Keyboard.current[Key.J].isPressed) eyePos.y = .2f; + else if (Keyboard.current[Key.U].isPressed) eyePos.y = .8f; + else eyePos.y = .5f; + + if (Keyboard.current[Key.K].isPressed) eyePos.x = .8f; + else if (Keyboard.current[Key.H].isPressed) eyePos.x = .2f; + else eyePos.x = .5f; + + SetEyePosition(eyePos); + } + if (Keyboard.current[Key.C].isPressed) + { + NextEyeTrackingCondition(); + print("Condition: " + eyeTrackingCondition); + } + } } } diff --git a/Scripts/SurfaceReplacement.cs b/Scripts/SurfaceReplacement.cs index e23facd..20b5cb1 100644 --- a/Scripts/SurfaceReplacement.cs +++ b/Scripts/SurfaceReplacement.cs @@ -18,9 +18,15 @@ public enum ReplacementModes { Normals = 5 } - public static void ActivateReplacementShader(ReplacementModes replacementMode){ + public static void ActivateReplacementShader(Camera target, ReplacementModes replacementMode){ + if (replacementMode == ReplacementModes.None) + { + DeactivateReplacementShader(target); + return; + } + // For rendering the object ID labels (instance segmentation) - var renderers = UnityEngine.Object.FindObjectsOfType(); + var renderers = FindObjectsOfType(); var mpb = new MaterialPropertyBlock(); foreach (var r in renderers) { @@ -30,11 +36,11 @@ public static void ActivateReplacementShader(ReplacementModes replacementMode){ mpb.SetInt("_OutputMode",(int)replacementMode); } - Camera.main.SetReplacementShader(replacementShader, ""); + target.SetReplacementShader(replacementShader, ""); } - public static void DeactivateReplacementShader(){ - Camera.main.ResetReplacementShader(); + public static void DeactivateReplacementShader(Camera target){ + target.ResetReplacementShader(); } public static byte ReverseBits(byte value) diff --git a/Shader/DSPV_PhospheneShader.shader b/Shader/DSPV_PhospheneShader.shader index 461f5f8..480e267 100644 --- a/Shader/DSPV_PhospheneShader.shader +++ b/Shader/DSPV_PhospheneShader.shader @@ -14,6 +14,8 @@ SubShader { + Tags { "Queue" = "Transparent" } + Lighting Off Blend One Zero diff --git a/Shader/DSPV_PhospheneShader_orig.shader b/Shader/DSPV_PhospheneShader_orig.shader deleted file mode 100644 index c5b1656..0000000 --- a/Shader/DSPV_PhospheneShader_orig.shader +++ /dev/null @@ -1,94 +0,0 @@ -Shader "Custom/DSPV_PhosShader" -{ - Properties - { - // _PhosheneMapping("PhospheneMapping", 2D) = "black" { } - _ActivationMask ("ActivationMask", 2D) = "black" { } - _SizeCoefficient ("SizeCoefficient", Range(0.001, 2)) = 0.03 - _Brightness ("Brightness", Range(0, 2)) = 0.005 - _Dropout("Dropout", Range(0.0,0.5)) = 0 - _PhospheneFilter("PhospheneFilter", Float) = 1 - _EyePosition("EyePosition", Vector) = (0., 0., 0., 0.) - _GazeLocked("GazeLocked", Int) = 0 - } - - SubShader - { - Lighting Off - Blend One Zero - - Pass - { - CGPROGRAM - #include "UnityCustomRenderTexture.cginc" - #include "DSPV_phosphene_vision.cginc" - - - #pragma vertex vertex_program - #pragma fragment frag - #pragma target 3.0 - - struct AppData - { - float2 uv: TEXCOORD0; - float4 vertex: POSITION; - }; - - struct VertexData - { - float2 uv: TEXCOORD0; - float4 vertex: SV_POSITION; - }; - - // Toggle phosphene filtering - float _PhospheneFilter; - - // // Mapping and initial size of phosphenes - // sampler2D _PhospheneMapping; - // float4 _PhospheneMapping_ST; - // float4 _PhospheneMapping_TexelSize; - - // Texture that determines where phosphenes should be activated - sampler2D _ActivationMask; - float4 _ActivationMask_ST; - float4 _ActivationMask_TexelSize; - - // Float array instead: - float activation[1000]; - - // Other parameters - float _SizeCoefficient; - float _Brightness; - float _Dropout; - - // EyePosition - float4 _EyePosition; - int _GazeLocked; - - int _nPhosphenes; - float4 _pSpecs[1000]; - - - VertexData vertex_program(AppData inputs) - { - VertexData outputs; - outputs.uv = TRANSFORM_TEX(inputs.uv, _ActivationMask); - outputs.vertex = UnityObjectToClipPos(inputs.vertex); - return outputs; - } - - float4 frag(VertexData inputs) : SV_Target - { - - if (_PhospheneFilter==1){ - // return DSPV_phospheneSimulation(_GazeLocked, _EyePosition.rg, _pSpecs, activation, _PhospheneMapping_TexelSize.z, _PhospheneMapping, _SizeCoefficient, _Brightness, _Dropout, inputs.uv); - return DSPV_phospheneSimulation(_GazeLocked, _EyePosition.rg, _pSpecs, activation, _nPhosphenes, _SizeCoefficient, _Brightness, _Dropout, inputs.uv); - } - else { - return tex2D(_ActivationMask, inputs.uv); - } - } - ENDCG - } - } -} diff --git a/Shader/DSPV_PhospheneShader_orig.shader.meta b/Shader/DSPV_PhospheneShader_orig.shader.meta deleted file mode 100644 index 43bcdf9..0000000 --- a/Shader/DSPV_PhospheneShader_orig.shader.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: 35dd9856dc62cbc45b4513733b0153d8 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - preprocessorOverride: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Shader/DSPV_phosphene_vision.cginc b/Shader/DSPV_phosphene_vision.cginc index 041691d..5dd4176 100644 --- a/Shader/DSPV_phosphene_vision.cginc +++ b/Shader/DSPV_phosphene_vision.cginc @@ -28,13 +28,21 @@ } fixed4 DSPV_gaussian(float r, float sigma) { - float c = 1 / (sigma * 3.5449077); + float c = 1 / (sigma * 3.4954077); return c * exp(-(r * r) / (2 * sigma * sigma)); } - float4 DSPV_phospheneSimulation(StructuredBuffer phospheneBuffer, int gazeLocked, float2 eyePosition, float nPhosphenes, float sizeCoefficient, float brightness, float dropout, float2 pixelPosition) { - + float4 DSPV_phospheneSimulation( + StructuredBuffer phospheneBuffer, + int gazeLocked, + float2 eyePosition, + float nPhosphenes, + float sizeCoefficient, + float brightness, + float dropout, + float2 pixelPosition + ) { // Output luminance for current pixel fixed4 pixelLuminance = fixed4(0,0,0,0); diff --git a/Shader/SurfaceReplacement.shader b/Shader/SurfaceReplacement.shader index 8b4188b..b1b76a2 100644 --- a/Shader/SurfaceReplacement.shader +++ b/Shader/SurfaceReplacement.shader @@ -14,6 +14,7 @@ Properties { SubShader { CGINCLUDE +#include fixed4 _ObjectColor; fixed4 _CategoryColor; int _OutputMode; diff --git a/Xarphos-Basement.cs b/Xarphos-Basement.cs new file mode 100644 index 0000000..36354fc --- /dev/null +++ b/Xarphos-Basement.cs @@ -0,0 +1,666 @@ +//------------------------------------------------------------------------------ +// +// This code was auto-generated by com.unity.inputsystem:InputActionCodeGenerator +// version 1.3.0 +// from Assets/Xarphos/SharedWork/Xarphos-Basement.inputactions +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.Utilities; + +public partial class @XarphosBasement : IInputActionCollection2, IDisposable +{ + public InputActionAsset asset { get; } + public @XarphosBasement() + { + asset = InputActionAsset.FromJson(@"{ + ""name"": ""Xarphos-Basement"", + ""maps"": [ + { + ""name"": ""Experiment"", + ""id"": ""0c1a547e-22aa-4aae-8248-84c703b22548"", + ""actions"": [ + { + ""name"": ""Move"", + ""type"": ""Value"", + ""id"": ""34bd96bc-3257-4350-9dbd-20a6578f8d03"", + ""expectedControlType"": ""Vector2"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": true + }, + { + ""name"": ""Look"", + ""type"": ""Value"", + ""id"": ""f6b2fbf2-2525-497f-8b48-480edbaae60a"", + ""expectedControlType"": ""Vector2"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": true + }, + { + ""name"": ""TogglePhospheneSim"", + ""type"": ""Button"", + ""id"": ""3fe95d10-e39d-4cc8-87f5-5a1b2a7a1609"", + ""expectedControlType"": ""Button"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + }, + { + ""name"": ""ToggleEdgeDetection"", + ""type"": ""Button"", + ""id"": ""3e196229-2795-46f2-bae8-3f888893222d"", + ""expectedControlType"": ""Button"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + }, + { + ""name"": ""IterateSurfaceReplacement"", + ""type"": ""Button"", + ""id"": ""e0959e22-032b-4278-9985-09bbe7bf988b"", + ""expectedControlType"": ""Button"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + }, + { + ""name"": ""ToggleEyeTrackingMode"", + ""type"": ""Button"", + ""id"": ""37a70d47-4e8b-4905-a375-e611ffd188ef"", + ""expectedControlType"": ""Button"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + }, + { + ""name"": ""ToggleGazeLocking"", + ""type"": ""Button"", + ""id"": ""35675ead-d89e-41d8-905e-a26a620f4a17"", + ""expectedControlType"": ""Button"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + }, + { + ""name"": ""ToggleCamLocking"", + ""type"": ""Button"", + ""id"": ""effd86eb-132c-4dc0-8579-f9f87766e61c"", + ""expectedControlType"": ""Button"", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + } + ], + ""bindings"": [ + { + ""name"": """", + ""id"": ""978bfe49-cc26-4a3d-ab7b-7d7a29327403"", + ""path"": ""/leftStick"", + ""interactions"": """", + ""processors"": """", + ""groups"": "";Gamepad"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""1635d3fe-58b6-4ba9-a4e2-f4b964f6b5c8"", + ""path"": ""/joystick"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""XR"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": ""WASD"", + ""id"": ""00ca640b-d935-4593-8157-c05846ea39b3"", + ""path"": ""Dpad"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""Move"", + ""isComposite"": true, + ""isPartOfComposite"": false + }, + { + ""name"": ""up"", + ""id"": ""8180e8bd-4097-4f4e-ab88-4523101a6ce9"", + ""path"": ""/d"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""Keyboard&Mouse"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": true + }, + { + ""name"": ""down"", + ""id"": ""1c5327b5-f71c-4f60-99c7-4e737386f1d1"", + ""path"": ""/s"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""Keyboard&Mouse"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": true + }, + { + ""name"": ""left"", + ""id"": ""2e46982e-44cc-431b-9f0b-c11910bf467a"", + ""path"": ""/a"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""Keyboard&Mouse"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": true + }, + { + ""name"": ""right"", + ""id"": ""77bff152-3580-4b21-b6de-dcd0c7e41164"", + ""path"": ""/h"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""Keyboard&Mouse"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": true + }, + { + ""name"": """", + ""id"": ""3ea4d645-4504-4529-b061-ab81934c3752"", + ""path"": ""/stick"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""Joystick"", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""8ca86599-2946-4e18-9fa8-7bd3eebc7691"", + ""path"": ""/trackpad"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""e891f054-6cdc-4392-88ec-222828cb5834"", + ""path"": ""/touchpad"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""d556355b-2f1d-4663-80a3-eaff580a98ee"", + ""path"": ""/thumbstick"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""Move"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""c1f7a91b-d0fd-4a62-997e-7fb9b69bf235"", + ""path"": ""/rightStick"", + ""interactions"": """", + ""processors"": ""ScaleVector2(x=15,y=15)"", + ""groups"": "";Gamepad"", + ""action"": ""Look"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""8c8e490b-c610-4785-884f-f04217b23ca4"", + ""path"": ""/delta"", + ""interactions"": """", + ""processors"": """", + ""groups"": "";Keyboard&Mouse;Touch"", + ""action"": ""Look"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""3e5f5442-8668-4b27-a940-df99bad7e831"", + ""path"": ""/{Hatswitch}"", + ""interactions"": """", + ""processors"": """", + ""groups"": ""Joystick"", + ""action"": ""Look"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""34a92533-1493-489f-97e9-401f2c472119"", + ""path"": ""/p"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""TogglePhospheneSim"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""32b6aaa4-3eee-42d2-9d12-f0792fc402ca"", + ""path"": ""/3"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""TogglePhospheneSim"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""24a67646-4120-4be0-889b-b8fd6b463fe5"", + ""path"": ""/e"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleEdgeDetection"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""0d48eca3-feac-46bd-a760-06ecc1e0d7c0"", + ""path"": ""/2"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleEdgeDetection"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""3015442e-b235-486c-a9a6-bbf917e480c6"", + ""path"": ""/t"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""IterateSurfaceReplacement"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""ab8dff0c-f727-49c3-a20c-017d3030bfa4"", + ""path"": ""/1"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""IterateSurfaceReplacement"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""eec3cc20-0a98-451b-954a-9cfb0fd747ef"", + ""path"": ""/g"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleGazeLocking"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""b685618a-b179-4684-8af0-3a47dc8fd4b4"", + ""path"": ""/5"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleGazeLocking"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""d50be507-897d-416c-96ce-65ea22dd8b9b"", + ""path"": ""/c"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleCamLocking"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""1c6fc37a-ea91-4895-9a57-e60854d729ac"", + ""path"": ""/6"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleCamLocking"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""89c72108-0434-4308-b703-f72af2a98878"", + ""path"": ""/c"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleEyeTrackingMode"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""32e146f2-3d6a-4d6f-9e5b-4356f0dbd45e"", + ""path"": ""/4"", + ""interactions"": """", + ""processors"": """", + ""groups"": """", + ""action"": ""ToggleEyeTrackingMode"", + ""isComposite"": false, + ""isPartOfComposite"": false + } + ] + } + ], + ""controlSchemes"": [ + { + ""name"": ""Keyboard&Mouse"", + ""bindingGroup"": ""Keyboard&Mouse"", + ""devices"": [ + { + ""devicePath"": """", + ""isOptional"": false, + ""isOR"": false + }, + { + ""devicePath"": """", + ""isOptional"": false, + ""isOR"": false + } + ] + }, + { + ""name"": ""Gamepad"", + ""bindingGroup"": ""Gamepad"", + ""devices"": [ + { + ""devicePath"": """", + ""isOptional"": false, + ""isOR"": false + } + ] + }, + { + ""name"": ""Touch"", + ""bindingGroup"": ""Touch"", + ""devices"": [ + { + ""devicePath"": """", + ""isOptional"": false, + ""isOR"": false + } + ] + }, + { + ""name"": ""Joystick"", + ""bindingGroup"": ""Joystick"", + ""devices"": [ + { + ""devicePath"": """", + ""isOptional"": false, + ""isOR"": false + } + ] + }, + { + ""name"": ""XR"", + ""bindingGroup"": ""XR"", + ""devices"": [ + { + ""devicePath"": """", + ""isOptional"": false, + ""isOR"": false + } + ] + } + ] +}"); + // Experiment + m_Experiment = asset.FindActionMap("Experiment", throwIfNotFound: true); + m_Experiment_Move = m_Experiment.FindAction("Move", throwIfNotFound: true); + m_Experiment_Look = m_Experiment.FindAction("Look", throwIfNotFound: true); + m_Experiment_TogglePhospheneSim = m_Experiment.FindAction("TogglePhospheneSim", throwIfNotFound: true); + m_Experiment_ToggleEdgeDetection = m_Experiment.FindAction("ToggleEdgeDetection", throwIfNotFound: true); + m_Experiment_IterateSurfaceReplacement = m_Experiment.FindAction("IterateSurfaceReplacement", throwIfNotFound: true); + m_Experiment_ToggleEyeTrackingMode = m_Experiment.FindAction("ToggleEyeTrackingMode", throwIfNotFound: true); + m_Experiment_ToggleGazeLocking = m_Experiment.FindAction("ToggleGazeLocking", throwIfNotFound: true); + m_Experiment_ToggleCamLocking = m_Experiment.FindAction("ToggleCamLocking", throwIfNotFound: true); + } + + public void Dispose() + { + UnityEngine.Object.Destroy(asset); + } + + public InputBinding? bindingMask + { + get => asset.bindingMask; + set => asset.bindingMask = value; + } + + public ReadOnlyArray? devices + { + get => asset.devices; + set => asset.devices = value; + } + + public ReadOnlyArray controlSchemes => asset.controlSchemes; + + public bool Contains(InputAction action) + { + return asset.Contains(action); + } + + public IEnumerator GetEnumerator() + { + return asset.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Enable() + { + asset.Enable(); + } + + public void Disable() + { + asset.Disable(); + } + public IEnumerable bindings => asset.bindings; + + public InputAction FindAction(string actionNameOrId, bool throwIfNotFound = false) + { + return asset.FindAction(actionNameOrId, throwIfNotFound); + } + public int FindBinding(InputBinding bindingMask, out InputAction action) + { + return asset.FindBinding(bindingMask, out action); + } + + // Experiment + private readonly InputActionMap m_Experiment; + private IExperimentActions m_ExperimentActionsCallbackInterface; + private readonly InputAction m_Experiment_Move; + private readonly InputAction m_Experiment_Look; + private readonly InputAction m_Experiment_TogglePhospheneSim; + private readonly InputAction m_Experiment_ToggleEdgeDetection; + private readonly InputAction m_Experiment_IterateSurfaceReplacement; + private readonly InputAction m_Experiment_ToggleEyeTrackingMode; + private readonly InputAction m_Experiment_ToggleGazeLocking; + private readonly InputAction m_Experiment_ToggleCamLocking; + public struct ExperimentActions + { + private @XarphosBasement m_Wrapper; + public ExperimentActions(@XarphosBasement wrapper) { m_Wrapper = wrapper; } + public InputAction @Move => m_Wrapper.m_Experiment_Move; + public InputAction @Look => m_Wrapper.m_Experiment_Look; + public InputAction @TogglePhospheneSim => m_Wrapper.m_Experiment_TogglePhospheneSim; + public InputAction @ToggleEdgeDetection => m_Wrapper.m_Experiment_ToggleEdgeDetection; + public InputAction @IterateSurfaceReplacement => m_Wrapper.m_Experiment_IterateSurfaceReplacement; + public InputAction @ToggleEyeTrackingMode => m_Wrapper.m_Experiment_ToggleEyeTrackingMode; + public InputAction @ToggleGazeLocking => m_Wrapper.m_Experiment_ToggleGazeLocking; + public InputAction @ToggleCamLocking => m_Wrapper.m_Experiment_ToggleCamLocking; + public InputActionMap Get() { return m_Wrapper.m_Experiment; } + public void Enable() { Get().Enable(); } + public void Disable() { Get().Disable(); } + public bool enabled => Get().enabled; + public static implicit operator InputActionMap(ExperimentActions set) { return set.Get(); } + public void SetCallbacks(IExperimentActions instance) + { + if (m_Wrapper.m_ExperimentActionsCallbackInterface != null) + { + @Move.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnMove; + @Move.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnMove; + @Move.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnMove; + @Look.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnLook; + @Look.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnLook; + @Look.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnLook; + @TogglePhospheneSim.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnTogglePhospheneSim; + @TogglePhospheneSim.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnTogglePhospheneSim; + @TogglePhospheneSim.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnTogglePhospheneSim; + @ToggleEdgeDetection.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleEdgeDetection; + @ToggleEdgeDetection.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleEdgeDetection; + @ToggleEdgeDetection.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleEdgeDetection; + @IterateSurfaceReplacement.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnIterateSurfaceReplacement; + @IterateSurfaceReplacement.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnIterateSurfaceReplacement; + @IterateSurfaceReplacement.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnIterateSurfaceReplacement; + @ToggleEyeTrackingMode.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleEyeTrackingMode; + @ToggleEyeTrackingMode.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleEyeTrackingMode; + @ToggleEyeTrackingMode.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleEyeTrackingMode; + @ToggleGazeLocking.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleGazeLocking; + @ToggleGazeLocking.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleGazeLocking; + @ToggleGazeLocking.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleGazeLocking; + @ToggleCamLocking.started -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleCamLocking; + @ToggleCamLocking.performed -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleCamLocking; + @ToggleCamLocking.canceled -= m_Wrapper.m_ExperimentActionsCallbackInterface.OnToggleCamLocking; + } + m_Wrapper.m_ExperimentActionsCallbackInterface = instance; + if (instance != null) + { + @Move.started += instance.OnMove; + @Move.performed += instance.OnMove; + @Move.canceled += instance.OnMove; + @Look.started += instance.OnLook; + @Look.performed += instance.OnLook; + @Look.canceled += instance.OnLook; + @TogglePhospheneSim.started += instance.OnTogglePhospheneSim; + @TogglePhospheneSim.performed += instance.OnTogglePhospheneSim; + @TogglePhospheneSim.canceled += instance.OnTogglePhospheneSim; + @ToggleEdgeDetection.started += instance.OnToggleEdgeDetection; + @ToggleEdgeDetection.performed += instance.OnToggleEdgeDetection; + @ToggleEdgeDetection.canceled += instance.OnToggleEdgeDetection; + @IterateSurfaceReplacement.started += instance.OnIterateSurfaceReplacement; + @IterateSurfaceReplacement.performed += instance.OnIterateSurfaceReplacement; + @IterateSurfaceReplacement.canceled += instance.OnIterateSurfaceReplacement; + @ToggleEyeTrackingMode.started += instance.OnToggleEyeTrackingMode; + @ToggleEyeTrackingMode.performed += instance.OnToggleEyeTrackingMode; + @ToggleEyeTrackingMode.canceled += instance.OnToggleEyeTrackingMode; + @ToggleGazeLocking.started += instance.OnToggleGazeLocking; + @ToggleGazeLocking.performed += instance.OnToggleGazeLocking; + @ToggleGazeLocking.canceled += instance.OnToggleGazeLocking; + @ToggleCamLocking.started += instance.OnToggleCamLocking; + @ToggleCamLocking.performed += instance.OnToggleCamLocking; + @ToggleCamLocking.canceled += instance.OnToggleCamLocking; + } + } + } + public ExperimentActions @Experiment => new ExperimentActions(this); + private int m_KeyboardMouseSchemeIndex = -1; + public InputControlScheme KeyboardMouseScheme + { + get + { + if (m_KeyboardMouseSchemeIndex == -1) m_KeyboardMouseSchemeIndex = asset.FindControlSchemeIndex("Keyboard&Mouse"); + return asset.controlSchemes[m_KeyboardMouseSchemeIndex]; + } + } + private int m_GamepadSchemeIndex = -1; + public InputControlScheme GamepadScheme + { + get + { + if (m_GamepadSchemeIndex == -1) m_GamepadSchemeIndex = asset.FindControlSchemeIndex("Gamepad"); + return asset.controlSchemes[m_GamepadSchemeIndex]; + } + } + private int m_TouchSchemeIndex = -1; + public InputControlScheme TouchScheme + { + get + { + if (m_TouchSchemeIndex == -1) m_TouchSchemeIndex = asset.FindControlSchemeIndex("Touch"); + return asset.controlSchemes[m_TouchSchemeIndex]; + } + } + private int m_JoystickSchemeIndex = -1; + public InputControlScheme JoystickScheme + { + get + { + if (m_JoystickSchemeIndex == -1) m_JoystickSchemeIndex = asset.FindControlSchemeIndex("Joystick"); + return asset.controlSchemes[m_JoystickSchemeIndex]; + } + } + private int m_XRSchemeIndex = -1; + public InputControlScheme XRScheme + { + get + { + if (m_XRSchemeIndex == -1) m_XRSchemeIndex = asset.FindControlSchemeIndex("XR"); + return asset.controlSchemes[m_XRSchemeIndex]; + } + } + public interface IExperimentActions + { + void OnMove(InputAction.CallbackContext context); + void OnLook(InputAction.CallbackContext context); + void OnTogglePhospheneSim(InputAction.CallbackContext context); + void OnToggleEdgeDetection(InputAction.CallbackContext context); + void OnIterateSurfaceReplacement(InputAction.CallbackContext context); + void OnToggleEyeTrackingMode(InputAction.CallbackContext context); + void OnToggleGazeLocking(InputAction.CallbackContext context); + void OnToggleCamLocking(InputAction.CallbackContext context); + } +} diff --git a/Xarphos-Basement.cs.meta b/Xarphos-Basement.cs.meta new file mode 100644 index 0000000..8b7e517 --- /dev/null +++ b/Xarphos-Basement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c06baad5f62772c419d0e01dd9ef3c8c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Xarphos-Basement.inputactions b/Xarphos-Basement.inputactions new file mode 100644 index 0000000..6346eaa --- /dev/null +++ b/Xarphos-Basement.inputactions @@ -0,0 +1,433 @@ +{ + "name": "Xarphos-Basement", + "maps": [ + { + "name": "Experiment", + "id": "0c1a547e-22aa-4aae-8248-84c703b22548", + "actions": [ + { + "name": "Move", + "type": "Value", + "id": "34bd96bc-3257-4350-9dbd-20a6578f8d03", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Look", + "type": "Value", + "id": "f6b2fbf2-2525-497f-8b48-480edbaae60a", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "TogglePhospheneSim", + "type": "Button", + "id": "3fe95d10-e39d-4cc8-87f5-5a1b2a7a1609", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ToggleEdgeDetection", + "type": "Button", + "id": "3e196229-2795-46f2-bae8-3f888893222d", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "IterateSurfaceReplacement", + "type": "Button", + "id": "e0959e22-032b-4278-9985-09bbe7bf988b", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ToggleEyeTrackingMode", + "type": "Button", + "id": "37a70d47-4e8b-4905-a375-e611ffd188ef", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ToggleGazeLocking", + "type": "Button", + "id": "35675ead-d89e-41d8-905e-a26a620f4a17", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ToggleCamLocking", + "type": "Button", + "id": "effd86eb-132c-4dc0-8579-f9f87766e61c", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "", + "id": "978bfe49-cc26-4a3d-ab7b-7d7a29327403", + "path": "/leftStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1635d3fe-58b6-4ba9-a4e2-f4b964f6b5c8", + "path": "/joystick", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "WASD", + "id": "00ca640b-d935-4593-8157-c05846ea39b3", + "path": "Dpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "8180e8bd-4097-4f4e-ab88-4523101a6ce9", + "path": "/d", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "1c5327b5-f71c-4f60-99c7-4e737386f1d1", + "path": "/s", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "2e46982e-44cc-431b-9f0b-c11910bf467a", + "path": "/a", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "77bff152-3580-4b21-b6de-dcd0c7e41164", + "path": "/h", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "3ea4d645-4504-4529-b061-ab81934c3752", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8ca86599-2946-4e18-9fa8-7bd3eebc7691", + "path": "/trackpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e891f054-6cdc-4392-88ec-222828cb5834", + "path": "/touchpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d556355b-2f1d-4663-80a3-eaff580a98ee", + "path": "/thumbstick", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c1f7a91b-d0fd-4a62-997e-7fb9b69bf235", + "path": "/rightStick", + "interactions": "", + "processors": "ScaleVector2(x=15,y=15)", + "groups": ";Gamepad", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8c8e490b-c610-4785-884f-f04217b23ca4", + "path": "/delta", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse;Touch", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3e5f5442-8668-4b27-a940-df99bad7e831", + "path": "/{Hatswitch}", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "34a92533-1493-489f-97e9-401f2c472119", + "path": "/p", + "interactions": "", + "processors": "", + "groups": "", + "action": "TogglePhospheneSim", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "32b6aaa4-3eee-42d2-9d12-f0792fc402ca", + "path": "/3", + "interactions": "", + "processors": "", + "groups": "", + "action": "TogglePhospheneSim", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "24a67646-4120-4be0-889b-b8fd6b463fe5", + "path": "/e", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleEdgeDetection", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "0d48eca3-feac-46bd-a760-06ecc1e0d7c0", + "path": "/2", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleEdgeDetection", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3015442e-b235-486c-a9a6-bbf917e480c6", + "path": "/t", + "interactions": "", + "processors": "", + "groups": "", + "action": "IterateSurfaceReplacement", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ab8dff0c-f727-49c3-a20c-017d3030bfa4", + "path": "/1", + "interactions": "", + "processors": "", + "groups": "", + "action": "IterateSurfaceReplacement", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "eec3cc20-0a98-451b-954a-9cfb0fd747ef", + "path": "/g", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleGazeLocking", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b685618a-b179-4684-8af0-3a47dc8fd4b4", + "path": "/5", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleGazeLocking", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d50be507-897d-416c-96ce-65ea22dd8b9b", + "path": "/c", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleCamLocking", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1c6fc37a-ea91-4895-9a57-e60854d729ac", + "path": "/6", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleCamLocking", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "89c72108-0434-4308-b703-f72af2a98878", + "path": "/c", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleEyeTrackingMode", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "32e146f2-3d6a-4d6f-9e5b-4356f0dbd45e", + "path": "/4", + "interactions": "", + "processors": "", + "groups": "", + "action": "ToggleEyeTrackingMode", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [ + { + "name": "Keyboard&Mouse", + "bindingGroup": "Keyboard&Mouse", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + }, + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Gamepad", + "bindingGroup": "Gamepad", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Touch", + "bindingGroup": "Touch", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Joystick", + "bindingGroup": "Joystick", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "XR", + "bindingGroup": "XR", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + } + ] +} \ No newline at end of file diff --git a/Xarphos-Basement.inputactions.meta b/Xarphos-Basement.inputactions.meta new file mode 100644 index 0000000..09c3857 --- /dev/null +++ b/Xarphos-Basement.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ba47e8253eefe60409f20f9227ccc725 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 1 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: