From bdd700199a610cf30c22e481b442863d45f79444 Mon Sep 17 00:00:00 2001 From: Mo Nipshagen Date: Tue, 19 Apr 2022 13:39:56 +0200 Subject: [PATCH 01/14] local changes --- Scripts/DSPVEyeTracking.cs | 280 +++++++++++++++++++++++++-- Scripts/DSPV_SimulationController.cs | 1 - Shader/DSPV_PhospheneShader.shader | 2 + Shader/DSPV_phosphene_vision.cginc | 14 +- 4 files changed, 273 insertions(+), 24 deletions(-) diff --git a/Scripts/DSPVEyeTracking.cs b/Scripts/DSPVEyeTracking.cs index 5a3f781..8ed7f7a 100644 --- a/Scripts/DSPVEyeTracking.cs +++ b/Scripts/DSPVEyeTracking.cs @@ -1,55 +1,199 @@ using System; +using System.Runtime.InteropServices; +using Unity.VisualScripting; using UnityEngine; +using UnityEngine.InputSystem; +using ViveSR.anipal; using ViveSR.anipal.Eye; using EyeFramework = ViveSR.anipal.Eye.SRanipal_Eye_Framework; namespace Xarphos.Scripts { - [RequireComponent(typeof(DSPV_SimulationController))] public class DSPVEyeTracking : MonoBehaviour { - // Added for Eye Tracking Implementation - [SerializeField] private Camera simCam; - internal bool EyeTrackingAvailable { get; private set; } + 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 = 0; + private static float time_stamp; + private static int frame; + + internal bool EyeTrackingAvailable { get; private set; } + +#region Unity Event Functioens private void Start() { - EyeTrackingAvailable = SRanipal_Eye_Framework.Instance.EnableEye; + // SRanipal_Eye_v2.LaunchEyeCalibration(); // Perform calibration for eye tracking. + Invoke(nameof(SystemCheck), .5f); + Invoke(nameof(RegisterCallback), .5f); } - + private void FixedUpdate() { - EyeTrackingAvailable = CheckFrameworkStatusErrors(); + if (!CheckFrameworkStatusErrors()) + { + EyeTrackingAvailable = false; + // Debug.LogWarning("Framework Responded failure to work."); + } } - internal bool EyeTrackingStep(out Vector2 eyePosition) + private void Update() { - eyePosition = Vector2.zero; - if (!EyeTrackingAvailable) + if (Keyboard.current[Key.F8].wasPressedThisFrame) + { + SetDebugGazeRender(!renderGazeRays); + } + if (Keyboard.current[Key.F9].wasPressedThisFrame) + { + freezeGazeRays = !freezeGazeRays; + } + if (renderGazeRays && !freezeGazeRays) + { + UpdateGazeRays(); + } + } +#endregion + +#region EyeData Setup + private void SystemCheck() + { + if (EyeFramework.Status != EyeFramework.FrameworkStatus.NOT_SUPPORT) + { + EyeTrackingAvailable = false; + Debug.LogError("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) { - return false; + SRanipal_Eye_v2.WrapperRegisterEyeDataCallback( + Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) + ); + eye_callback_registered = true; } - 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)) + else if (!SRanipal_Eye_Framework.Instance.EnableEyeDataCallback && eye_callback_registered) { - eyePosition = hit.textureCoord; - return true; + 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 && - EyeFramework.Status != EyeFramework.FrameworkStatus.NOT_SUPPORT; + return EyeFramework.Status == EyeFramework.FrameworkStatus.WORKING; } +#endregion private int Gcf(int a, int b) { @@ -61,5 +205,99 @@ private int Gcf(int a, int b) } return a; } + +#region EyeData Clean Up & Necessities + private void OnDisable() + { + Release(); + } + + void OnApplicationQuit() + { + Release(); + } + + /// + /// Release callback thread when disabled or quit + /// + private static void Release() + { + if (eye_callback_registered == true) + { + SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( + Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) + ); + eye_callback_registered = false; + } + + Destroy(leftVisual); + Destroy(rightVisual); + } + + /// + /// Required class for IL2CPP scripting backend support + /// + internal class MonoPInvokeCallbackAttribute : System.Attribute + { + public MonoPInvokeCallbackAttribute() { } + } +#endregion + +#region Debug Gaze Rendering + private static bool renderGazeRays, freezeGazeRays; + private static GameObject leftVisual, rightVisual; + private static LineRenderer leftGazeLine, rightGazeLine; + + private static Camera mainCam; + + private void SetDebugGazeRender(bool status) + { + // first acticvation: set up objects and references + if (status && (leftVisual == null || rightVisual == null)) + { + mainCam = Camera.main; + leftVisual = new GameObject("LeftGazeRender"); + rightVisual = new GameObject("RightGazeRender"); + leftGazeLine = leftVisual.AddComponent(); + { + leftGazeLine.startColor = Color.blue; + leftGazeLine.endColor = Color.blue; + leftGazeLine.startWidth = 0.005f; + leftGazeLine.endWidth = 0.005f; + } + rightGazeLine = rightVisual.AddComponent(); + { + rightGazeLine.startColor = Color.red; + rightGazeLine.endColor = Color.red; + rightGazeLine.startWidth = 0.005f; + rightGazeLine.endWidth = 0.005f; + } + } + + renderGazeRays = status; + leftVisual.SetActive(status); + rightVisual.SetActive(status); + } + + private void UpdateGazeRays() + { + Vector3 leftOrigin, rightOrigin, leftDir, rightDir; + + // 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); + + // transform from local space + var t = mainCam.transform; + leftOrigin = t.TransformPoint(leftOrigin); + rightOrigin = t.TransformPoint(rightOrigin); + leftDir = t.TransformDirection(leftDir); + rightDir = t.TransformDirection(rightDir); + + // update render + leftGazeLine.SetPositions(new [] { leftOrigin, leftOrigin + leftDir * 20 }); + rightGazeLine.SetPositions(new [] { rightOrigin, rightOrigin + rightDir * 20 }); + } +#endregion } } \ No newline at end of file diff --git a/Scripts/DSPV_SimulationController.cs b/Scripts/DSPV_SimulationController.cs index 287f576..cbcf88c 100644 --- a/Scripts/DSPV_SimulationController.cs +++ b/Scripts/DSPV_SimulationController.cs @@ -245,7 +245,6 @@ private void ProcessImageAndUpdatePhosphenes() activation[i] *= intensity_decay; activation[i] += Math.Max(0,input_effect*(stim-memoryTrace[i]));//);; memoryTrace[i] = memoryTrace[i] * trace_decay + trace_increase*stim; - } Material.SetFloatArray("activation", activation); diff --git a/Shader/DSPV_PhospheneShader.shader b/Shader/DSPV_PhospheneShader.shader index 03378a3..00c58f7 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_phosphene_vision.cginc b/Shader/DSPV_phosphene_vision.cginc index 7009173..90f70c7 100644 --- a/Shader/DSPV_phosphene_vision.cginc +++ b/Shader/DSPV_phosphene_vision.cginc @@ -20,12 +20,22 @@ } 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(int gazeLocked, float2 eyePosition, float4 pSpecs[1000], float activation[1000], float nPhosphenes, float sizeCoefficient, float brightness, float dropout, float2 pixelPosition) { + float4 DSPV_phospheneSimulation( + int gazeLocked, + float2 eyePosition, + float4 pSpecs[1000], + float activation[1000], + float nPhosphenes, + float sizeCoefficient, + float brightness, + float dropout, + float2 pixelPosition + ) { // Output luminance for current pixel fixed4 pixelLuminance = fixed4(0,0,0,0); From be61065c54e6201c01990c554074f6e751464018 Mon Sep 17 00:00:00 2001 From: Mo Nipshagen Date: Tue, 19 Apr 2022 13:40:29 +0200 Subject: [PATCH 02/14] onRender solution --- Material.meta | 8 + Material/QuadMaterial.mat | 79 ++++++++ Material/QuadMaterial.mat.meta | 8 + Scripts/DSPV_SimulationPostProcessor.cs | 182 +++++++++++++++++++ Scripts/DSPV_SimulationPostProcessor.cs.meta | 11 ++ Scripts/PhospheneConfiguration.cs | 31 ++++ Scripts/PhospheneConfiguration.cs.meta | 11 ++ Shader/CircularMask.shader | 143 +++++++++++++++ Shader/CircularMask.shader.meta | 10 + pSpecs1.json | 1 + pSpecs1.json.meta | 7 + 11 files changed, 491 insertions(+) create mode 100644 Material.meta create mode 100644 Material/QuadMaterial.mat create mode 100644 Material/QuadMaterial.mat.meta create mode 100644 Scripts/DSPV_SimulationPostProcessor.cs create mode 100644 Scripts/DSPV_SimulationPostProcessor.cs.meta create mode 100644 Scripts/PhospheneConfiguration.cs create mode 100644 Scripts/PhospheneConfiguration.cs.meta create mode 100644 Shader/CircularMask.shader create mode 100644 Shader/CircularMask.shader.meta create mode 100644 pSpecs1.json create mode 100644 pSpecs1.json.meta 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/DSPV_SimulationPostProcessor.cs b/Scripts/DSPV_SimulationPostProcessor.cs new file mode 100644 index 0000000..c4a4ded --- /dev/null +++ b/Scripts/DSPV_SimulationPostProcessor.cs @@ -0,0 +1,182 @@ +using UnityEngine; +using Rect = UnityEngine.Rect; +using System; +using OpenCVForUnity.CoreModule; +using OpenCVForUnity.ImgprocModule; +using OpenCVForUnity.UnityUtils; +using UnityEngine.InputSystem; + + +namespace Xarphos.Scripts +{ + [RequireComponent(typeof(Camera))] + public class DSPV_SimulationPostProcessor : MonoBehaviour + { + // // The material texture will be used as phosphene activation mask + protected Material material; + protected Texture2D input_texture; //The input texture (from webcam or virtual camera) + protected Texture2D activation_mask; //The output texture after preprocessing + + // // The shader that is used for the phosphene simulation + [SerializeField] protected Shader shader; + private static readonly int _PhospheneActivationMask = Shader.PropertyToID("_ActivationMask"); + private static readonly int _PhospheneActivation = Shader.PropertyToID("activation"); + private static readonly int _PhospheneSpecs = Shader.PropertyToID("_pSpecs"); + private static readonly int _PhospheneFilter = Shader.PropertyToID("_PhospheneFilter"); + private static readonly int _PhospheneEyePos = Shader.PropertyToID("_EyePosition"); + private static readonly int _PhospheneGazeLocked = Shader.PropertyToID("_GazeLocked"); + + + // // TODO use separate image processing shader + // protected Shader imgprocShader; + // protected Material imgprocMaterial; + + // // TODO: image processing + // // OpenCVForUnity + protected Mat in_mat; + protected Mat out_mat; + protected Mat dilateElement; + protected bool cannyFiltering = true; + + // EyeTracking + protected Vector2 eyePosition; + protected int gazeLocking; // used as boolean (sent to shader) + protected bool camLocking; + + // For reading phosphene configuration from JSON + [SerializeField] string phospheneConfigurationFile; + PhospheneConfiguration phospheneConfiguration; // is loaded from the above JSON file + + // stimulation parameters + protected float stim; + protected float[] activation; + protected float[] memoryTrace; + [SerializeField] float input_effect = 0.7f; + [SerializeField] float intensity_decay = 0.8f; + [SerializeField] float trace_increase = 0.1f; + [SerializeField] float trace_decay = 0.9f; + + protected void Awake() + { + // Initialize material, input texture and shader + material = new Material(shader); + // imgprocMaterial = new Material(imgprocShader); TODO + + input_texture = new Texture2D(512, 512, TextureFormat.RGBA32, false); + + + // Load phosphene configuration and pass to shader + phospheneConfiguration = PhospheneConfiguration.load(phospheneConfigurationFile); + material.SetVectorArray(_PhospheneSpecs, phospheneConfiguration.specifications); + material.SetInt("_nPhosphenes", phospheneConfiguration.phospheneCount); + + // Initialize other simulation variables + activation = new float[phospheneConfiguration.phospheneCount]; + memoryTrace = new float[phospheneConfiguration.phospheneCount]; + + // // OPENCV TODO + in_mat = new Mat(512, 512, CvType.CV_8UC4, new Scalar(0, 0, 0, 255)); + out_mat = new Mat(512, 512, CvType.CV_8UC4, new Scalar(0, 0, 0, 255)); + dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(3, 3)); // was new Size(9, 9)) + } + + // Postprocess the image + void OnRenderImage (RenderTexture source, RenderTexture destination) + { + //1. Read the pixels from 'source' (which is the active rendertexture by default) + input_texture.ReadPixels(new Rect(0, 0, source.width, source.height), 0, 0); + input_texture.Apply(); + + //2. Sample a subsection of the input texture for the activation mask + // TODO + + activation_mask = input_texture; + + //3. Apply image processing + if (cannyFiltering){ + Utils.texture2DToMat(input_texture,in_mat); + Imgproc.Canny(in_mat, out_mat, 110, 220); + Imgproc.dilate(out_mat, out_mat, dilateElement); + Utils.matToTexture2D(out_mat, activation_mask); + } + + //4. Calculate the phosphene activations + for (int i = 0; i < phospheneConfiguration.phospheneCount; i++){ + Vector2 pos = phospheneConfiguration.specifications[i]; // x and y coordinates + if (camLocking) { + pos += eyePosition- new Vector2(0.5f,0.5f);} + + if (pos.x > 0 && pos.x < 1 && pos.y > 0 && pos.y < 1) { + stim = activation_mask.GetPixelBilinear(pos.x, pos.y).grayscale;} + else { + stim = 0;} + activation[i] *= intensity_decay; + activation[i] += Math.Max(0,input_effect*(stim-memoryTrace[i]));//);; + memoryTrace[i] = memoryTrace[i] * trace_decay + trace_increase*stim; + } + + // 5. apply the phosphene shader + material.SetTexture(_PhospheneActivationMask, activation_mask); + material.SetFloatArray(_PhospheneActivation, activation); + material.SetVectorArray(_PhospheneSpecs, phospheneConfiguration.specifications); + Graphics.Blit (source, destination, material); + } + + protected void Update() + { + + ProcessKeyboardInput(); + + // + material.SetVector(_PhospheneEyePos, eyePosition); + material.SetInt(_PhospheneGazeLocked, gazeLocking); + } + + private void ProcessKeyboardInput() + { + if (Keyboard.current.digit1Key.isPressed) + { + cannyFiltering = false; + material.SetFloat(_PhospheneFilter, 0f); + } + + if (Keyboard.current.digit2Key.isPressed) + { + cannyFiltering = true; + material.SetFloat(_PhospheneFilter, 1f); + } + + if (Keyboard.current.digit3Key.isPressed) + { + cannyFiltering = false; + material.SetFloat(_PhospheneFilter, 1f); + } + + if (Keyboard.current.digit4Key.isPressed) + { + cannyFiltering = true; + material.SetFloat(_PhospheneFilter, 0f); + } + + if (Keyboard.current.gKey.isPressed) + { + gazeLocking = 1 - gazeLocking; + } + + if (Keyboard.current.cKey.isPressed) + { + camLocking = !camLocking; + } + + if (Keyboard.current.escapeKey.isPressed) + { +#if UNITY_EDITOR + UnityEditor.EditorApplication.isPlaying = false; +#else + Application.Quit(); +#endif + } + } + + } +} diff --git a/Scripts/DSPV_SimulationPostProcessor.cs.meta b/Scripts/DSPV_SimulationPostProcessor.cs.meta new file mode 100644 index 0000000..1d0e56d --- /dev/null +++ b/Scripts/DSPV_SimulationPostProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: edd7a3a668f4d93408e5efc3de49ff39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/PhospheneConfiguration.cs b/Scripts/PhospheneConfiguration.cs new file mode 100644 index 0000000..4cbb9f8 --- /dev/null +++ b/Scripts/PhospheneConfiguration.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using System.IO; +using System.Collections.Generic; + + +namespace Xarphos.Scripts +{ + + + public class PhospheneConfiguration + { // Data class containing the phosphene configuration (count, locations, sizes) + // instances can be directly deseriallized from a JSON file using the 'load' method + + public string description = "PHOSPHENE SPECIFICATIONS FILE. 'phospheneCount': the number of phosphenes. 'specifications': list of phosphenes, with their screen coordinates 'x','y' (range 0 to 1). 'z' indicates phosphene size (sigma), and 'w' is unused at the moment."; + public int phospheneCount; + public Vector4[] specifications; + + public static PhospheneConfiguration load(string filename) + { + string json = System.IO.File.ReadAllText(filename); + return JsonUtility.FromJson(json); + } + + public void save(string filename) + { + string json = JsonUtility.ToJson(this); + File.WriteAllText(filename, json); + Debug.Log("Saved phosphene configuration to " + filename); + } + } +} diff --git a/Scripts/PhospheneConfiguration.cs.meta b/Scripts/PhospheneConfiguration.cs.meta new file mode 100644 index 0000000..3d83bd1 --- /dev/null +++ b/Scripts/PhospheneConfiguration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a10f5ebd8e4e53d43b4fdfd7e6193d35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Shader/CircularMask.shader b/Shader/CircularMask.shader new file mode 100644 index 0000000..8a6d05e --- /dev/null +++ b/Shader/CircularMask.shader @@ -0,0 +1,143 @@ +// Adapted from: https://github.com/umm/circle_mask_shader + +Shader "UI/CircleMask" +{ + Properties + { + [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _ColorMask ("Color Mask", Float) = 15 + + _RadiusX ("Radius X", Range(0,1)) = 1 + _RadiusY ("Radius Y", Range(0,1)) = 1 + + _ScaleX ("Scale X", Float) = 1 + _ScaleY ("Scale Y", Float) = 1 + + _AntialiasThreshold ("Antialias Threshold", Range(0, 0.9999)) = 0.96 + + [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 + } + + SubShader + { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest [unity_GUIZTestMode] + Blend SrcAlpha OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass + { + Name "Default" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + + #include "UnityCG.cginc" + + #pragma multi_compile __ UNITY_UI_CLIP_RECT + #pragma multi_compile __ UNITY_UI_ALPHACLIP + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + float2 originalTexcoord : TEXCOORD2; + UNITY_VERTEX_OUTPUT_STEREO + }; + + sampler2D _MainTex; + fixed4 _Color; + float4 _ClipRect; + float4 _MainTex_ST; + float _RadiusX; + float _RadiusY; + float _ScaleX; + float _ScaleY; + float _AntialiasThreshold; + + float circleDelta(float2 texcoord) { + if (_RadiusX <= 0.0001 || _RadiusY <= 0.0001) return 0; + float x = (2 * (texcoord.x - 0.5)) / _RadiusX; + float y = (2 * (texcoord.y - 0.5)) / _RadiusY; + float value = x * x + y * y; + + return smoothstep(1.0, _AntialiasThreshold, value); + } + + v2f vert(appdata_t v) + { + v2f OUT; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); + OUT.worldPosition = v.vertex; + OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); + OUT.originalTexcoord = v.texcoord; + OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + + OUT.color = v.color * _Color; + return OUT; + } + + fixed4 frag(v2f IN) : SV_Target + { + // scale before circle clipping + float2 size = float2(1 / _ScaleX, 1 / _ScaleY); + float2 halfSize = size * 0.5; + float2 center = float2(0.5, 0.5); + half4 color = tex2D(_MainTex, IN.texcoord * size + center - halfSize) * IN.color; + + color.a *= circleDelta(IN.texcoord); + + #ifdef UNITY_UI_CLIP_RECT + color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); + #endif + + #ifdef UNITY_UI_ALPHACLIP + clip (color.a - 0.001); + #endif + + return color; + } + ENDCG + } + } +} diff --git a/Shader/CircularMask.shader.meta b/Shader/CircularMask.shader.meta new file mode 100644 index 0000000..c8cfb98 --- /dev/null +++ b/Shader/CircularMask.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 1e4925d6ba257174eaef019aab0dba69 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/pSpecs1.json b/pSpecs1.json new file mode 100644 index 0000000..f418992 --- /dev/null +++ b/pSpecs1.json @@ -0,0 +1 @@ +{"description":"PHOSPHENE SPECIFICATIONS FILE. 'phospheneCount': the number of phosphenes. 'specifications': list of phosphenes, with their screen coordinates 'x','y' (range 0 to 1). 'z' indicates phosphene size (sigma), and 'w' is unused at the moment.","phospheneCount":1000,"specifications":[{"x":0.6039215922355652,"y":0.5372549295425415,"z":0.16862745583057404,"w":1.0},{"x":0.0117647061124444,"y":0.21960784494876862,"z":0.8627451062202454,"w":1.0},{"x":0.4156862795352936,"y":0.13725490868091584,"z":0.5764706134796143,"w":1.0},{"x":0.6784313917160034,"y":0.3019607961177826,"z":0.40784314274787905,"w":1.0},{"x":0.7137255072593689,"y":0.5843137502670288,"z":0.3450980484485626,"w":1.0},{"x":0.35686275362968447,"y":0.33725491166114809,"z":0.33725491166114809,"w":1.0},{"x":0.4313725531101227,"y":0.5607843399047852,"z":0.1411764770746231,"w":1.0},{"x":0.5921568870544434,"y":0.501960813999176,"z":0.1411764770746231,"w":1.0},{"x":0.5098039507865906,"y":0.2705882489681244,"z":0.3529411852359772,"w":1.0},{"x":0.501960813999176,"y":0.7607843279838562,"z":0.3960784375667572,"w":1.0},{"x":0.5647059082984924,"y":0.5254902243614197,"z":0.10588235408067703,"w":1.0},{"x":0.33725491166114809,"y":0.529411792755127,"z":0.2549019753932953,"w":1.0},{"x":0.3176470696926117,"y":0.364705890417099,"z":0.3529411852359772,"w":1.0},{"x":0.42352941632270815,"y":0.37254902720451357,"z":0.23137255012989045,"w":1.0},{"x":0.8745098114013672,"y":0.95686274766922,"z":0.8980392217636108,"w":1.0},{"x":0.3921568691730499,"y":0.5411764979362488,"z":0.18039216101169587,"w":1.0},{"x":0.27450981736183169,"y":0.7333333492279053,"z":0.49803921580314639,"w":1.0},{"x":0.8745098114013672,"y":0.9960784316062927,"z":0.9411764740943909,"w":1.0},{"x":0.6352941393852234,"y":0.46666666865348818,"z":0.21176470816135407,"w":1.0},{"x":0.8901960849761963,"y":0.21568627655506135,"z":0.7333333492279053,"w":1.0},{"x":0.6313725709915161,"y":0.30980393290519717,"z":0.3529411852359772,"w":1.0},{"x":0.843137264251709,"y":0.4274509847164154,"z":0.529411792755127,"w":1.0},{"x":0.1411764770746231,"y":0.6784313917160034,"z":0.6117647290229797,"w":1.0},{"x":0.8823529481887817,"y":0.729411780834198,"z":0.6745098233222961,"w":1.0},{"x":0.3803921639919281,"y":0.29411765933036806,"z":0.3686274588108063,"w":1.0},{"x":0.23529411852359773,"y":0.5333333611488342,"z":0.40784314274787905,"w":1.0},{"x":0.6196078658103943,"y":0.23529411852359773,"z":0.4470588266849518,"w":1.0},{"x":0.3137255012989044,"y":0.09019608050584793,"z":0.6941176652908325,"w":1.0},{"x":0.5098039507865906,"y":0.10196078568696976,"z":0.6117647290229797,"w":1.0},{"x":0.4588235318660736,"y":0.5372549295425415,"z":0.08627451211214066,"w":1.0},{"x":0.5333333611488342,"y":0.40392157435417178,"z":0.16078431904315949,"w":1.0},{"x":0.5176470875740051,"y":0.18431372940540315,"z":0.48235294222831728,"w":1.0},{"x":0.6470588445663452,"y":0.4745098054409027,"z":0.22745098173618318,"w":1.0},{"x":0.38823530077934267,"y":0.4313725531101227,"z":0.20392157137393952,"w":1.0},{"x":0.40392157435417178,"y":0.3686274588108063,"z":0.250980406999588,"w":1.0},{"x":0.7450980544090271,"y":0.14901961386203767,"z":0.6549019813537598,"w":1.0},{"x":0.6274510025978088,"y":0.43921568989753725,"z":0.21568627655506135,"w":1.0},{"x":0.6431372761726379,"y":0.054901961237192157,"z":0.7137255072593689,"w":1.0},{"x":0.4941176474094391,"y":0.41960784792900088,"z":0.125490203499794,"w":1.0},{"x":0.027450980618596078,"y":0.1921568661928177,"z":0.8627451062202454,"w":1.0},{"x":0.6431372761726379,"y":0.7254902124404907,"z":0.40392157435417178,"w":1.0},{"x":0.6039215922355652,"y":0.5843137502670288,"z":0.20000000298023225,"w":1.0},{"x":0.529411792755127,"y":0.47843137383461,"z":0.05882352963089943,"w":1.0},{"x":0.5882353186607361,"y":0.45490196347236636,"z":0.15294118225574494,"w":1.0},{"x":0.3803921639919281,"y":0.41960784792900088,"z":0.22745098173618318,"w":1.0},{"x":0.3960784375667572,"y":0.6039215922355652,"z":0.22745098173618318,"w":1.0},{"x":0.7568627595901489,"y":0.6941176652908325,"z":0.4901960790157318,"w":1.0},{"x":0.3843137323856354,"y":0.48235294222831728,"z":0.18431372940540315,"w":1.0},{"x":0.5215686559677124,"y":0.5254902243614197,"z":0.05098039284348488,"w":1.0},{"x":0.5098039507865906,"y":0.7568627595901489,"z":0.3921568691730499,"w":1.0},{"x":0.5882353186607361,"y":0.7058823704719544,"z":0.33725491166114809,"w":1.0},{"x":0.18431372940540315,"y":0.3137255012989044,"z":0.5647059082984924,"w":1.0},{"x":0.7137255072593689,"y":0.47843137383461,"z":0.32549020648002627,"w":1.0},{"x":0.3686274588108063,"y":0.6549019813537598,"z":0.3137255012989044,"w":1.0},{"x":0.6078431606292725,"y":0.6509804129600525,"z":0.2823529541492462,"w":1.0},{"x":0.5607843399047852,"y":0.4745098054409027,"z":0.09803921729326248,"w":1.0},{"x":0.5137255191802979,"y":0.3803921639919281,"z":0.1921568661928177,"w":1.0},{"x":0.5607843399047852,"y":0.6117647290229797,"z":0.1921568661928177,"w":1.0},{"x":0.29411765933036806,"y":0.3529411852359772,"z":0.3921568691730499,"w":1.0},{"x":0.3529411852359772,"y":0.5411764979362488,"z":0.23529411852359773,"w":1.0},{"x":0.7568627595901489,"y":0.4313725531101227,"z":0.40392157435417178,"w":1.0},{"x":0.615686297416687,"y":0.7607843279838562,"z":0.4313725531101227,"w":1.0},{"x":0.4470588266849518,"y":0.4431372582912445,"z":0.12156862765550614,"w":1.0},{"x":0.07058823853731156,"y":0.6549019813537598,"z":0.6980392336845398,"w":1.0},{"x":0.4313725531101227,"y":0.5843137502670288,"z":0.16470588743686677,"w":1.0},{"x":0.5176470875740051,"y":0.3450980484485626,"z":0.239215686917305,"w":1.0},{"x":0.6745098233222961,"y":0.9803921580314636,"z":0.7764706015586853,"w":1.0},{"x":0.4117647111415863,"y":0.5058823823928833,"z":0.1411764770746231,"w":1.0},{"x":0.4156862795352936,"y":0.5176470875740051,"z":0.13333334028720857,"w":1.0},{"x":0.572549045085907,"y":0.7764706015586853,"z":0.4313725531101227,"w":1.0},{"x":0.5215686559677124,"y":0.7843137383460999,"z":0.4313725531101227,"w":1.0},{"x":0.5254902243614197,"y":0.6666666865348816,"z":0.2549019753932953,"w":1.0},{"x":0.6901960968971252,"y":0.27843138575553896,"z":0.4470588266849518,"w":1.0},{"x":0.33725491166114809,"y":0.4000000059604645,"z":0.2980392277240753,"w":1.0},{"x":0.37254902720451357,"y":0.4588235318660736,"z":0.21176470816135407,"w":1.0},{"x":0.4313725531101227,"y":1.0,"z":0.7686274647712708,"w":1.0},{"x":0.6039215922355652,"y":0.529411792755127,"z":0.16862745583057404,"w":1.0},{"x":0.5137255191802979,"y":0.6039215922355652,"z":0.16078431904315949,"w":1.0},{"x":0.7882353067398071,"y":0.4627451002597809,"z":0.4431372582912445,"w":1.0},{"x":0.5098039507865906,"y":0.5960784554481506,"z":0.14901961386203767,"w":1.0},{"x":0.9607843160629273,"y":0.10588235408067703,"z":0.9254902005195618,"w":1.0},{"x":0.2705882489681244,"y":0.5529412031173706,"z":0.3607843220233917,"w":1.0},{"x":0.5098039507865906,"y":0.49803921580314639,"z":0.01568627543747425,"w":1.0},{"x":0.7568627595901489,"y":0.6235294342041016,"z":0.4313725531101227,"w":1.0},{"x":0.8823529481887817,"y":0.7882353067398071,"z":0.7254902124404907,"w":1.0},{"x":0.5098039507865906,"y":0.5176470875740051,"z":0.0313725508749485,"w":1.0},{"x":0.6274510025978088,"y":0.6039215922355652,"z":0.24705882370471955,"w":1.0},{"x":0.5372549295425415,"y":0.6431372761726379,"z":0.2235294133424759,"w":1.0},{"x":0.46666666865348818,"y":0.47843137383461,"z":0.06666667014360428,"w":1.0},{"x":0.11764705926179886,"y":0.545098066329956,"z":0.5921568870544434,"w":1.0},{"x":0.30980393290519717,"y":0.6784313917160034,"z":0.4000000059604645,"w":1.0},{"x":0.27450981736183169,"y":0.46666666865348818,"z":0.3529411852359772,"w":1.0},{"x":0.7019608020782471,"y":0.7372549176216126,"z":0.47058823704719546,"w":1.0},{"x":0.3333333432674408,"y":0.4431372582912445,"z":0.2705882489681244,"w":1.0},{"x":0.6313725709915161,"y":0.6000000238418579,"z":0.250980406999588,"w":1.0},{"x":0.6078431606292725,"y":0.27843138575553896,"z":0.3803921639919281,"w":1.0},{"x":0.2666666805744171,"y":0.30980393290519717,"z":0.46666666865348818,"w":1.0},{"x":0.45098039507865908,"y":0.43921568989753725,"z":0.12941177189350129,"w":1.0},{"x":0.800000011920929,"y":0.4901960790157318,"z":0.4588235318660736,"w":1.0},{"x":0.19607843458652497,"y":0.1882352977991104,"z":0.6666666865348816,"w":1.0},{"x":0.43921568989753725,"y":0.250980406999588,"z":0.3921568691730499,"w":1.0},{"x":0.4274509847164154,"y":0.364705890417099,"z":0.239215686917305,"w":1.0},{"x":0.34117648005485537,"y":0.2078431397676468,"z":0.5098039507865906,"w":1.0},{"x":0.5254902243614197,"y":0.6745098233222961,"z":0.26274511218070986,"w":1.0},{"x":0.658823549747467,"y":0.29411765933036806,"z":0.3960784375667572,"w":1.0},{"x":0.9215686321258545,"y":0.23529411852359773,"z":0.7568627595901489,"w":1.0},{"x":0.4588235318660736,"y":0.6549019813537598,"z":0.24313725531101228,"w":1.0},{"x":0.30980393290519717,"y":0.01568627543747425,"z":0.800000011920929,"w":1.0},{"x":0.6666666865348816,"y":0.3490196168422699,"z":0.34117648005485537,"w":1.0},{"x":0.6196078658103943,"y":0.6117647290229797,"z":0.24705882370471955,"w":1.0},{"x":0.46666666865348818,"y":0.21960784494876862,"z":0.43529412150382998,"w":1.0},{"x":0.5411764979362488,"y":0.18431372940540315,"z":0.48627451062202456,"w":1.0},{"x":0.5176470875740051,"y":0.7450980544090271,"z":0.37254902720451357,"w":1.0},{"x":0.5372549295425415,"y":0.5333333611488342,"z":0.07450980693101883,"w":1.0},{"x":0.4745098054409027,"y":0.5254902243614197,"z":0.05882352963089943,"w":1.0},{"x":0.3019607961177826,"y":0.2823529541492462,"z":0.45098039507865908,"w":1.0},{"x":0.4941176474094391,"y":0.9411764740943909,"z":0.6666666865348816,"w":1.0},{"x":0.5058823823928833,"y":0.5686274766921997,"z":0.10588235408067703,"w":1.0},{"x":0.23137255012989045,"y":0.6352941393852234,"z":0.4627451002597809,"w":1.0},{"x":0.13333334028720857,"y":0.7098039388656616,"z":0.6431372761726379,"w":1.0},{"x":0.47058823704719546,"y":0.7215686440467835,"z":0.34117648005485537,"w":1.0},{"x":0.6823529601097107,"y":0.6392157077789307,"z":0.3490196168422699,"w":1.0},{"x":0.47843137383461,"y":0.24313725531101228,"z":0.3960784375667572,"w":1.0},{"x":0.20392157137393952,"y":0.46666666865348818,"z":0.4588235318660736,"w":1.0},{"x":0.529411792755127,"y":0.41960784792900088,"z":0.13725490868091584,"w":1.0},{"x":0.27450981736183169,"y":0.5529412031173706,"z":0.3529411852359772,"w":1.0},{"x":0.3921568691730499,"y":0.4117647111415863,"z":0.21960784494876862,"w":1.0},{"x":0.7450980544090271,"y":0.8509804010391235,"z":0.6470588445663452,"w":1.0},{"x":0.5647059082984924,"y":0.7686274647712708,"z":0.41960784792900088,"w":1.0},{"x":0.5098039507865906,"y":0.3960784375667572,"z":0.16470588743686677,"w":1.0},{"x":0.7686274647712708,"y":0.545098066329956,"z":0.4117647111415863,"w":1.0},{"x":0.6117647290229797,"y":0.5058823823928833,"z":0.16862745583057404,"w":1.0},{"x":0.49803921580314639,"y":0.5137255191802979,"z":0.019607843831181527,"w":1.0},{"x":0.7254902124404907,"y":0.25882354378700259,"z":0.5058823823928833,"w":1.0},{"x":0.9803921580314636,"y":0.5490196347236633,"z":0.729411780834198,"w":1.0},{"x":0.3137255012989044,"y":0.6470588445663452,"z":0.364705890417099,"w":1.0},{"x":0.572549045085907,"y":0.5607843399047852,"z":0.1411764770746231,"w":1.0},{"x":0.32549020648002627,"y":0.8117647171020508,"z":0.5490196347236633,"w":1.0},{"x":0.4627451002597809,"y":0.6000000238418579,"z":0.16470588743686677,"w":1.0},{"x":0.10588235408067703,"y":0.43529412150382998,"z":0.6117647290229797,"w":1.0},{"x":0.3450980484485626,"y":0.3686274588108063,"z":0.3176470696926117,"w":1.0},{"x":0.6117647290229797,"y":0.5215686559677124,"z":0.1725490242242813,"w":1.0},{"x":0.43921568989753725,"y":0.2980392277240753,"z":0.3294117748737335,"w":1.0},{"x":0.20000000298023225,"y":0.7098039388656616,"z":0.5647059082984924,"w":1.0},{"x":0.6823529601097107,"y":0.4156862795352936,"z":0.30588236451148989,"w":1.0},{"x":0.35686275362968447,"y":0.7372549176216126,"z":0.42352941632270815,"w":1.0},{"x":0.37254902720451357,"y":0.729411780834198,"z":0.4000000059604645,"w":1.0},{"x":0.2862745225429535,"y":0.8941176533699036,"z":0.6823529601097107,"w":1.0},{"x":0.48627451062202456,"y":0.5176470875740051,"z":0.03921568766236305,"w":1.0},{"x":0.7921568751335144,"y":0.14901961386203767,"z":0.6941176652908325,"w":1.0},{"x":0.6823529601097107,"y":0.7098039388656616,"z":0.42352941632270815,"w":1.0},{"x":0.6235294342041016,"y":0.27450981736183169,"z":0.4000000059604645,"w":1.0},{"x":0.7333333492279053,"y":0.3843137323856354,"z":0.3960784375667572,"w":1.0},{"x":0.9333333373069763,"y":0.6549019813537598,"z":0.6980392336845398,"w":1.0},{"x":0.3176470696926117,"y":0.38823530077934267,"z":0.3333333432674408,"w":1.0},{"x":0.46666666865348818,"y":0.9098039269447327,"z":0.6235294342041016,"w":1.0},{"x":0.6196078658103943,"y":0.2862745225429535,"z":0.37254902720451357,"w":1.0},{"x":0.4431372582912445,"y":0.4941176474094391,"z":0.09019608050584793,"w":1.0},{"x":0.46666666865348818,"y":0.20392157137393952,"z":0.4588235318660736,"w":1.0},{"x":0.5215686559677124,"y":0.5882353186607361,"z":0.13725490868091584,"w":1.0},{"x":0.32156863808631899,"y":0.6627451181411743,"z":0.3686274588108063,"w":1.0},{"x":0.6000000238418579,"y":0.6039215922355652,"z":0.21960784494876862,"w":1.0},{"x":0.5568627715110779,"y":0.572549045085907,"z":0.1411764770746231,"w":1.0},{"x":0.7529411911964417,"y":0.7372549176216126,"z":0.5254902243614197,"w":1.0},{"x":0.48235294222831728,"y":0.43921568989753725,"z":0.10588235408067703,"w":1.0},{"x":0.5333333611488342,"y":0.6549019813537598,"z":0.239215686917305,"w":1.0},{"x":0.7215686440467835,"y":0.5333333611488342,"z":0.33725491166114809,"w":1.0},{"x":0.4588235318660736,"y":0.4313725531101227,"z":0.12941177189350129,"w":1.0},{"x":0.4627451002597809,"y":0.8901960849761963,"z":0.5960784554481506,"w":1.0},{"x":0.7960784435272217,"y":0.05098039284348488,"z":0.8196078538894653,"w":1.0},{"x":0.32156863808631899,"y":0.3294117748737335,"z":0.3803921639919281,"w":1.0},{"x":0.4588235318660736,"y":0.5058823823928833,"z":0.07058823853731156,"w":1.0},{"x":0.16862745583057404,"y":0.23529411852359773,"z":0.6509804129600525,"w":1.0},{"x":0.5764706134796143,"y":0.27843138575553896,"z":0.3607843220233917,"w":1.0},{"x":0.14509804546833039,"y":0.0941176488995552,"z":0.8274509906768799,"w":1.0},{"x":0.6039215922355652,"y":0.34117648005485537,"z":0.29411765933036806,"w":1.0},{"x":0.5372549295425415,"y":0.7176470756530762,"z":0.3333333432674408,"w":1.0},{"x":0.572549045085907,"y":0.3490196168422699,"z":0.25882354378700259,"w":1.0},{"x":0.615686297416687,"y":0.5176470875740051,"z":0.1764705926179886,"w":1.0},{"x":0.572549045085907,"y":0.08235294371843338,"z":0.6470588445663452,"w":1.0},{"x":0.2705882489681244,"y":0.7215686440467835,"z":0.48627451062202456,"w":1.0},{"x":0.4431372582912445,"y":0.3686274588108063,"z":0.2235294133424759,"w":1.0},{"x":0.572549045085907,"y":0.5411764979362488,"z":0.125490203499794,"w":1.0},{"x":0.6431372761726379,"y":0.3960784375667572,"z":0.2705882489681244,"w":1.0},{"x":0.6352941393852234,"y":0.125490203499794,"z":0.6117647290229797,"w":1.0},{"x":0.4431372582912445,"y":0.34117648005485537,"z":0.26274511218070986,"w":1.0},{"x":0.5803921818733215,"y":0.3450980484485626,"z":0.2705882489681244,"w":1.0},{"x":0.4156862795352936,"y":0.5529412031173706,"z":0.1568627506494522,"w":1.0},{"x":0.35686275362968447,"y":0.6039215922355652,"z":0.27450981736183169,"w":1.0},{"x":0.4901960790157318,"y":0.5137255191802979,"z":0.027450980618596078,"w":1.0},{"x":0.6745098233222961,"y":0.6117647290229797,"z":0.3137255012989044,"w":1.0},{"x":0.5058823823928833,"y":0.37254902720451357,"z":0.20000000298023225,"w":1.0},{"x":0.6941176652908325,"y":0.30588236451148989,"z":0.4156862795352936,"w":1.0},{"x":0.4588235318660736,"y":0.5686274766921997,"z":0.12156862765550614,"w":1.0},{"x":0.5803921818733215,"y":0.5411764979362488,"z":0.13725490868091584,"w":1.0},{"x":0.7568627595901489,"y":0.1568627506494522,"z":0.6509804129600525,"w":1.0},{"x":0.49803921580314639,"y":0.7921568751335144,"z":0.4470588266849518,"w":1.0},{"x":0.05882352963089943,"y":0.46666666865348818,"z":0.6745098233222961,"w":1.0},{"x":0.5058823823928833,"y":0.4627451002597809,"z":0.062745101749897,"w":1.0},{"x":0.7098039388656616,"y":0.5333333611488342,"z":0.32549020648002627,"w":1.0},{"x":0.48627451062202456,"y":0.33725491166114809,"z":0.2549019753932953,"w":1.0},{"x":0.7098039388656616,"y":0.16470588743686677,"z":0.6039215922355652,"w":1.0},{"x":0.3294117748737335,"y":0.6627451181411743,"z":0.3607843220233917,"w":1.0},{"x":0.4470588266849518,"y":0.6313725709915161,"z":0.21960784494876862,"w":1.0},{"x":0.43921568989753725,"y":0.8078431487083435,"z":0.4745098054409027,"w":1.0},{"x":0.32549020648002627,"y":0.7372549176216126,"z":0.4470588266849518,"w":1.0},{"x":0.5843137502670288,"y":0.41960784792900088,"z":0.1764705926179886,"w":1.0},{"x":0.6313725709915161,"y":0.3921568691730499,"z":0.25882354378700259,"w":1.0},{"x":0.5215686559677124,"y":0.34117648005485537,"z":0.250980406999588,"w":1.0},{"x":0.16470588743686677,"y":0.8078431487083435,"z":0.6941176652908325,"w":1.0},{"x":0.35686275362968447,"y":0.37254902720451357,"z":0.2980392277240753,"w":1.0},{"x":0.49803921580314639,"y":0.3607843220233917,"z":0.21960784494876862,"w":1.0},{"x":0.6705882549285889,"y":0.8392156958580017,"z":0.572549045085907,"w":1.0},{"x":0.26274511218070986,"y":0.3137255012989044,"z":0.4627451002597809,"w":1.0},{"x":0.6000000238418579,"y":0.5333333611488342,"z":0.1568627506494522,"w":1.0},{"x":0.6235294342041016,"y":0.20392157137393952,"z":0.4941176474094391,"w":1.0},{"x":0.46666666865348818,"y":0.4745098054409027,"z":0.06666667014360428,"w":1.0},{"x":0.7333333492279053,"y":0.5803921818733215,"z":0.3764705955982208,"w":1.0},{"x":0.42352941632270815,"y":0.7176470756530762,"z":0.3490196168422699,"w":1.0},{"x":0.2980392277240753,"y":0.4901960790157318,"z":0.3137255012989044,"w":1.0},{"x":0.572549045085907,"y":0.45098039507865908,"z":0.13725490868091584,"w":1.0},{"x":0.5607843399047852,"y":0.24313725531101228,"z":0.40784314274787905,"w":1.0},{"x":0.3960784375667572,"y":0.529411792755127,"z":0.16862745583057404,"w":1.0},{"x":0.5764706134796143,"y":0.3333333432674408,"z":0.2823529541492462,"w":1.0},{"x":0.5803921818733215,"y":0.729411780834198,"z":0.3686274588108063,"w":1.0},{"x":0.24705882370471955,"y":0.5803921818733215,"z":0.40392157435417178,"w":1.0},{"x":0.3843137323856354,"y":0.6352941393852234,"z":0.2705882489681244,"w":1.0},{"x":0.250980406999588,"y":0.5333333611488342,"z":0.3843137323856354,"w":1.0},{"x":0.5058823823928833,"y":0.6901960968971252,"z":0.29019609093666079,"w":1.0},{"x":0.3803921639919281,"y":0.7019608020782471,"z":0.35686275362968447,"w":1.0},{"x":0.7333333492279053,"y":0.32156863808631899,"z":0.45098039507865908,"w":1.0},{"x":0.5529412031173706,"y":0.43921568989753725,"z":0.125490203499794,"w":1.0},{"x":0.6745098233222961,"y":0.41960784792900088,"z":0.29411765933036806,"w":1.0},{"x":0.47843137383461,"y":0.6196078658103943,"z":0.18431372940540315,"w":1.0},{"x":0.19607843458652497,"y":0.7254902124404907,"z":0.5764706134796143,"w":1.0},{"x":0.6039215922355652,"y":0.4470588266849518,"z":0.18039216101169587,"w":1.0},{"x":0.27843138575553896,"y":0.6431372761726379,"z":0.40392157435417178,"w":1.0},{"x":0.5333333611488342,"y":0.5529412031173706,"z":0.0941176488995552,"w":1.0},{"x":0.7019608020782471,"y":0.2705882489681244,"z":0.47058823704719546,"w":1.0},{"x":0.4117647111415863,"y":0.6274510025978088,"z":0.239215686917305,"w":1.0},{"x":0.6745098233222961,"y":0.04313725605607033,"z":0.7450980544090271,"w":1.0},{"x":0.3450980484485626,"y":0.7686274647712708,"z":0.4745098054409027,"w":1.0},{"x":0.5921568870544434,"y":0.615686297416687,"z":0.21960784494876862,"w":1.0},{"x":0.3019607961177826,"y":0.572549045085907,"z":0.3294117748737335,"w":1.0},{"x":0.658823549747467,"y":0.46666666865348818,"z":0.24705882370471955,"w":1.0},{"x":0.364705890417099,"y":0.5490196347236633,"z":0.2235294133424759,"w":1.0},{"x":0.6117647290229797,"y":0.6431372761726379,"z":0.27450981736183169,"w":1.0},{"x":0.5764706134796143,"y":0.5607843399047852,"z":0.14901961386203767,"w":1.0},{"x":0.5372549295425415,"y":0.529411792755127,"z":0.07058823853731156,"w":1.0},{"x":0.43921568989753725,"y":0.9607843160629273,"z":0.7058823704719544,"w":1.0},{"x":0.6039215922355652,"y":0.4000000059604645,"z":0.21960784494876862,"w":1.0},{"x":0.4000000059604645,"y":0.658823549747467,"z":0.29019609093666079,"w":1.0},{"x":0.3686274588108063,"y":0.2549019753932953,"z":0.4313725531101227,"w":1.0},{"x":0.5411764979362488,"y":0.6313725709915161,"z":0.2078431397676468,"w":1.0},{"x":0.239215686917305,"y":0.5333333611488342,"z":0.40392157435417178,"w":1.0},{"x":0.48627451062202456,"y":0.5098039507865906,"z":0.027450980618596078,"w":1.0},{"x":0.47058823704719546,"y":0.7882353067398071,"z":0.43921568989753725,"w":1.0},{"x":0.5686274766921997,"y":0.3843137323856354,"z":0.2078431397676468,"w":1.0},{"x":0.25882354378700259,"y":0.6039215922355652,"z":0.4000000059604645,"w":1.0},{"x":0.5137255191802979,"y":0.5843137502670288,"z":0.13333334028720857,"w":1.0},{"x":0.6980392336845398,"y":0.2980392277240753,"z":0.4313725531101227,"w":1.0},{"x":0.21176470816135407,"y":0.2549019753932953,"z":0.5803921818733215,"w":1.0},{"x":0.4431372582912445,"y":0.615686297416687,"z":0.19607843458652497,"w":1.0},{"x":0.3803921639919281,"y":0.5098039507865906,"z":0.1882352977991104,"w":1.0},{"x":0.45098039507865908,"y":0.6117647290229797,"z":0.1882352977991104,"w":1.0},{"x":0.5843137502670288,"y":0.3333333432674408,"z":0.2862745225429535,"w":1.0},{"x":0.250980406999588,"y":0.47843137383461,"z":0.3843137323856354,"w":1.0},{"x":0.6745098233222961,"y":0.48627451062202456,"z":0.26274511218070986,"w":1.0},{"x":0.48627451062202456,"y":0.5137255191802979,"z":0.03529411926865578,"w":1.0},{"x":0.3294117748737335,"y":0.3529411852359772,"z":0.3450980484485626,"w":1.0},{"x":0.7490196228027344,"y":0.6235294342041016,"z":0.41960784792900088,"w":1.0},{"x":0.529411792755127,"y":0.8392156958580017,"z":0.5176470875740051,"w":1.0},{"x":0.5176470875740051,"y":0.615686297416687,"z":0.1764705926179886,"w":1.0},{"x":0.4000000059604645,"y":0.43529412150382998,"z":0.1882352977991104,"w":1.0},{"x":0.5372549295425415,"y":0.4588235318660736,"z":0.09019608050584793,"w":1.0},{"x":0.615686297416687,"y":0.8705882430076599,"z":0.5882353186607361,"w":1.0},{"x":0.7411764860153198,"y":0.6509804129600525,"z":0.4313725531101227,"w":1.0},{"x":0.545098066329956,"y":0.7176470756530762,"z":0.33725491166114809,"w":1.0},{"x":0.4470588266849518,"y":0.8156862854957581,"z":0.48627451062202456,"w":1.0},{"x":0.3176470696926117,"y":0.45490196347236636,"z":0.29411765933036806,"w":1.0},{"x":0.3529411852359772,"y":0.3019607961177826,"z":0.3843137323856354,"w":1.0},{"x":0.0784313753247261,"y":0.32156863808631899,"z":0.7058823704719544,"w":1.0},{"x":0.22745098173618318,"y":0.5529412031173706,"z":0.4274509847164154,"w":1.0},{"x":0.5647059082984924,"y":0.5647059082984924,"z":0.13333334028720857,"w":1.0},{"x":0.6431372761726379,"y":0.6941176652908325,"z":0.3686274588108063,"w":1.0},{"x":0.43921568989753725,"y":0.40392157435417178,"z":0.18039216101169587,"w":1.0},{"x":0.43921568989753725,"y":0.37254902720451357,"z":0.21960784494876862,"w":1.0},{"x":0.47843137383461,"y":0.6196078658103943,"z":0.18431372940540315,"w":1.0},{"x":0.5176470875740051,"y":0.5411764979362488,"z":0.06666667014360428,"w":1.0},{"x":0.7686274647712708,"y":0.1921568661928177,"z":0.6274510025978088,"w":1.0},{"x":0.13333334028720857,"y":0.6509804129600525,"z":0.6078431606292725,"w":1.0},{"x":0.5882353186607361,"y":0.09803921729326248,"z":0.6274510025978088,"w":1.0},{"x":0.20000000298023225,"y":0.7019608020782471,"z":0.5490196347236633,"w":1.0},{"x":0.6392157077789307,"y":0.2078431397676468,"z":0.49803921580314639,"w":1.0},{"x":0.6039215922355652,"y":0.5843137502670288,"z":0.20392157137393952,"w":1.0},{"x":0.7529411911964417,"y":0.3960784375667572,"z":0.4156862795352936,"w":1.0},{"x":0.3176470696926117,"y":0.3843137323856354,"z":0.33725491166114809,"w":1.0},{"x":0.38823530077934267,"y":0.5960784554481506,"z":0.22745098173618318,"w":1.0},{"x":0.3803921639919281,"y":0.6117647290229797,"z":0.250980406999588,"w":1.0},{"x":0.6470588445663452,"y":0.7647058963775635,"z":0.4588235318660736,"w":1.0},{"x":0.3686274588108063,"y":0.4000000059604645,"z":0.2549019753932953,"w":1.0},{"x":0.19607843458652497,"y":0.5882353186607361,"z":0.48627451062202456,"w":1.0},{"x":0.6549019813537598,"y":0.7176470756530762,"z":0.40784314274787905,"w":1.0},{"x":0.6431372761726379,"y":0.6196078658103943,"z":0.2823529541492462,"w":1.0},{"x":0.3333333432674408,"y":0.3803921639919281,"z":0.3137255012989044,"w":1.0},{"x":0.6627451181411743,"y":0.5921568870544434,"z":0.2823529541492462,"w":1.0},{"x":0.5058823823928833,"y":0.47843137383461,"z":0.04313725605607033,"w":1.0},{"x":0.6941176652908325,"y":0.8235294222831726,"z":0.572549045085907,"w":1.0},{"x":0.1921568661928177,"y":0.6235294342041016,"z":0.5058823823928833,"w":1.0},{"x":0.29019609093666079,"y":0.5411764979362488,"z":0.3294117748737335,"w":1.0},{"x":0.8117647171020508,"y":0.6470588445663452,"z":0.5215686559677124,"w":1.0},{"x":0.5372549295425415,"y":0.21176470816135407,"z":0.45098039507865908,"w":1.0},{"x":0.10980392247438431,"y":0.3921568691730499,"z":0.6196078658103943,"w":1.0},{"x":0.5647059082984924,"y":0.4588235318660736,"z":0.11764705926179886,"w":1.0},{"x":0.38823530077934267,"y":0.45098039507865908,"z":0.1921568661928177,"w":1.0},{"x":0.6196078658103943,"y":0.5176470875740051,"z":0.18431372940540315,"w":1.0},{"x":0.6705882549285889,"y":0.7490196228027344,"z":0.45490196347236636,"w":1.0},{"x":0.25882354378700259,"y":0.3294117748737335,"z":0.45490196347236636,"w":1.0},{"x":0.4274509847164154,"y":0.7137255072593689,"z":0.3450980484485626,"w":1.0},{"x":0.7803921699523926,"y":0.33725491166114809,"z":0.4941176474094391,"w":1.0},{"x":0.4470588266849518,"y":0.37254902720451357,"z":0.21568627655506135,"w":1.0},{"x":0.5254902243614197,"y":0.5803921818733215,"z":0.12941177189350129,"w":1.0},{"x":0.40784314274787905,"y":0.615686297416687,"z":0.22745098173618318,"w":1.0},{"x":0.47843137383461,"y":0.5529412031173706,"z":0.08627451211214066,"w":1.0},{"x":0.43921568989753725,"y":0.6392157077789307,"z":0.23529411852359773,"w":1.0},{"x":0.5647059082984924,"y":0.545098066329956,"z":0.11764705926179886,"w":1.0},{"x":0.6431372761726379,"y":0.250980406999588,"z":0.43921568989753725,"w":1.0},{"x":0.6823529601097107,"y":0.545098066329956,"z":0.2823529541492462,"w":1.0},{"x":0.5058823823928833,"y":0.6509804129600525,"z":0.22745098173618318,"w":1.0},{"x":0.5254902243614197,"y":0.2862745225429535,"z":0.3333333432674408,"w":1.0},{"x":0.8509804010391235,"y":0.33725491166114809,"z":0.5921568870544434,"w":1.0},{"x":0.40784314274787905,"y":0.41960784792900088,"z":0.1921568661928177,"w":1.0},{"x":0.6078431606292725,"y":0.30980393290519717,"z":0.33725491166114809,"w":1.0},{"x":0.6078431606292725,"y":0.6431372761726379,"z":0.27450981736183169,"w":1.0},{"x":0.529411792755127,"y":0.7529411911964417,"z":0.38823530077934267,"w":1.0},{"x":0.24313725531101228,"y":0.1921568661928177,"z":0.615686297416687,"w":1.0},{"x":0.37254902720451357,"y":0.3803921639919281,"z":0.2705882489681244,"w":1.0},{"x":0.7098039388656616,"y":0.26274511218070986,"z":0.48627451062202456,"w":1.0},{"x":0.5098039507865906,"y":0.5372549295425415,"z":0.054901961237192157,"w":1.0},{"x":0.48627451062202456,"y":0.7647058963775635,"z":0.40392157435417178,"w":1.0},{"x":0.5058823823928833,"y":0.1568627506494522,"z":0.529411792755127,"w":1.0},{"x":0.6039215922355652,"y":0.40784314274787905,"z":0.21568627655506135,"w":1.0},{"x":0.7333333492279053,"y":0.47058823704719546,"z":0.3607843220233917,"w":1.0},{"x":0.4745098054409027,"y":0.572549045085907,"z":0.11764705926179886,"w":1.0},{"x":0.3960784375667572,"y":0.3921568691730499,"z":0.23529411852359773,"w":1.0},{"x":0.7803921699523926,"y":0.5960784554481506,"z":0.4470588266849518,"w":1.0},{"x":0.5960784554481506,"y":0.48627451062202456,"z":0.14509804546833039,"w":1.0},{"x":0.7607843279838562,"y":0.8392156958580017,"z":0.6509804129600525,"w":1.0},{"x":0.364705890417099,"y":0.3176470696926117,"z":0.3529411852359772,"w":1.0},{"x":0.8117647171020508,"y":0.9490196108818054,"z":0.8274509906768799,"w":1.0},{"x":0.4588235318660736,"y":0.8078431487083435,"z":0.47058823704719546,"w":1.0},{"x":0.6549019813537598,"y":0.47843137383461,"z":0.239215686917305,"w":1.0},{"x":0.27843138575553896,"y":0.6980392336845398,"z":0.45490196347236636,"w":1.0},{"x":0.572549045085907,"y":0.49803921580314639,"z":0.10980392247438431,"w":1.0},{"x":0.4588235318660736,"y":0.364705890417099,"z":0.21960784494876862,"w":1.0},{"x":0.12156862765550614,"y":0.5137255191802979,"z":0.5843137502670288,"w":1.0},{"x":0.01568627543747425,"y":0.14901961386203767,"z":0.9137254953384399,"w":1.0},{"x":0.6470588445663452,"y":0.45098039507865908,"z":0.23529411852359773,"w":1.0},{"x":0.33725491166114809,"y":0.5333333611488342,"z":0.2549019753932953,"w":1.0},{"x":0.3490196168422699,"y":0.24313725531101228,"z":0.4588235318660736,"w":1.0},{"x":0.48235294222831728,"y":0.5098039507865906,"z":0.03529411926865578,"w":1.0},{"x":0.5137255191802979,"y":0.5215686559677124,"z":0.03921568766236305,"w":1.0},{"x":0.5960784554481506,"y":0.4274509847164154,"z":0.18431372940540315,"w":1.0},{"x":0.3803921639919281,"y":0.2078431397676468,"z":0.48627451062202456,"w":1.0},{"x":0.6117647290229797,"y":0.886274516582489,"z":0.6078431606292725,"w":1.0},{"x":0.7372549176216126,"y":0.5568627715110779,"z":0.37254902720451357,"w":1.0},{"x":0.529411792755127,"y":0.49803921580314639,"z":0.0470588244497776,"w":1.0},{"x":0.20392157137393952,"y":0.30980393290519717,"z":0.5411764979362488,"w":1.0},{"x":0.3450980484485626,"y":0.6666666865348816,"z":0.3490196168422699,"w":1.0},{"x":0.6039215922355652,"y":0.6196078658103943,"z":0.239215686917305,"w":1.0},{"x":0.5254902243614197,"y":0.43529412150382998,"z":0.10980392247438431,"w":1.0},{"x":0.43921568989753725,"y":0.47843137383461,"z":0.10588235408067703,"w":1.0},{"x":0.38823530077934267,"y":0.3686274588108063,"z":0.2666666805744171,"w":1.0},{"x":0.35686275362968447,"y":0.615686297416687,"z":0.2823529541492462,"w":1.0},{"x":0.1921568661928177,"y":1.0,"z":0.8980392217636108,"w":1.0},{"x":0.45490196347236636,"y":0.6000000238418579,"z":0.16862745583057404,"w":1.0},{"x":0.5686274766921997,"y":0.5803921818733215,"z":0.1568627506494522,"w":1.0},{"x":0.47058823704719546,"y":0.40392157435417178,"z":0.1568627506494522,"w":1.0},{"x":0.8666666746139526,"y":0.3607843220233917,"z":0.6000000238418579,"w":1.0},{"x":0.8588235378265381,"y":0.4313725531101227,"z":0.5568627715110779,"w":1.0},{"x":0.800000011920929,"y":0.5215686559677124,"z":0.45490196347236636,"w":1.0},{"x":0.7529411911964417,"y":0.3764705955982208,"z":0.4274509847164154,"w":1.0},{"x":0.1725490242242813,"y":0.03529411926865578,"z":0.8666666746139526,"w":1.0},{"x":0.7647058963775635,"y":0.5490196347236633,"z":0.40784314274787905,"w":1.0},{"x":0.4941176474094391,"y":0.5137255191802979,"z":0.0235294122248888,"w":1.0},{"x":0.6313725709915161,"y":0.43529412150382998,"z":0.2235294133424759,"w":1.0},{"x":0.2235294133424759,"y":0.48235294222831728,"z":0.4274509847164154,"w":1.0},{"x":0.5647059082984924,"y":0.41960784792900088,"z":0.16078431904315949,"w":1.0},{"x":0.8509804010391235,"y":0.5254902243614197,"z":0.5333333611488342,"w":1.0},{"x":0.34117648005485537,"y":0.7098039388656616,"z":0.40392157435417178,"w":1.0},{"x":0.7529411911964417,"y":0.6705882549285889,"z":0.4588235318660736,"w":1.0},{"x":0.34117648005485537,"y":0.5764706134796143,"z":0.2705882489681244,"w":1.0},{"x":0.27843138575553896,"y":0.6000000238418579,"z":0.37254902720451357,"w":1.0},{"x":0.38823530077934267,"y":0.24705882370471955,"z":0.4313725531101227,"w":1.0},{"x":0.26274511218070986,"y":0.529411792755127,"z":0.3686274588108063,"w":1.0},{"x":0.37254902720451357,"y":0.4588235318660736,"z":0.2078431397676468,"w":1.0},{"x":0.34117648005485537,"y":0.4274509847164154,"z":0.2705882489681244,"w":1.0},{"x":0.43921568989753725,"y":0.2666666805744171,"z":0.37254902720451357,"w":1.0},{"x":0.3686274588108063,"y":0.5137255191802979,"z":0.2078431397676468,"w":1.0},{"x":0.6431372761726379,"y":0.8196078538894653,"z":0.529411792755127,"w":1.0},{"x":0.5411764979362488,"y":0.5058823823928833,"z":0.06666667014360428,"w":1.0},{"x":0.7254902124404907,"y":0.4274509847164154,"z":0.3607843220233917,"w":1.0},{"x":0.33725491166114809,"y":0.7098039388656616,"z":0.40392157435417178,"w":1.0},{"x":0.7686274647712708,"y":0.6352941393852234,"z":0.45490196347236636,"w":1.0},{"x":0.6313725709915161,"y":0.5098039507865906,"z":0.20000000298023225,"w":1.0},{"x":0.6235294342041016,"y":0.27843138575553896,"z":0.3921568691730499,"w":1.0},{"x":0.2666666805744171,"y":0.3294117748737335,"z":0.4470588266849518,"w":1.0},{"x":0.46666666865348818,"y":0.4313725531101227,"z":0.12156862765550614,"w":1.0},{"x":0.5372549295425415,"y":0.3803921639919281,"z":0.19607843458652497,"w":1.0},{"x":0.4000000059604645,"y":0.40784314274787905,"z":0.21568627655506135,"w":1.0},{"x":0.23529411852359773,"y":0.3333333432674408,"z":0.48235294222831728,"w":1.0},{"x":0.5647059082984924,"y":0.46666666865348818,"z":0.11372549086809159,"w":1.0},{"x":0.5686274766921997,"y":0.6941176652908325,"z":0.30980393290519717,"w":1.0},{"x":0.06666667014360428,"y":0.24705882370471955,"z":0.7686274647712708,"w":1.0},{"x":0.3686274588108063,"y":0.5686274766921997,"z":0.22745098173618318,"w":1.0},{"x":0.5137255191802979,"y":0.5215686559677124,"z":0.03921568766236305,"w":1.0},{"x":0.18039216101169587,"y":0.43921568989753725,"z":0.49803921580314639,"w":1.0},{"x":0.239215686917305,"y":0.5176470875740051,"z":0.4000000059604645,"w":1.0},{"x":0.4588235318660736,"y":0.4745098054409027,"z":0.08235294371843338,"w":1.0},{"x":0.7019608020782471,"y":0.7215686440467835,"z":0.45098039507865908,"w":1.0},{"x":0.545098066329956,"y":0.7568627595901489,"z":0.3960784375667572,"w":1.0},{"x":0.5058823823928833,"y":0.529411792755127,"z":0.04313725605607033,"w":1.0},{"x":0.4156862795352936,"y":0.7411764860153198,"z":0.38823530077934267,"w":1.0},{"x":0.007843137718737126,"y":0.2862745225429535,"z":0.8196078538894653,"w":1.0},{"x":0.8274509906768799,"y":0.8470588326454163,"z":0.7254902124404907,"w":1.0},{"x":0.5843137502670288,"y":0.6823529601097107,"z":0.3019607961177826,"w":1.0},{"x":0.007843137718737126,"y":0.7254902124404907,"z":0.8274509906768799,"w":1.0},{"x":0.5176470875740051,"y":0.800000011920929,"z":0.4588235318660736,"w":1.0},{"x":0.21176470816135407,"y":0.615686297416687,"z":0.4745098054409027,"w":1.0},{"x":0.6078431606292725,"y":0.4627451002597809,"z":0.1725490242242813,"w":1.0},{"x":0.6823529601097107,"y":0.35686275362968447,"z":0.3529411852359772,"w":1.0},{"x":0.6549019813537598,"y":0.3764705955982208,"z":0.30588236451148989,"w":1.0},{"x":0.5960784554481506,"y":0.7254902124404907,"z":0.37254902720451357,"w":1.0},{"x":0.5098039507865906,"y":0.5372549295425415,"z":0.054901961237192157,"w":1.0},{"x":0.5372549295425415,"y":0.9607843160629273,"z":0.7019608020782471,"w":1.0},{"x":0.6117647290229797,"y":0.26274511218070986,"z":0.40392157435417178,"w":1.0},{"x":0.34117648005485537,"y":0.41960784792900088,"z":0.27450981736183169,"w":1.0},{"x":0.6000000238418579,"y":0.6549019813537598,"z":0.27843138575553896,"w":1.0},{"x":0.545098066329956,"y":0.800000011920929,"z":0.4588235318660736,"w":1.0},{"x":0.6078431606292725,"y":0.3921568691730499,"z":0.23137255012989045,"w":1.0},{"x":0.35686275362968447,"y":0.10980392247438431,"z":0.6392157077789307,"w":1.0},{"x":0.4117647111415863,"y":0.3333333432674408,"z":0.29019609093666079,"w":1.0},{"x":0.21176470816135407,"y":0.3843137323856354,"z":0.47843137383461,"w":1.0},{"x":0.7960784435272217,"y":0.5215686559677124,"z":0.45490196347236636,"w":1.0},{"x":0.886274516582489,"y":0.4431372582912445,"z":0.5960784554481506,"w":1.0},{"x":0.05882352963089943,"y":0.8705882430076599,"z":0.8784313797950745,"w":1.0},{"x":1.0,"y":0.4941176474094391,"z":0.7607843279838562,"w":1.0},{"x":0.32156863808631899,"y":0.3137255012989044,"z":0.4000000059604645,"w":1.0},{"x":0.1411764770746231,"y":0.4000000059604645,"z":0.572549045085907,"w":1.0},{"x":0.3176470696926117,"y":0.8666666746139526,"z":0.6235294342041016,"w":1.0},{"x":0.772549033164978,"y":0.45098039507865908,"z":0.41960784792900088,"w":1.0},{"x":0.8941176533699036,"y":0.615686297416687,"z":0.6196078658103943,"w":1.0},{"x":0.7333333492279053,"y":0.4941176474094391,"z":0.35686275362968447,"w":1.0},{"x":0.16470588743686677,"y":0.9333333373069763,"z":0.8352941274642944,"w":1.0},{"x":0.5411764979362488,"y":0.8352941274642944,"z":0.5098039507865906,"w":1.0},{"x":0.529411792755127,"y":0.3764705955982208,"z":0.20000000298023225,"w":1.0},{"x":0.6901960968971252,"y":0.545098066329956,"z":0.29411765933036806,"w":1.0},{"x":0.6352941393852234,"y":0.8117647171020508,"z":0.5137255191802979,"w":1.0},{"x":0.49803921580314639,"y":0.6039215922355652,"z":0.1568627506494522,"w":1.0},{"x":0.6509804129600525,"y":0.4627451002597809,"z":0.239215686917305,"w":1.0},{"x":0.5490196347236633,"y":0.4745098054409027,"z":0.08627451211214066,"w":1.0},{"x":0.37254902720451357,"y":0.6352941393852234,"z":0.2862745225429535,"w":1.0},{"x":0.3490196168422699,"y":0.9254902005195618,"z":0.686274528503418,"w":1.0},{"x":0.772549033164978,"y":0.6196078658103943,"z":0.45098039507865908,"w":1.0},{"x":0.5764706134796143,"y":0.47843137383461,"z":0.12156862765550614,"w":1.0},{"x":0.5411764979362488,"y":0.33725491166114809,"z":0.25882354378700259,"w":1.0},{"x":0.5803921818733215,"y":0.30980393290519717,"z":0.32156863808631899,"w":1.0},{"x":0.6274510025978088,"y":0.12156862765550614,"z":0.615686297416687,"w":1.0},{"x":0.6549019813537598,"y":0.35686275362968447,"z":0.32156863808631899,"w":1.0},{"x":0.5176470875740051,"y":0.501960813999176,"z":0.027450980618596078,"w":1.0},{"x":0.3843137323856354,"y":0.47058823704719546,"z":0.1882352977991104,"w":1.0},{"x":0.6039215922355652,"y":0.615686297416687,"z":0.23529411852359773,"w":1.0},{"x":0.9490196108818054,"y":0.027450980618596078,"z":0.9921568632125855,"w":1.0},{"x":0.3843137323856354,"y":0.1921568661928177,"z":0.5058823823928833,"w":1.0},{"x":0.25882354378700259,"y":0.658823549747467,"z":0.4431372582912445,"w":1.0},{"x":0.572549045085907,"y":0.2862745225429535,"z":0.3490196168422699,"w":1.0},{"x":0.5137255191802979,"y":0.5843137502670288,"z":0.12941177189350129,"w":1.0},{"x":0.37254902720451357,"y":0.7568627595901489,"z":0.43921568989753725,"w":1.0},{"x":0.5764706134796143,"y":0.3960784375667572,"z":0.19607843458652497,"w":1.0},{"x":0.20000000298023225,"y":0.15294118225574494,"z":0.7019608020782471,"w":1.0},{"x":0.5137255191802979,"y":0.48235294222831728,"z":0.03529411926865578,"w":1.0},{"x":0.7450980544090271,"y":0.7215686440467835,"z":0.49803921580314639,"w":1.0},{"x":0.6274510025978088,"y":0.6431372761726379,"z":0.29019609093666079,"w":1.0},{"x":0.529411792755127,"y":0.48235294222831728,"z":0.05882352963089943,"w":1.0},{"x":0.37254902720451357,"y":0.6431372761726379,"z":0.29411765933036806,"w":1.0},{"x":0.5882353186607361,"y":0.12156862765550614,"z":0.5960784554481506,"w":1.0},{"x":0.545098066329956,"y":0.6509804129600525,"z":0.24313725531101228,"w":1.0},{"x":0.47058823704719546,"y":0.5254902243614197,"z":0.062745101749897,"w":1.0},{"x":0.5372549295425415,"y":0.6823529601097107,"z":0.2823529541492462,"w":1.0},{"x":0.6549019813537598,"y":0.43921568989753725,"z":0.2549019753932953,"w":1.0},{"x":0.615686297416687,"y":0.5529412031173706,"z":0.1882352977991104,"w":1.0},{"x":0.6941176652908325,"y":0.8274509906768799,"z":0.5764706134796143,"w":1.0},{"x":0.6352941393852234,"y":0.5490196347236633,"z":0.21568627655506135,"w":1.0},{"x":0.49803921580314639,"y":0.5960784554481506,"z":0.14509804546833039,"w":1.0},{"x":0.054901961237192157,"y":0.6274510025978088,"z":0.7058823704719544,"w":1.0},{"x":0.7411764860153198,"y":0.658823549747467,"z":0.43921568989753725,"w":1.0},{"x":0.29411765933036806,"y":0.4000000059604645,"z":0.3529411852359772,"w":1.0},{"x":0.22745098173618318,"y":0.29019609093666079,"z":0.529411792755127,"w":1.0},{"x":0.5176470875740051,"y":0.615686297416687,"z":0.18039216101169587,"w":1.0},{"x":0.501960813999176,"y":0.3529411852359772,"z":0.23137255012989045,"w":1.0},{"x":0.3294117748737335,"y":0.5176470875740051,"z":0.2666666805744171,"w":1.0},{"x":0.6235294342041016,"y":0.43529412150382998,"z":0.21176470816135407,"w":1.0},{"x":0.7254902124404907,"y":0.49803921580314639,"z":0.3450980484485626,"w":1.0},{"x":0.8666666746139526,"y":0.5686274766921997,"z":0.5647059082984924,"w":1.0},{"x":0.572549045085907,"y":0.37254902720451357,"z":0.23137255012989045,"w":1.0},{"x":0.3333333432674408,"y":0.46666666865348818,"z":0.2666666805744171,"w":1.0},{"x":0.48627451062202456,"y":0.5058823823928833,"z":0.027450980618596078,"w":1.0},{"x":0.22745098173618318,"y":0.5686274766921997,"z":0.4313725531101227,"w":1.0},{"x":0.4627451002597809,"y":0.5803921818733215,"z":0.13725490868091584,"w":1.0},{"x":0.4470588266849518,"y":0.5333333611488342,"z":0.10196078568696976,"w":1.0},{"x":0.6470588445663452,"y":0.6235294342041016,"z":0.29411765933036806,"w":1.0},{"x":0.5529412031173706,"y":0.4313725531101227,"z":0.13725490868091584,"w":1.0},{"x":0.24705882370471955,"y":0.7254902124404907,"z":0.5176470875740051,"w":1.0},{"x":0.6196078658103943,"y":0.545098066329956,"z":0.19607843458652497,"w":1.0},{"x":0.5568627715110779,"y":0.501960813999176,"z":0.08235294371843338,"w":1.0},{"x":0.239215686917305,"y":0.7333333492279053,"z":0.5372549295425415,"w":1.0},{"x":0.45098039507865908,"y":0.9137254953384399,"z":0.6352941393852234,"w":1.0},{"x":0.4274509847164154,"y":0.529411792755127,"z":0.125490203499794,"w":1.0},{"x":0.4274509847164154,"y":0.3686274588108063,"z":0.239215686917305,"w":1.0},{"x":0.007843137718737126,"y":0.19607843458652497,"z":0.886274516582489,"w":1.0},{"x":0.4588235318660736,"y":0.5333333611488342,"z":0.08627451211214066,"w":1.0},{"x":0.4627451002597809,"y":0.47058823704719546,"z":0.08235294371843338,"w":1.0},{"x":0.1921568661928177,"y":0.5843137502670288,"z":0.4901960790157318,"w":1.0},{"x":0.46666666865348818,"y":0.5882353186607361,"z":0.1411764770746231,"w":1.0},{"x":0.18431372940540315,"y":0.5176470875740051,"z":0.4901960790157318,"w":1.0},{"x":0.5137255191802979,"y":0.7411764860153198,"z":0.3686274588108063,"w":1.0},{"x":0.6745098233222961,"y":0.4627451002597809,"z":0.27450981736183169,"w":1.0},{"x":0.35686275362968447,"y":0.5764706134796143,"z":0.24705882370471955,"w":1.0},{"x":0.4745098054409027,"y":0.6509804129600525,"z":0.23529411852359773,"w":1.0},{"x":0.5333333611488342,"y":0.4588235318660736,"z":0.08627451211214066,"w":1.0},{"x":0.20000000298023225,"y":0.5882353186607361,"z":0.47843137383461,"w":1.0},{"x":0.7254902124404907,"y":0.7176470756530762,"z":0.4745098054409027,"w":1.0},{"x":0.22745098173618318,"y":0.572549045085907,"z":0.43529412150382998,"w":1.0},{"x":0.4941176474094391,"y":0.48627451062202456,"z":0.027450980618596078,"w":1.0},{"x":0.29411765933036806,"y":0.5647059082984924,"z":0.3333333432674408,"w":1.0},{"x":0.5137255191802979,"y":0.5372549295425415,"z":0.05882352963089943,"w":1.0},{"x":0.5490196347236633,"y":0.6235294342041016,"z":0.20000000298023225,"w":1.0},{"x":0.47843137383461,"y":0.6274510025978088,"z":0.19607843458652497,"w":1.0},{"x":0.7058823704719544,"y":0.3529411852359772,"z":0.38823530077934267,"w":1.0},{"x":0.501960813999176,"y":0.3607843220233917,"z":0.21568627655506135,"w":1.0},{"x":0.03921568766236305,"y":0.5803921818733215,"z":0.7137255072593689,"w":1.0},{"x":0.5137255191802979,"y":0.21960784494876862,"z":0.4313725531101227,"w":1.0},{"x":0.5921568870544434,"y":0.8156862854957581,"z":0.49803921580314639,"w":1.0},{"x":0.2549019753932953,"y":0.501960813999176,"z":0.3764705955982208,"w":1.0},{"x":0.21960784494876862,"y":0.40784314274787905,"z":0.45490196347236636,"w":1.0},{"x":0.364705890417099,"y":0.6745098233222961,"z":0.33725491166114809,"w":1.0},{"x":0.45098039507865908,"y":0.6627451181411743,"z":0.25882354378700259,"w":1.0},{"x":0.47058823704719546,"y":0.529411792755127,"z":0.06666667014360428,"w":1.0},{"x":0.3803921639919281,"y":0.4431372582912445,"z":0.20392157137393952,"w":1.0},{"x":0.5411764979362488,"y":0.250980406999588,"z":0.38823530077934267,"w":1.0},{"x":0.800000011920929,"y":0.5098039507865906,"z":0.45490196347236636,"w":1.0},{"x":0.5215686559677124,"y":0.3960784375667572,"z":0.16470588743686677,"w":1.0},{"x":0.5803921818733215,"y":0.2235294133424759,"z":0.4431372582912445,"w":1.0},{"x":0.5568627715110779,"y":0.3764705955982208,"z":0.2078431397676468,"w":1.0},{"x":0.886274516582489,"y":0.16078431904315949,"z":0.7843137383460999,"w":1.0},{"x":0.4000000059604645,"y":0.43921568989753725,"z":0.18431372940540315,"w":1.0},{"x":0.8745098114013672,"y":0.3137255012989044,"z":0.6352941393852234,"w":1.0},{"x":0.48235294222831728,"y":0.501960813999176,"z":0.03529411926865578,"w":1.0},{"x":0.5098039507865906,"y":0.47843137383461,"z":0.03921568766236305,"w":1.0},{"x":0.3019607961177826,"y":0.6745098233222961,"z":0.40392157435417178,"w":1.0},{"x":0.08627451211214066,"y":0.34117648005485537,"z":0.6823529601097107,"w":1.0},{"x":0.5647059082984924,"y":0.5098039507865906,"z":0.10196078568696976,"w":1.0},{"x":0.26274511218070986,"y":0.7333333492279053,"z":0.5058823823928833,"w":1.0},{"x":0.5137255191802979,"y":0.7843137383460999,"z":0.43529412150382998,"w":1.0},{"x":0.41960784792900088,"y":0.5882353186607361,"z":0.18039216101169587,"w":1.0},{"x":0.45490196347236636,"y":0.6196078658103943,"z":0.19607843458652497,"w":1.0},{"x":0.7843137383460999,"y":0.729411780834198,"z":0.5529412031173706,"w":1.0},{"x":0.3450980484485626,"y":0.47843137383461,"z":0.24705882370471955,"w":1.0},{"x":0.7098039388656616,"y":0.9176470637321472,"z":0.7098039388656616,"w":1.0},{"x":0.5137255191802979,"y":0.4941176474094391,"z":0.0235294122248888,"w":1.0},{"x":0.21176470816135407,"y":0.41960784792900088,"z":0.4588235318660736,"w":1.0},{"x":0.729411780834198,"y":0.5098039507865906,"z":0.3490196168422699,"w":1.0},{"x":0.3490196168422699,"y":0.729411780834198,"z":0.4156862795352936,"w":1.0},{"x":0.4156862795352936,"y":0.2235294133424759,"z":0.4470588266849518,"w":1.0},{"x":0.37254902720451357,"y":0.6196078658103943,"z":0.2666666805744171,"w":1.0},{"x":0.6941176652908325,"y":0.6313725709915161,"z":0.3529411852359772,"w":1.0},{"x":0.8784313797950745,"y":0.7411764860153198,"z":0.6784313917160034,"w":1.0},{"x":0.9921568632125855,"y":0.29411765933036806,"z":0.8078431487083435,"w":1.0},{"x":0.364705890417099,"y":0.7058823704719544,"z":0.3764705955982208,"w":1.0},{"x":0.47843137383461,"y":0.4313725531101227,"z":0.11764705926179886,"w":1.0},{"x":0.7647058963775635,"y":0.4274509847164154,"z":0.4156862795352936,"w":1.0},{"x":0.47843137383461,"y":0.8470588326454163,"z":0.5254902243614197,"w":1.0},{"x":0.3450980484485626,"y":0.5607843399047852,"z":0.2549019753932953,"w":1.0},{"x":0.3450980484485626,"y":0.6431372761726379,"z":0.32156863808631899,"w":1.0},{"x":0.8235294222831726,"y":0.5411764979362488,"z":0.4941176474094391,"w":1.0},{"x":0.529411792755127,"y":0.38823530077934267,"z":0.18431372940540315,"w":1.0},{"x":0.7137255072593689,"y":0.7019608020782471,"z":0.4470588266849518,"w":1.0},{"x":0.4901960790157318,"y":0.7921568751335144,"z":0.4431372582912445,"w":1.0},{"x":0.9450980424880981,"y":0.33725491166114809,"z":0.7254902124404907,"w":1.0},{"x":0.5176470875740051,"y":0.364705890417099,"z":0.21176470816135407,"w":1.0},{"x":0.6745098233222961,"y":0.2980392277240753,"z":0.4117647111415863,"w":1.0},{"x":0.3019607961177826,"y":0.7176470756530762,"z":0.45098039507865908,"w":1.0},{"x":0.5764706134796143,"y":0.7803921699523926,"z":0.43921568989753725,"w":1.0},{"x":0.40392157435417178,"y":0.3803921639919281,"z":0.239215686917305,"w":1.0},{"x":0.9686274528503418,"y":0.5960784554481506,"z":0.729411780834198,"w":1.0},{"x":0.8235294222831726,"y":0.07058823853731156,"z":0.8196078538894653,"w":1.0},{"x":0.0941176488995552,"y":0.3137255012989044,"z":0.6823529601097107,"w":1.0},{"x":0.7764706015586853,"y":0.40392157435417178,"z":0.4470588266849518,"w":1.0},{"x":0.42352941632270815,"y":0.6235294342041016,"z":0.2235294133424759,"w":1.0},{"x":0.8117647171020508,"y":0.41960784792900088,"z":0.4901960790157318,"w":1.0},{"x":0.3764705955982208,"y":0.4274509847164154,"z":0.2235294133424759,"w":1.0},{"x":0.364705890417099,"y":0.29019609093666079,"z":0.3843137323856354,"w":1.0},{"x":0.7019608020782471,"y":0.32156863808631899,"z":0.4117647111415863,"w":1.0},{"x":0.4117647111415863,"y":0.5803921818733215,"z":0.18431372940540315,"w":1.0},{"x":0.7960784435272217,"y":0.47058823704719546,"z":0.45490196347236636,"w":1.0},{"x":0.5254902243614197,"y":0.4000000059604645,"z":0.16078431904315949,"w":1.0},{"x":0.4313725531101227,"y":0.9215686321258545,"z":0.6470588445663452,"w":1.0},{"x":0.6196078658103943,"y":0.019607843831181527,"z":0.7607843279838562,"w":1.0},{"x":0.9019607901573181,"y":0.9647058844566345,"z":0.9333333373069763,"w":1.0},{"x":0.529411792755127,"y":0.5254902243614197,"z":0.05882352963089943,"w":1.0},{"x":0.843137264251709,"y":0.32549020648002627,"z":0.5882353186607361,"w":1.0},{"x":0.3137255012989044,"y":0.7137255072593689,"z":0.4313725531101227,"w":1.0},{"x":0.3450980484485626,"y":0.2862745225429535,"z":0.40784314274787905,"w":1.0},{"x":0.1882352977991104,"y":0.6980392336845398,"z":0.5607843399047852,"w":1.0},{"x":0.250980406999588,"y":0.5137255191802979,"z":0.3803921639919281,"w":1.0},{"x":0.5254902243614197,"y":0.5764706134796143,"z":0.125490203499794,"w":1.0},{"x":0.8941176533699036,"y":0.5607843399047852,"z":0.6039215922355652,"w":1.0},{"x":0.3686274588108063,"y":0.2705882489681244,"z":0.4117647111415863,"w":1.0},{"x":0.7019608020782471,"y":0.5254902243614197,"z":0.30588236451148989,"w":1.0},{"x":0.22745098173618318,"y":0.4588235318660736,"z":0.4274509847164154,"w":1.0},{"x":0.7058823704719544,"y":0.3921568691730499,"z":0.35686275362968447,"w":1.0},{"x":0.6078431606292725,"y":0.4117647111415863,"z":0.21568627655506135,"w":1.0},{"x":0.2705882489681244,"y":0.6392157077789307,"z":0.4117647111415863,"w":1.0},{"x":0.29019609093666079,"y":0.5803921818733215,"z":0.3450980484485626,"w":1.0},{"x":0.6117647290229797,"y":0.6509804129600525,"z":0.2823529541492462,"w":1.0},{"x":0.658823549747467,"y":0.41960784792900088,"z":0.27450981736183169,"w":1.0},{"x":0.615686297416687,"y":0.239215686917305,"z":0.43529412150382998,"w":1.0},{"x":0.7843137383460999,"y":0.501960813999176,"z":0.4313725531101227,"w":1.0},{"x":0.5490196347236633,"y":0.34117648005485537,"z":0.2549019753932953,"w":1.0},{"x":0.6784313917160034,"y":0.6666666865348816,"z":0.37254902720451357,"w":1.0},{"x":0.2980392277240753,"y":0.6705882549285889,"z":0.40392157435417178,"w":1.0},{"x":0.3333333432674408,"y":0.3921568691730499,"z":0.30980393290519717,"w":1.0},{"x":0.30980393290519717,"y":0.7176470756530762,"z":0.4431372582912445,"w":1.0},{"x":0.545098066329956,"y":0.5568627715110779,"z":0.10980392247438431,"w":1.0},{"x":0.8196078538894653,"y":0.5529412031173706,"z":0.4901960790157318,"w":1.0},{"x":0.29411765933036806,"y":0.3686274588108063,"z":0.3764705955982208,"w":1.0},{"x":0.7490196228027344,"y":0.47843137383461,"z":0.3803921639919281,"w":1.0},{"x":0.49803921580314639,"y":0.26274511218070986,"z":0.364705890417099,"w":1.0},{"x":0.5843137502670288,"y":0.7254902124404907,"z":0.364705890417099,"w":1.0},{"x":0.5647059082984924,"y":0.5215686559677124,"z":0.10588235408067703,"w":1.0},{"x":0.47058823704719546,"y":0.6823529601097107,"z":0.2823529541492462,"w":1.0},{"x":0.5098039507865906,"y":0.5058823823928833,"z":0.019607843831181527,"w":1.0},{"x":0.7607843279838562,"y":0.40392157435417178,"z":0.42352941632270815,"w":1.0},{"x":0.6509804129600525,"y":0.7490196228027344,"z":0.4431372582912445,"w":1.0},{"x":0.4745098054409027,"y":0.3450980484485626,"z":0.24313725531101228,"w":1.0},{"x":0.615686297416687,"y":0.29019609093666079,"z":0.3686274588108063,"w":1.0},{"x":0.08235294371843338,"y":0.04313725605607033,"z":0.9450980424880981,"w":1.0},{"x":0.8823529481887817,"y":0.5254902243614197,"z":0.5843137502670288,"w":1.0},{"x":0.37254902720451357,"y":0.6078431606292725,"z":0.2549019753932953,"w":1.0},{"x":0.6196078658103943,"y":0.4901960790157318,"z":0.18431372940540315,"w":1.0},{"x":0.6470588445663452,"y":0.7843137383460999,"z":0.48627451062202456,"w":1.0},{"x":0.6235294342041016,"y":0.5843137502670288,"z":0.22745098173618318,"w":1.0},{"x":0.5647059082984924,"y":0.37254902720451357,"z":0.21960784494876862,"w":1.0},{"x":0.6823529601097107,"y":0.07058823853731156,"z":0.7137255072593689,"w":1.0},{"x":0.6470588445663452,"y":0.4117647111415863,"z":0.25882354378700259,"w":1.0},{"x":0.29411765933036806,"y":0.6627451181411743,"z":0.40392157435417178,"w":1.0},{"x":0.30588236451148989,"y":0.2549019753932953,"z":0.48627451062202456,"w":1.0},{"x":0.658823549747467,"y":0.4901960790157318,"z":0.239215686917305,"w":1.0},{"x":0.5686274766921997,"y":0.5058823823928833,"z":0.10588235408067703,"w":1.0},{"x":0.6431372761726379,"y":0.9921568632125855,"z":0.7764706015586853,"w":1.0},{"x":0.6745098233222961,"y":0.5843137502670288,"z":0.29019609093666079,"w":1.0},{"x":0.3294117748737335,"y":0.48235294222831728,"z":0.2666666805744171,"w":1.0},{"x":0.8705882430076599,"y":0.729411780834198,"z":0.6627451181411743,"w":1.0},{"x":0.729411780834198,"y":0.45490196347236636,"z":0.3529411852359772,"w":1.0},{"x":0.5058823823928833,"y":0.49803921580314639,"z":0.0117647061124444,"w":1.0},{"x":0.5098039507865906,"y":0.07058823853731156,"z":0.658823549747467,"w":1.0},{"x":0.4627451002597809,"y":0.6745098233222961,"z":0.2705882489681244,"w":1.0},{"x":0.3843137323856354,"y":0.4745098054409027,"z":0.18431372940540315,"w":1.0},{"x":0.7490196228027344,"y":0.43921568989753725,"z":0.3921568691730499,"w":1.0},{"x":0.8352941274642944,"y":0.5215686559677124,"z":0.5098039507865906,"w":1.0},{"x":0.3137255012989044,"y":0.2862745225429535,"z":0.43529412150382998,"w":1.0},{"x":0.6823529601097107,"y":0.6705882549285889,"z":0.3803921639919281,"w":1.0},{"x":0.7333333492279053,"y":0.43921568989753725,"z":0.3686274588108063,"w":1.0},{"x":0.5176470875740051,"y":0.5098039507865906,"z":0.027450980618596078,"w":1.0},{"x":0.41960784792900088,"y":0.47058823704719546,"z":0.13333334028720857,"w":1.0},{"x":0.43921568989753725,"y":0.34117648005485537,"z":0.2666666805744171,"w":1.0},{"x":0.8509804010391235,"y":0.5372549295425415,"z":0.5372549295425415,"w":1.0},{"x":0.27450981736183169,"y":0.7529411911964417,"z":0.5137255191802979,"w":1.0},{"x":0.4588235318660736,"y":0.729411780834198,"z":0.3529411852359772,"w":1.0},{"x":0.7960784435272217,"y":0.501960813999176,"z":0.4470588266849518,"w":1.0},{"x":0.49803921580314639,"y":0.3803921639919281,"z":0.1882352977991104,"w":1.0},{"x":0.9137254953384399,"y":0.6549019813537598,"z":0.6705882549285889,"w":1.0},{"x":0.615686297416687,"y":0.239215686917305,"z":0.43921568989753725,"w":1.0},{"x":0.5058823823928833,"y":0.843137264251709,"z":0.5176470875740051,"w":1.0},{"x":0.21568627655506135,"y":0.5647059082984924,"z":0.45098039507865908,"w":1.0},{"x":0.6431372761726379,"y":0.48627451062202456,"z":0.21960784494876862,"w":1.0},{"x":0.2078431397676468,"y":0.5686274766921997,"z":0.4627451002597809,"w":1.0},{"x":0.7686274647712708,"y":0.47843137383461,"z":0.4117647111415863,"w":1.0},{"x":0.49803921580314639,"y":0.5098039507865906,"z":0.019607843831181527,"w":1.0},{"x":0.49803921580314639,"y":0.5686274766921997,"z":0.10196078568696976,"w":1.0},{"x":0.9725490212440491,"y":0.7960784435272217,"z":0.843137264251709,"w":1.0},{"x":0.4745098054409027,"y":0.09803921729326248,"z":0.6196078658103943,"w":1.0},{"x":0.239215686917305,"y":0.5372549295425415,"z":0.40392157435417178,"w":1.0},{"x":0.29019609093666079,"y":0.7921568751335144,"z":0.545098066329956,"w":1.0},{"x":0.29411765933036806,"y":0.4313725531101227,"z":0.33725491166114809,"w":1.0},{"x":0.22745098173618318,"y":0.45490196347236636,"z":0.4274509847164154,"w":1.0},{"x":0.5098039507865906,"y":0.545098066329956,"z":0.06666667014360428,"w":1.0},{"x":0.7098039388656616,"y":0.3607843220233917,"z":0.38823530077934267,"w":1.0},{"x":0.6745098233222961,"y":0.3176470696926117,"z":0.38823530077934267,"w":1.0},{"x":0.7058823704719544,"y":0.501960813999176,"z":0.3137255012989044,"w":1.0},{"x":0.2823529541492462,"y":0.7372549176216126,"z":0.4901960790157318,"w":1.0},{"x":0.3176470696926117,"y":0.6352941393852234,"z":0.3490196168422699,"w":1.0},{"x":0.4000000059604645,"y":0.7921568751335144,"z":0.47058823704719546,"w":1.0},{"x":0.43921568989753725,"y":0.30588236451148989,"z":0.3137255012989044,"w":1.0},{"x":0.3529411852359772,"y":0.5098039507865906,"z":0.22745098173618318,"w":1.0},{"x":0.6666666865348816,"y":0.7411764860153198,"z":0.4431372582912445,"w":1.0},{"x":0.32156863808631899,"y":0.2980392277240753,"z":0.4156862795352936,"w":1.0},{"x":0.5333333611488342,"y":0.501960813999176,"z":0.05098039284348488,"w":1.0},{"x":0.529411792755127,"y":0.4901960790157318,"z":0.0470588244497776,"w":1.0},{"x":0.5843137502670288,"y":0.2823529541492462,"z":0.35686275362968447,"w":1.0},{"x":0.48235294222831728,"y":0.2666666805744171,"z":0.3607843220233917,"w":1.0},{"x":0.6549019813537598,"y":0.5411764979362488,"z":0.24313725531101228,"w":1.0},{"x":0.7215686440467835,"y":0.2666666805744171,"z":0.4941176474094391,"w":1.0},{"x":0.20000000298023225,"y":0.7647058963775635,"z":0.615686297416687,"w":1.0},{"x":0.5647059082984924,"y":0.24705882370471955,"z":0.4000000059604645,"w":1.0},{"x":0.5372549295425415,"y":0.3450980484485626,"z":0.250980406999588,"w":1.0},{"x":0.5098039507865906,"y":0.6470588445663452,"z":0.22745098173618318,"w":1.0},{"x":0.8156862854957581,"y":0.6117647290229797,"z":0.5058823823928833,"w":1.0},{"x":0.4745098054409027,"y":0.43529412150382998,"z":0.11372549086809159,"w":1.0},{"x":0.6980392336845398,"y":0.8627451062202454,"z":0.6274510025978088,"w":1.0},{"x":0.7098039388656616,"y":0.3490196168422699,"z":0.3921568691730499,"w":1.0},{"x":0.5647059082984924,"y":0.5411764979362488,"z":0.11764705926179886,"w":1.0},{"x":0.3529411852359772,"y":0.6705882549285889,"z":0.3450980484485626,"w":1.0},{"x":0.43921568989753725,"y":0.6901960968971252,"z":0.30588236451148989,"w":1.0},{"x":0.4627451002597809,"y":0.5176470875740051,"z":0.06666667014360428,"w":1.0},{"x":0.5647059082984924,"y":0.5686274766921997,"z":0.1411764770746231,"w":1.0},{"x":0.4431372582912445,"y":0.545098066329956,"z":0.11372549086809159,"w":1.0},{"x":0.6117647290229797,"y":0.5137255191802979,"z":0.1725490242242813,"w":1.0},{"x":0.6235294342041016,"y":0.686274528503418,"z":0.34117648005485537,"w":1.0},{"x":0.5058823823928833,"y":0.4745098054409027,"z":0.0470588244497776,"w":1.0},{"x":0.4156862795352936,"y":0.42352941632270815,"z":0.18431372940540315,"w":1.0},{"x":0.43921568989753725,"y":0.7333333492279053,"z":0.3686274588108063,"w":1.0},{"x":0.2862745225429535,"y":0.250980406999588,"z":0.5058823823928833,"w":1.0},{"x":0.6117647290229797,"y":0.40392157435417178,"z":0.2235294133424759,"w":1.0},{"x":0.843137264251709,"y":0.7843137383460999,"z":0.6784313917160034,"w":1.0},{"x":0.49803921580314639,"y":0.6509804129600525,"z":0.22745098173618318,"w":1.0},{"x":0.8470588326454163,"y":0.30588236451148989,"z":0.6078431606292725,"w":1.0},{"x":0.49803921580314639,"y":0.5058823823928833,"z":0.0117647061124444,"w":1.0},{"x":0.8392156958580017,"y":0.38823530077934267,"z":0.545098066329956,"w":1.0},{"x":0.5882353186607361,"y":0.8078431487083435,"z":0.48627451062202456,"w":1.0},{"x":0.4941176474094391,"y":0.6392157077789307,"z":0.21176470816135407,"w":1.0},{"x":0.38823530077934267,"y":0.23529411852359773,"z":0.4431372582912445,"w":1.0},{"x":0.5490196347236633,"y":0.6117647290229797,"z":0.1882352977991104,"w":1.0},{"x":0.2666666805744171,"y":0.3529411852359772,"z":0.42352941632270815,"w":1.0},{"x":0.47843137383461,"y":0.27450981736183169,"z":0.3490196168422699,"w":1.0},{"x":0.29411765933036806,"y":0.33725491166114809,"z":0.40392157435417178,"w":1.0},{"x":0.43529412150382998,"y":0.3960784375667572,"z":0.1921568661928177,"w":1.0},{"x":0.49803921580314639,"y":0.6745098233222961,"z":0.2666666805744171,"w":1.0},{"x":0.12941177189350129,"y":0.5686274766921997,"z":0.5803921818733215,"w":1.0},{"x":0.22745098173618318,"y":0.4000000059604645,"z":0.4470588266849518,"w":1.0},{"x":0.6980392336845398,"y":0.4000000059604645,"z":0.33725491166114809,"w":1.0},{"x":0.5764706134796143,"y":0.7529411911964417,"z":0.3960784375667572,"w":1.0},{"x":0.6117647290229797,"y":0.46666666865348818,"z":0.1764705926179886,"w":1.0},{"x":0.6117647290229797,"y":0.3490196168422699,"z":0.29019609093666079,"w":1.0},{"x":0.47843137383461,"y":0.38823530077934267,"z":0.18039216101169587,"w":1.0},{"x":0.32549020648002627,"y":0.8705882430076599,"z":0.6235294342041016,"w":1.0},{"x":0.3176470696926117,"y":0.03529411926865578,"z":0.7647058963775635,"w":1.0},{"x":0.0784313753247261,"y":0.2666666805744171,"z":0.7411764860153198,"w":1.0},{"x":0.20392157137393952,"y":0.5843137502670288,"z":0.4745098054409027,"w":1.0},{"x":0.8078431487083435,"y":0.3450980484485626,"z":0.5254902243614197,"w":1.0},{"x":0.3921568691730499,"y":0.4313725531101227,"z":0.20392157137393952,"w":1.0},{"x":0.7490196228027344,"y":0.6549019813537598,"z":0.4470588266849518,"w":1.0},{"x":0.2235294133424759,"y":0.47058823704719546,"z":0.4274509847164154,"w":1.0},{"x":0.18039216101169587,"y":0.4941176474094391,"z":0.4901960790157318,"w":1.0},{"x":0.9921568632125855,"y":0.06666667014360428,"z":1.0,"w":1.0},{"x":0.3921568691730499,"y":0.1725490242242813,"z":0.5333333611488342,"w":1.0},{"x":0.20392157137393952,"y":0.40392157435417178,"z":0.47843137383461,"w":1.0},{"x":0.5490196347236633,"y":0.3450980484485626,"z":0.250980406999588,"w":1.0},{"x":0.9058823585510254,"y":0.45098039507865908,"z":0.6196078658103943,"w":1.0},{"x":0.3137255012989044,"y":0.4901960790157318,"z":0.2862745225429535,"w":1.0},{"x":0.4941176474094391,"y":0.5921568870544434,"z":0.1411764770746231,"w":1.0},{"x":0.22745098173618318,"y":0.3843137323856354,"z":0.4588235318660736,"w":1.0},{"x":0.3294117748737335,"y":0.3607843220233917,"z":0.34117648005485537,"w":1.0},{"x":0.6039215922355652,"y":0.48627451062202456,"z":0.16078431904315949,"w":1.0},{"x":0.42352941632270815,"y":0.8588235378265381,"z":0.5607843399047852,"w":1.0},{"x":0.07058823853731156,"y":0.0784313753247261,"z":0.9176470637321472,"w":1.0},{"x":0.7137255072593689,"y":0.5098039507865906,"z":0.32549020648002627,"w":1.0},{"x":0.545098066329956,"y":0.7529411911964417,"z":0.3921568691730499,"w":1.0},{"x":0.6470588445663452,"y":0.3960784375667572,"z":0.27450981736183169,"w":1.0},{"x":0.6431372761726379,"y":0.34117648005485537,"z":0.3294117748737335,"w":1.0},{"x":0.46666666865348818,"y":0.239215686917305,"z":0.40784314274787905,"w":1.0},{"x":0.501960813999176,"y":0.4901960790157318,"z":0.0235294122248888,"w":1.0},{"x":0.4941176474094391,"y":0.250980406999588,"z":0.3843137323856354,"w":1.0},{"x":0.4941176474094391,"y":0.4470588266849518,"z":0.08627451211214066,"w":1.0},{"x":0.40784314274787905,"y":0.7372549176216126,"z":0.38823530077934267,"w":1.0},{"x":0.5882353186607361,"y":0.8313725590705872,"z":0.5215686559677124,"w":1.0},{"x":0.04313725605607033,"y":0.5137255191802979,"z":0.7019608020782471,"w":1.0},{"x":0.19607843458652497,"y":0.37254902720451357,"z":0.5058823823928833,"w":1.0},{"x":0.3176470696926117,"y":0.6941176652908325,"z":0.40392157435417178,"w":1.0},{"x":0.5176470875740051,"y":0.21568627655506135,"z":0.43921568989753725,"w":1.0},{"x":0.8392156958580017,"y":0.30980393290519717,"z":0.5921568870544434,"w":1.0},{"x":0.27450981736183169,"y":0.5843137502670288,"z":0.37254902720451357,"w":1.0},{"x":0.32549020648002627,"y":0.5490196347236633,"z":0.2823529541492462,"w":1.0},{"x":0.5137255191802979,"y":0.4588235318660736,"z":0.07450980693101883,"w":1.0},{"x":0.3686274588108063,"y":0.7019608020782471,"z":0.3686274588108063,"w":1.0},{"x":0.5137255191802979,"y":0.364705890417099,"z":0.2078431397676468,"w":1.0},{"x":0.239215686917305,"y":0.6392157077789307,"z":0.45490196347236636,"w":1.0},{"x":0.6941176652908325,"y":0.6980392336845398,"z":0.41960784792900088,"w":1.0},{"x":0.5490196347236633,"y":0.6784313917160034,"z":0.2823529541492462,"w":1.0},{"x":0.4274509847164154,"y":0.45490196347236636,"z":0.13725490868091584,"w":1.0},{"x":0.5647059082984924,"y":0.23529411852359773,"z":0.41960784792900088,"w":1.0},{"x":0.6313725709915161,"y":0.800000011920929,"z":0.49803921580314639,"w":1.0},{"x":0.5960784554481506,"y":0.7137255072593689,"z":0.3529411852359772,"w":1.0},{"x":0.49803921580314639,"y":0.686274528503418,"z":0.2823529541492462,"w":1.0},{"x":0.3803921639919281,"y":0.6901960968971252,"z":0.34117648005485537,"w":1.0},{"x":0.5960784554481506,"y":0.2862745225429535,"z":0.3607843220233917,"w":1.0},{"x":0.3019607961177826,"y":0.5803921818733215,"z":0.3294117748737335,"w":1.0},{"x":0.5058823823928833,"y":0.45490196347236636,"z":0.07450980693101883,"w":1.0},{"x":0.0313725508749485,"y":0.2862745225429535,"z":0.7882353067398071,"w":1.0},{"x":0.6196078658103943,"y":0.3960784375667572,"z":0.24313725531101228,"w":1.0},{"x":0.6705882549285889,"y":0.0235294122248888,"z":0.772549033164978,"w":1.0},{"x":0.886274516582489,"y":0.6392157077789307,"z":0.6235294342041016,"w":1.0},{"x":0.2862745225429535,"y":0.2980392277240753,"z":0.45490196347236636,"w":1.0},{"x":0.5686274766921997,"y":0.14901961386203767,"z":0.545098066329956,"w":1.0},{"x":0.49803921580314639,"y":0.5176470875740051,"z":0.027450980618596078,"w":1.0},{"x":0.5843137502670288,"y":0.7098039388656616,"z":0.34117648005485537,"w":1.0},{"x":0.7843137383460999,"y":0.6705882549285889,"z":0.5058823823928833,"w":1.0},{"x":0.4627451002597809,"y":0.364705890417099,"z":0.21960784494876862,"w":1.0},{"x":0.8470588326454163,"y":0.6470588445663452,"z":0.572549045085907,"w":1.0},{"x":0.3450980484485626,"y":0.5058823823928833,"z":0.24313725531101228,"w":1.0},{"x":0.5803921818733215,"y":0.6313725709915161,"z":0.23137255012989045,"w":1.0},{"x":0.3450980484485626,"y":0.7215686440467835,"z":0.4117647111415863,"w":1.0},{"x":0.4431372582912445,"y":0.46666666865348818,"z":0.10980392247438431,"w":1.0},{"x":0.4627451002597809,"y":0.21176470816135407,"z":0.45098039507865908,"w":1.0},{"x":0.8117647171020508,"y":0.3294117748737335,"z":0.5411764979362488,"w":1.0},{"x":0.4627451002597809,"y":0.239215686917305,"z":0.40392157435417178,"w":1.0},{"x":0.7215686440467835,"y":0.3529411852359772,"z":0.40392157435417178,"w":1.0},{"x":0.843137264251709,"y":0.9058823585510254,"z":0.8078431487083435,"w":1.0},{"x":0.8235294222831726,"y":0.6470588445663452,"z":0.5372549295425415,"w":1.0},{"x":0.6823529601097107,"y":0.46666666865348818,"z":0.2862745225429535,"w":1.0},{"x":0.6352941393852234,"y":0.5333333611488342,"z":0.21176470816135407,"w":1.0},{"x":0.0470588244497776,"y":0.33725491166114809,"z":0.7372549176216126,"w":1.0},{"x":0.3529411852359772,"y":0.5058823823928833,"z":0.22745098173618318,"w":1.0},{"x":0.5843137502670288,"y":0.30588236451148989,"z":0.3294117748737335,"w":1.0},{"x":0.4274509847164154,"y":0.10588235408067703,"z":0.6117647290229797,"w":1.0},{"x":0.8941176533699036,"y":0.062745101749897,"z":0.8980392217636108,"w":1.0},{"x":0.7764706015586853,"y":0.3803921639919281,"z":0.4588235318660736,"w":1.0},{"x":0.658823549747467,"y":0.1411764770746231,"z":0.6039215922355652,"w":1.0},{"x":0.7921568751335144,"y":0.6196078658103943,"z":0.48235294222831728,"w":1.0},{"x":0.45098039507865908,"y":0.7411764860153198,"z":0.37254902720451357,"w":1.0},{"x":0.8039215803146362,"y":0.7372549176216126,"z":0.5843137502670288,"w":1.0},{"x":0.572549045085907,"y":0.6980392336845398,"z":0.32156863808631899,"w":1.0},{"x":0.2705882489681244,"y":0.7568627595901489,"z":0.5254902243614197,"w":1.0},{"x":0.6549019813537598,"y":0.3960784375667572,"z":0.2862745225429535,"w":1.0},{"x":0.6196078658103943,"y":0.658823549747467,"z":0.3019607961177826,"w":1.0},{"x":0.800000011920929,"y":0.529411792755127,"z":0.4588235318660736,"w":1.0},{"x":0.6392157077789307,"y":0.5607843399047852,"z":0.23137255012989045,"w":1.0},{"x":0.8784313797950745,"y":0.15294118225574494,"z":0.7803921699523926,"w":1.0},{"x":0.4470588266849518,"y":0.6117647290229797,"z":0.1882352977991104,"w":1.0},{"x":0.5215686559677124,"y":0.772549033164978,"z":0.4117647111415863,"w":1.0},{"x":0.5607843399047852,"y":0.5372549295425415,"z":0.10980392247438431,"w":1.0},{"x":0.5176470875740051,"y":0.49803921580314639,"z":0.027450980618596078,"w":1.0},{"x":0.45098039507865908,"y":0.4941176474094391,"z":0.08235294371843338,"w":1.0},{"x":0.1921568661928177,"y":0.26274511218070986,"z":0.6000000238418579,"w":1.0},{"x":0.40392157435417178,"y":0.545098066329956,"z":0.16470588743686677,"w":1.0},{"x":0.4117647111415863,"y":0.5607843399047852,"z":0.16862745583057404,"w":1.0},{"x":0.5960784554481506,"y":0.5686274766921997,"z":0.18039216101169587,"w":1.0},{"x":0.572549045085907,"y":0.5960784554481506,"z":0.18039216101169587,"w":1.0},{"x":0.10980392247438431,"y":0.8627451062202454,"z":0.8156862854957581,"w":1.0},{"x":0.501960813999176,"y":0.5568627715110779,"z":0.08235294371843338,"w":1.0},{"x":0.5058823823928833,"y":0.5568627715110779,"z":0.08627451211214066,"w":1.0},{"x":0.6039215922355652,"y":0.16078431904315949,"z":0.545098066329956,"w":1.0},{"x":0.6470588445663452,"y":0.47843137383461,"z":0.2235294133424759,"w":1.0},{"x":0.545098066329956,"y":0.6823529601097107,"z":0.2862745225429535,"w":1.0},{"x":0.4274509847164154,"y":0.5372549295425415,"z":0.125490203499794,"w":1.0},{"x":0.5607843399047852,"y":0.43529412150382998,"z":0.13725490868091584,"w":1.0},{"x":0.22745098173618318,"y":0.5176470875740051,"z":0.42352941632270815,"w":1.0},{"x":0.6941176652908325,"y":0.529411792755127,"z":0.29411765933036806,"w":1.0},{"x":0.3921568691730499,"y":0.6823529601097107,"z":0.32156863808631899,"w":1.0},{"x":0.5529412031173706,"y":0.5098039507865906,"z":0.08235294371843338,"w":1.0},{"x":0.4431372582912445,"y":0.5058823823928833,"z":0.09019608050584793,"w":1.0},{"x":0.3019607961177826,"y":0.3137255012989044,"z":0.41960784792900088,"w":1.0},{"x":0.6392157077789307,"y":0.6196078658103943,"z":0.27843138575553896,"w":1.0},{"x":0.5058823823928833,"y":0.49803921580314639,"z":0.0117647061124444,"w":1.0},{"x":0.11764705926179886,"y":0.7764706015586853,"z":0.7176470756530762,"w":1.0},{"x":0.43921568989753725,"y":0.41960784792900088,"z":0.16078431904315949,"w":1.0},{"x":0.25882354378700259,"y":0.8470588326454163,"z":0.6431372761726379,"w":1.0},{"x":0.5647059082984924,"y":0.23137255012989045,"z":0.4274509847164154,"w":1.0},{"x":0.38823530077934267,"y":0.5215686559677124,"z":0.1764705926179886,"w":1.0},{"x":0.5176470875740051,"y":0.3921568691730499,"z":0.1725490242242813,"w":1.0},{"x":0.529411792755127,"y":0.5372549295425415,"z":0.07058823853731156,"w":1.0},{"x":0.6431372761726379,"y":0.5568627715110779,"z":0.23137255012989045,"w":1.0},{"x":0.5372549295425415,"y":0.3686274588108063,"z":0.21568627655506135,"w":1.0},{"x":0.5372549295425415,"y":0.5921568870544434,"z":0.15294118225574494,"w":1.0},{"x":0.43529412150382998,"y":0.572549045085907,"z":0.14901961386203767,"w":1.0},{"x":0.33725491166114809,"y":0.4470588266849518,"z":0.26274511218070986,"w":1.0},{"x":0.7098039388656616,"y":0.6470588445663452,"z":0.3921568691730499,"w":1.0},{"x":0.7921568751335144,"y":0.48235294222831728,"z":0.4431372582912445,"w":1.0},{"x":0.30588236451148989,"y":0.3294117748737335,"z":0.4000000059604645,"w":1.0},{"x":0.48627451062202456,"y":0.4627451002597809,"z":0.06666667014360428,"w":1.0},{"x":0.572549045085907,"y":0.6666666865348816,"z":0.27843138575553896,"w":1.0},{"x":0.5686274766921997,"y":0.7764706015586853,"z":0.43529412150382998,"w":1.0},{"x":0.29019609093666079,"y":0.8078431487083435,"z":0.5686274766921997,"w":1.0},{"x":0.5686274766921997,"y":0.4941176474094391,"z":0.10196078568696976,"w":1.0},{"x":0.501960813999176,"y":0.4941176474094391,"z":0.01568627543747425,"w":1.0},{"x":0.3686274588108063,"y":0.545098066329956,"z":0.21568627655506135,"w":1.0},{"x":0.8078431487083435,"y":0.658823549747467,"z":0.529411792755127,"w":1.0},{"x":0.6627451181411743,"y":0.45490196347236636,"z":0.25882354378700259,"w":1.0},{"x":0.43921568989753725,"y":0.5607843399047852,"z":0.13333334028720857,"w":1.0},{"x":0.30588236451148989,"y":0.6627451181411743,"z":0.3843137323856354,"w":1.0},{"x":0.3450980484485626,"y":0.3921568691730499,"z":0.29411765933036806,"w":1.0},{"x":0.5529412031173706,"y":0.5607843399047852,"z":0.12156862765550614,"w":1.0},{"x":0.29411765933036806,"y":0.3450980484485626,"z":0.3960784375667572,"w":1.0},{"x":0.45098039507865908,"y":0.501960813999176,"z":0.08235294371843338,"w":1.0},{"x":0.6196078658103943,"y":0.6509804129600525,"z":0.29411765933036806,"w":1.0},{"x":0.23529411852359773,"y":0.5843137502670288,"z":0.42352941632270815,"w":1.0},{"x":0.2705882489681244,"y":0.3607843220233917,"z":0.4156862795352936,"w":1.0},{"x":0.6549019813537598,"y":0.8941176533699036,"z":0.6431372761726379,"w":1.0},{"x":0.5333333611488342,"y":0.3803921639919281,"z":0.1921568661928177,"w":1.0},{"x":0.47058823704719546,"y":0.3176470696926117,"z":0.2862745225429535,"w":1.0},{"x":0.5882353186607361,"y":0.929411768913269,"z":0.6627451181411743,"w":1.0},{"x":0.3019607961177826,"y":0.615686297416687,"z":0.3529411852359772,"w":1.0},{"x":0.48627451062202456,"y":0.3294117748737335,"z":0.2666666805744171,"w":1.0},{"x":0.4470588266849518,"y":0.5529412031173706,"z":0.11764705926179886,"w":1.0},{"x":0.5058823823928833,"y":0.501960813999176,"z":0.007843137718737126,"w":1.0},{"x":0.5411764979362488,"y":0.5411764979362488,"z":0.09019608050584793,"w":1.0},{"x":0.47058823704719546,"y":0.4000000059604645,"z":0.16470588743686677,"w":1.0},{"x":0.43921568989753725,"y":0.42352941632270815,"z":0.1568627506494522,"w":1.0},{"x":0.5490196347236633,"y":0.4941176474094391,"z":0.07450980693101883,"w":1.0},{"x":0.48235294222831728,"y":0.5411764979362488,"z":0.07058823853731156,"w":1.0},{"x":0.35686275362968447,"y":0.14509804546833039,"z":0.5882353186607361,"w":1.0},{"x":0.4313725531101227,"y":0.6549019813537598,"z":0.25882354378700259,"w":1.0},{"x":0.6941176652908325,"y":0.33725491166114809,"z":0.3843137323856354,"w":1.0},{"x":0.29019609093666079,"y":0.45490196347236636,"z":0.3294117748737335,"w":1.0},{"x":0.3450980484485626,"y":0.32156863808631899,"z":0.3686274588108063,"w":1.0},{"x":0.3333333432674408,"y":0.48235294222831728,"z":0.26274511218070986,"w":1.0},{"x":0.43921568989753725,"y":0.4588235318660736,"z":0.11764705926179886,"w":1.0},{"x":0.4745098054409027,"y":0.7490196228027344,"z":0.3843137323856354,"w":1.0},{"x":0.6745098233222961,"y":0.5882353186607361,"z":0.29411765933036806,"w":1.0},{"x":0.40392157435417178,"y":0.15294118225574494,"z":0.5529412031173706,"w":1.0},{"x":0.43921568989753725,"y":0.3333333432674408,"z":0.27843138575553896,"w":1.0},{"x":0.6941176652908325,"y":0.6745098233222961,"z":0.3960784375667572,"w":1.0},{"x":0.3490196168422699,"y":0.43529412150382998,"z":0.2549019753932953,"w":1.0},{"x":0.8352941274642944,"y":0.24313725531101228,"z":0.6392157077789307,"w":1.0},{"x":0.4627451002597809,"y":0.6901960968971252,"z":0.29411765933036806,"w":1.0},{"x":0.5098039507865906,"y":0.4901960790157318,"z":0.027450980618596078,"w":1.0},{"x":0.6901960968971252,"y":0.49803921580314639,"z":0.2862745225429535,"w":1.0},{"x":0.46666666865348818,"y":0.5215686559677124,"z":0.06666667014360428,"w":1.0},{"x":0.45490196347236636,"y":0.40784314274787905,"z":0.16470588743686677,"w":1.0},{"x":0.40392157435417178,"y":0.7176470756530762,"z":0.364705890417099,"w":1.0},{"x":0.45490196347236636,"y":0.5215686559677124,"z":0.08235294371843338,"w":1.0},{"x":0.10980392247438431,"y":0.3764705955982208,"z":0.6313725709915161,"w":1.0},{"x":0.8039215803146362,"y":0.45098039507865908,"z":0.47058823704719546,"w":1.0},{"x":0.5372549295425415,"y":0.4274509847164154,"z":0.125490203499794,"w":1.0},{"x":0.7019608020782471,"y":0.34117648005485537,"z":0.3960784375667572,"w":1.0},{"x":0.7333333492279053,"y":0.4745098054409027,"z":0.35686275362968447,"w":1.0},{"x":0.19607843458652497,"y":0.18039216101169587,"z":0.6745098233222961,"w":1.0},{"x":0.8784313797950745,"y":0.49803921580314639,"z":0.572549045085907,"w":1.0},{"x":0.5529412031173706,"y":0.5333333611488342,"z":0.09019608050584793,"w":1.0},{"x":0.23529411852359773,"y":0.10196078568696976,"z":0.7333333492279053,"w":1.0},{"x":0.6431372761726379,"y":0.48235294222831728,"z":0.21960784494876862,"w":1.0},{"x":0.3019607961177826,"y":0.4745098054409027,"z":0.30980393290519717,"w":1.0},{"x":0.4627451002597809,"y":0.7215686440467835,"z":0.34117648005485537,"w":1.0},{"x":0.24705882370471955,"y":0.7411764860153198,"z":0.5333333611488342,"w":1.0},{"x":0.21176470816135407,"y":0.0784313753247261,"z":0.7803921699523926,"w":1.0},{"x":0.6078431606292725,"y":0.16078431904315949,"z":0.545098066329956,"w":1.0},{"x":0.6000000238418579,"y":0.545098066329956,"z":0.16470588743686677,"w":1.0},{"x":0.007843137718737126,"y":0.8745098114013672,"z":0.9450980424880981,"w":1.0},{"x":0.16470588743686677,"y":0.7647058963775635,"z":0.6509804129600525,"w":1.0},{"x":0.19607843458652497,"y":0.772549033164978,"z":0.6235294342041016,"w":1.0},{"x":0.7607843279838562,"y":0.4745098054409027,"z":0.4000000059604645,"w":1.0},{"x":0.7058823704719544,"y":0.4941176474094391,"z":0.3137255012989044,"w":1.0},{"x":0.8352941274642944,"y":0.2666666805744171,"z":0.6196078658103943,"w":1.0},{"x":0.4588235318660736,"y":0.3137255012989044,"z":0.2980392277240753,"w":1.0},{"x":0.615686297416687,"y":0.5607843399047852,"z":0.20000000298023225,"w":1.0},{"x":0.5411764979362488,"y":0.5411764979362488,"z":0.08627451211214066,"w":1.0},{"x":0.5333333611488342,"y":0.9254902005195618,"z":0.6470588445663452,"w":1.0},{"x":0.3921568691730499,"y":0.6627451181411743,"z":0.2980392277240753,"w":1.0},{"x":0.7215686440467835,"y":0.09019608050584793,"z":0.7137255072593689,"w":1.0},{"x":0.6235294342041016,"y":0.7764706015586853,"z":0.4588235318660736,"w":1.0},{"x":0.572549045085907,"y":0.09019608050584793,"z":0.6392157077789307,"w":1.0},{"x":0.501960813999176,"y":0.5058823823928833,"z":0.007843137718737126,"w":1.0},{"x":0.3176470696926117,"y":0.6823529601097107,"z":0.3960784375667572,"w":1.0},{"x":0.5960784554481506,"y":0.501960813999176,"z":0.14901961386203767,"w":1.0},{"x":0.5607843399047852,"y":0.6666666865348816,"z":0.2705882489681244,"w":1.0},{"x":0.6509804129600525,"y":0.40784314274787905,"z":0.2705882489681244,"w":1.0},{"x":0.5098039507865906,"y":0.5215686559677124,"z":0.03529411926865578,"w":1.0},{"x":0.5411764979362488,"y":0.4274509847164154,"z":0.12941177189350129,"w":1.0},{"x":0.2705882489681244,"y":0.5960784554481506,"z":0.3843137323856354,"w":1.0},{"x":0.7450980544090271,"y":0.3294117748737335,"z":0.45490196347236636,"w":1.0},{"x":0.6078431606292725,"y":0.3686274588108063,"z":0.25882354378700259,"w":1.0},{"x":0.41960784792900088,"y":0.4313725531101227,"z":0.16862745583057404,"w":1.0},{"x":0.7411764860153198,"y":0.9058823585510254,"z":0.7176470756530762,"w":1.0},{"x":0.8039215803146362,"y":0.6431372761726379,"z":0.5098039507865906,"w":1.0},{"x":0.7647058963775635,"y":0.5372549295425415,"z":0.40784314274787905,"w":1.0},{"x":0.5215686559677124,"y":0.6705882549285889,"z":0.25882354378700259,"w":1.0},{"x":0.33725491166114809,"y":0.32156863808631899,"z":0.37254902720451357,"w":1.0},{"x":0.30588236451148989,"y":0.32549020648002627,"z":0.40392157435417178,"w":1.0},{"x":0.6352941393852234,"y":0.6705882549285889,"z":0.3294117748737335,"w":1.0},{"x":0.21568627655506135,"y":0.7450980544090271,"z":0.572549045085907,"w":1.0},{"x":0.5098039507865906,"y":0.6745098233222961,"z":0.2666666805744171,"w":1.0},{"x":0.33725491166114809,"y":0.37254902720451357,"z":0.32156863808631899,"w":1.0},{"x":0.7764706015586853,"y":0.27450981736183169,"z":0.5411764979362488,"w":1.0},{"x":0.5803921818733215,"y":0.4470588266849518,"z":0.14901961386203767,"w":1.0},{"x":0.40784314274787905,"y":0.5647059082984924,"z":0.1725490242242813,"w":1.0},{"x":0.6745098233222961,"y":0.5843137502670288,"z":0.29019609093666079,"w":1.0},{"x":0.686274528503418,"y":0.4156862795352936,"z":0.3137255012989044,"w":1.0},{"x":0.501960813999176,"y":0.5098039507865906,"z":0.01568627543747425,"w":1.0},{"x":0.5490196347236633,"y":0.8117647171020508,"z":0.47843137383461,"w":1.0},{"x":0.25882354378700259,"y":0.686274528503418,"z":0.47058823704719546,"w":1.0}]} \ No newline at end of file diff --git a/pSpecs1.json.meta b/pSpecs1.json.meta new file mode 100644 index 0000000..b17619c --- /dev/null +++ b/pSpecs1.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b003ce129f5413f40b83eca2229754aa +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 7d5fbefab2114381bf854cdebb41d7fc81d89b00 Mon Sep 17 00:00:00 2001 From: Mo Date: Fri, 22 Apr 2022 15:00:28 +0200 Subject: [PATCH 03/14] Added direct camera reference instead of Camera.main --- Scripts/PhospheneSimulator.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Scripts/PhospheneSimulator.cs b/Scripts/PhospheneSimulator.cs index dfabf43..fe3ee3d 100644 --- a/Scripts/PhospheneSimulator.cs +++ b/Scripts/PhospheneSimulator.cs @@ -7,7 +7,6 @@ using OpenCVForUnity.CoreModule; using OpenCVForUnity.ImgprocModule; using OpenCVForUnity.UnityUtils; -using static ImageSynthesis; using UnityEngine.InputSystem; using System.Collections; @@ -17,6 +16,8 @@ namespace Xarphos.Scripts public class PhospheneSimulator : MonoBehaviour { + public Camera TargetCamera; + // Image processing settings float phospheneFiltering = 0.0f; @@ -32,9 +33,9 @@ public class PhospheneSimulator : MonoBehaviour [SerializeField] protected Vector2Int resolution; // Render textures - protected RenderTexture inputRT; - protected RenderTexture activationMask; - protected RenderTexture phospheneRT; + [SerializeField] protected RenderTexture inputRT; + [SerializeField] protected RenderTexture activationMask; + [SerializeField] protected RenderTexture phospheneRT; // For reading phosphene configuration from JSON [SerializeField] string phospheneConfigFile; @@ -58,6 +59,8 @@ public class PhospheneSimulator : MonoBehaviour protected void Awake() { + TargetCamera ??= GetComponent(); + // Initialize the array of phosphenes phosphenes = PhospheneConfig.InitPhosphenesFromJSON(phospheneConfigFile); nPhosphenes = phosphenes.Length; @@ -105,7 +108,7 @@ void computePhospheneActivity(){ void OnPreRender() { // Render to the input render texture - Camera.main.targetTexture = inputRT; + TargetCamera.targetTexture = inputRT; } @@ -115,7 +118,7 @@ IEnumerator blitToScreen() yield return new WaitForEndOfFrame(); // Target tex has to be (temporarilty) set to null - Camera.main.targetTexture = null; + TargetCamera.targetTexture = null; // Simulate the phosphenes (based on the shared phosphene buffer) Graphics.Blit(null as RenderTexture, phospheneRT, phospheneMaterial); From c3b2ed91bab97b81e589d96f8e90ae12ee4c2351 Mon Sep 17 00:00:00 2001 From: Mo Date: Fri, 22 Apr 2022 15:00:45 +0200 Subject: [PATCH 04/14] obsolete shader --- Shader/DSPV_PhospheneShader_orig.shader | 94 -------------------- Shader/DSPV_PhospheneShader_orig.shader.meta | 10 --- 2 files changed, 104 deletions(-) delete mode 100644 Shader/DSPV_PhospheneShader_orig.shader delete mode 100644 Shader/DSPV_PhospheneShader_orig.shader.meta 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: From 01ce405ace733c7706555a0226aae619a18de142 Mon Sep 17 00:00:00 2001 From: Mo Date: Mon, 25 Apr 2022 16:49:15 +0200 Subject: [PATCH 05/14] deleted obsolete files --- Scripts/DSPVEyeTracking.cs | 303 ------------------- Scripts/DSPVEyeTracking.cs.meta | 11 - Scripts/DSPV_SimulationPostProcessor.cs | 182 ----------- Scripts/DSPV_SimulationPostProcessor.cs.meta | 11 - Scripts/PhospheneConfiguration.cs | 29 -- Scripts/PhospheneConfiguration.cs.meta | 11 - Shader/CircularMask.shader | 143 --------- Shader/CircularMask.shader.meta | 10 - 8 files changed, 700 deletions(-) delete mode 100644 Scripts/DSPVEyeTracking.cs delete mode 100644 Scripts/DSPVEyeTracking.cs.meta delete mode 100644 Scripts/DSPV_SimulationPostProcessor.cs delete mode 100644 Scripts/DSPV_SimulationPostProcessor.cs.meta delete mode 100644 Scripts/PhospheneConfiguration.cs delete mode 100644 Scripts/PhospheneConfiguration.cs.meta delete mode 100644 Shader/CircularMask.shader delete mode 100644 Shader/CircularMask.shader.meta diff --git a/Scripts/DSPVEyeTracking.cs b/Scripts/DSPVEyeTracking.cs deleted file mode 100644 index ffe7074..0000000 --- a/Scripts/DSPVEyeTracking.cs +++ /dev/null @@ -1,303 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Unity.VisualScripting; -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 DSPVEyeTracking : MonoBehaviour - { - 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 = 0; - private static float time_stamp; - private static int frame; - - - internal bool EyeTrackingAvailable { get; private set; } - -#region Unity Event Functioens - private void Start() - { - // SRanipal_Eye_v2.LaunchEyeCalibration(); // Perform calibration for eye tracking. - Invoke(nameof(SystemCheck), .5f); - Invoke(nameof(RegisterCallback), .5f); - } - - private void FixedUpdate() - { - if (!CheckFrameworkStatusErrors()) - { - EyeTrackingAvailable = false; - // Debug.LogWarning("Framework Responded failure to work."); - } - } - - private void Update() - { - if (Keyboard.current[Key.F8].wasPressedThisFrame) - { - SetDebugGazeRender(!renderGazeRays); - } - if (Keyboard.current[Key.F9].wasPressedThisFrame) - { - freezeGazeRays = !freezeGazeRays; - } - if (renderGazeRays && !freezeGazeRays) - { - UpdateGazeRays(); - } - } -#endregion - -#region EyeData Setup - private void SystemCheck() - { - if (EyeFramework.Status != EyeFramework.FrameworkStatus.NOT_SUPPORT) - { - EyeTrackingAvailable = false; - Debug.LogError("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 - private void OnDisable() - { - Release(); - } - - void OnApplicationQuit() - { - Release(); - } - - /// - /// Release callback thread when disabled or quit - /// - private static void Release() - { - if (eye_callback_registered == true) - { - SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( - Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) - ); - eye_callback_registered = false; - } - - Destroy(leftVisual); - Destroy(rightVisual); - } - - /// - /// Required class for IL2CPP scripting backend support - /// - internal class MonoPInvokeCallbackAttribute : System.Attribute - { - public MonoPInvokeCallbackAttribute() { } - } -#endregion - -#region Debug Gaze Rendering - private static bool renderGazeRays, freezeGazeRays; - private static GameObject leftVisual, rightVisual; - private static LineRenderer leftGazeLine, rightGazeLine; - - private static Camera mainCam; - - private void SetDebugGazeRender(bool status) - { - // first acticvation: set up objects and references - if (status && (leftVisual == null || rightVisual == null)) - { - mainCam = Camera.main; - leftVisual = new GameObject("LeftGazeRender"); - rightVisual = new GameObject("RightGazeRender"); - leftGazeLine = leftVisual.AddComponent(); - { - leftGazeLine.startColor = Color.blue; - leftGazeLine.endColor = Color.blue; - leftGazeLine.startWidth = 0.005f; - leftGazeLine.endWidth = 0.005f; - } - rightGazeLine = rightVisual.AddComponent(); - { - rightGazeLine.startColor = Color.red; - rightGazeLine.endColor = Color.red; - rightGazeLine.startWidth = 0.005f; - rightGazeLine.endWidth = 0.005f; - } - } - - renderGazeRays = status; - leftVisual.SetActive(status); - rightVisual.SetActive(status); - } - - private void UpdateGazeRays() - { - Vector3 leftOrigin, rightOrigin, leftDir, rightDir; - - // 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); - - // transform from local space - var t = mainCam.transform; - leftOrigin = t.TransformPoint(leftOrigin); - rightOrigin = t.TransformPoint(rightOrigin); - leftDir = t.TransformDirection(leftDir); - rightDir = t.TransformDirection(rightDir); - - // update render - leftGazeLine.SetPositions(new [] { leftOrigin, leftOrigin + leftDir * 20 }); - rightGazeLine.SetPositions(new [] { rightOrigin, rightOrigin + rightDir * 20 }); - } -#endregion - } -} diff --git a/Scripts/DSPVEyeTracking.cs.meta b/Scripts/DSPVEyeTracking.cs.meta deleted file mode 100644 index 7dfa96c..0000000 --- a/Scripts/DSPVEyeTracking.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d7e6fb78bd046e54dbc6ec6200589850 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Scripts/DSPV_SimulationPostProcessor.cs b/Scripts/DSPV_SimulationPostProcessor.cs deleted file mode 100644 index c4a4ded..0000000 --- a/Scripts/DSPV_SimulationPostProcessor.cs +++ /dev/null @@ -1,182 +0,0 @@ -using UnityEngine; -using Rect = UnityEngine.Rect; -using System; -using OpenCVForUnity.CoreModule; -using OpenCVForUnity.ImgprocModule; -using OpenCVForUnity.UnityUtils; -using UnityEngine.InputSystem; - - -namespace Xarphos.Scripts -{ - [RequireComponent(typeof(Camera))] - public class DSPV_SimulationPostProcessor : MonoBehaviour - { - // // The material texture will be used as phosphene activation mask - protected Material material; - protected Texture2D input_texture; //The input texture (from webcam or virtual camera) - protected Texture2D activation_mask; //The output texture after preprocessing - - // // The shader that is used for the phosphene simulation - [SerializeField] protected Shader shader; - private static readonly int _PhospheneActivationMask = Shader.PropertyToID("_ActivationMask"); - private static readonly int _PhospheneActivation = Shader.PropertyToID("activation"); - private static readonly int _PhospheneSpecs = Shader.PropertyToID("_pSpecs"); - private static readonly int _PhospheneFilter = Shader.PropertyToID("_PhospheneFilter"); - private static readonly int _PhospheneEyePos = Shader.PropertyToID("_EyePosition"); - private static readonly int _PhospheneGazeLocked = Shader.PropertyToID("_GazeLocked"); - - - // // TODO use separate image processing shader - // protected Shader imgprocShader; - // protected Material imgprocMaterial; - - // // TODO: image processing - // // OpenCVForUnity - protected Mat in_mat; - protected Mat out_mat; - protected Mat dilateElement; - protected bool cannyFiltering = true; - - // EyeTracking - protected Vector2 eyePosition; - protected int gazeLocking; // used as boolean (sent to shader) - protected bool camLocking; - - // For reading phosphene configuration from JSON - [SerializeField] string phospheneConfigurationFile; - PhospheneConfiguration phospheneConfiguration; // is loaded from the above JSON file - - // stimulation parameters - protected float stim; - protected float[] activation; - protected float[] memoryTrace; - [SerializeField] float input_effect = 0.7f; - [SerializeField] float intensity_decay = 0.8f; - [SerializeField] float trace_increase = 0.1f; - [SerializeField] float trace_decay = 0.9f; - - protected void Awake() - { - // Initialize material, input texture and shader - material = new Material(shader); - // imgprocMaterial = new Material(imgprocShader); TODO - - input_texture = new Texture2D(512, 512, TextureFormat.RGBA32, false); - - - // Load phosphene configuration and pass to shader - phospheneConfiguration = PhospheneConfiguration.load(phospheneConfigurationFile); - material.SetVectorArray(_PhospheneSpecs, phospheneConfiguration.specifications); - material.SetInt("_nPhosphenes", phospheneConfiguration.phospheneCount); - - // Initialize other simulation variables - activation = new float[phospheneConfiguration.phospheneCount]; - memoryTrace = new float[phospheneConfiguration.phospheneCount]; - - // // OPENCV TODO - in_mat = new Mat(512, 512, CvType.CV_8UC4, new Scalar(0, 0, 0, 255)); - out_mat = new Mat(512, 512, CvType.CV_8UC4, new Scalar(0, 0, 0, 255)); - dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(3, 3)); // was new Size(9, 9)) - } - - // Postprocess the image - void OnRenderImage (RenderTexture source, RenderTexture destination) - { - //1. Read the pixels from 'source' (which is the active rendertexture by default) - input_texture.ReadPixels(new Rect(0, 0, source.width, source.height), 0, 0); - input_texture.Apply(); - - //2. Sample a subsection of the input texture for the activation mask - // TODO - - activation_mask = input_texture; - - //3. Apply image processing - if (cannyFiltering){ - Utils.texture2DToMat(input_texture,in_mat); - Imgproc.Canny(in_mat, out_mat, 110, 220); - Imgproc.dilate(out_mat, out_mat, dilateElement); - Utils.matToTexture2D(out_mat, activation_mask); - } - - //4. Calculate the phosphene activations - for (int i = 0; i < phospheneConfiguration.phospheneCount; i++){ - Vector2 pos = phospheneConfiguration.specifications[i]; // x and y coordinates - if (camLocking) { - pos += eyePosition- new Vector2(0.5f,0.5f);} - - if (pos.x > 0 && pos.x < 1 && pos.y > 0 && pos.y < 1) { - stim = activation_mask.GetPixelBilinear(pos.x, pos.y).grayscale;} - else { - stim = 0;} - activation[i] *= intensity_decay; - activation[i] += Math.Max(0,input_effect*(stim-memoryTrace[i]));//);; - memoryTrace[i] = memoryTrace[i] * trace_decay + trace_increase*stim; - } - - // 5. apply the phosphene shader - material.SetTexture(_PhospheneActivationMask, activation_mask); - material.SetFloatArray(_PhospheneActivation, activation); - material.SetVectorArray(_PhospheneSpecs, phospheneConfiguration.specifications); - Graphics.Blit (source, destination, material); - } - - protected void Update() - { - - ProcessKeyboardInput(); - - // - material.SetVector(_PhospheneEyePos, eyePosition); - material.SetInt(_PhospheneGazeLocked, gazeLocking); - } - - private void ProcessKeyboardInput() - { - if (Keyboard.current.digit1Key.isPressed) - { - cannyFiltering = false; - material.SetFloat(_PhospheneFilter, 0f); - } - - if (Keyboard.current.digit2Key.isPressed) - { - cannyFiltering = true; - material.SetFloat(_PhospheneFilter, 1f); - } - - if (Keyboard.current.digit3Key.isPressed) - { - cannyFiltering = false; - material.SetFloat(_PhospheneFilter, 1f); - } - - if (Keyboard.current.digit4Key.isPressed) - { - cannyFiltering = true; - material.SetFloat(_PhospheneFilter, 0f); - } - - if (Keyboard.current.gKey.isPressed) - { - gazeLocking = 1 - gazeLocking; - } - - if (Keyboard.current.cKey.isPressed) - { - camLocking = !camLocking; - } - - if (Keyboard.current.escapeKey.isPressed) - { -#if UNITY_EDITOR - UnityEditor.EditorApplication.isPlaying = false; -#else - Application.Quit(); -#endif - } - } - - } -} diff --git a/Scripts/DSPV_SimulationPostProcessor.cs.meta b/Scripts/DSPV_SimulationPostProcessor.cs.meta deleted file mode 100644 index 1d0e56d..0000000 --- a/Scripts/DSPV_SimulationPostProcessor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: edd7a3a668f4d93408e5efc3de49ff39 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Scripts/PhospheneConfiguration.cs b/Scripts/PhospheneConfiguration.cs deleted file mode 100644 index 9eb7b40..0000000 --- a/Scripts/PhospheneConfiguration.cs +++ /dev/null @@ -1,29 +0,0 @@ -using UnityEngine; -using System.IO; -using System.Collections.Generic; - - -namespace Xarphos.Scripts -{ - public class PhospheneConfiguration - { // Data class containing the phosphene configuration (count, locations, sizes) - // instances can be directly deseriallized from a JSON file using the 'load' method - - public string description = "PHOSPHENE SPECIFICATIONS FILE. 'phospheneCount': the number of phosphenes. 'specifications': list of phosphenes, with their screen coordinates 'x','y' (range 0 to 1). 'z' indicates phosphene size (sigma), and 'w' is unused at the moment."; - public int phospheneCount; - public Vector4[] specifications; - - public static PhospheneConfiguration load(string filename) - { - string json = System.IO.File.ReadAllText(filename); - return JsonUtility.FromJson(json); - } - - public void save(string filename) - { - string json = JsonUtility.ToJson(this); - File.WriteAllText(filename, json); - Debug.Log("Saved phosphene configuration to " + filename); - } - } -} diff --git a/Scripts/PhospheneConfiguration.cs.meta b/Scripts/PhospheneConfiguration.cs.meta deleted file mode 100644 index 0856519..0000000 --- a/Scripts/PhospheneConfiguration.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8c32d8eed77f239438ef6b8d212b3a42 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Shader/CircularMask.shader b/Shader/CircularMask.shader deleted file mode 100644 index 8a6d05e..0000000 --- a/Shader/CircularMask.shader +++ /dev/null @@ -1,143 +0,0 @@ -// Adapted from: https://github.com/umm/circle_mask_shader - -Shader "UI/CircleMask" -{ - Properties - { - [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} - _Color ("Tint", Color) = (1,1,1,1) - - _StencilComp ("Stencil Comparison", Float) = 8 - _Stencil ("Stencil ID", Float) = 0 - _StencilOp ("Stencil Operation", Float) = 0 - _StencilWriteMask ("Stencil Write Mask", Float) = 255 - _StencilReadMask ("Stencil Read Mask", Float) = 255 - - _ColorMask ("Color Mask", Float) = 15 - - _RadiusX ("Radius X", Range(0,1)) = 1 - _RadiusY ("Radius Y", Range(0,1)) = 1 - - _ScaleX ("Scale X", Float) = 1 - _ScaleY ("Scale Y", Float) = 1 - - _AntialiasThreshold ("Antialias Threshold", Range(0, 0.9999)) = 0.96 - - [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 - } - - SubShader - { - Tags - { - "Queue"="Transparent" - "IgnoreProjector"="True" - "RenderType"="Transparent" - "PreviewType"="Plane" - "CanUseSpriteAtlas"="True" - } - - Stencil - { - Ref [_Stencil] - Comp [_StencilComp] - Pass [_StencilOp] - ReadMask [_StencilReadMask] - WriteMask [_StencilWriteMask] - } - - Cull Off - Lighting Off - ZWrite Off - ZTest [unity_GUIZTestMode] - Blend SrcAlpha OneMinusSrcAlpha - ColorMask [_ColorMask] - - Pass - { - Name "Default" - CGPROGRAM - #pragma vertex vert - #pragma fragment frag - #pragma target 2.0 - - #include "UnityCG.cginc" - - #pragma multi_compile __ UNITY_UI_CLIP_RECT - #pragma multi_compile __ UNITY_UI_ALPHACLIP - - struct appdata_t - { - float4 vertex : POSITION; - float4 color : COLOR; - float2 texcoord : TEXCOORD0; - UNITY_VERTEX_INPUT_INSTANCE_ID - }; - - struct v2f - { - float4 vertex : SV_POSITION; - fixed4 color : COLOR; - float2 texcoord : TEXCOORD0; - float4 worldPosition : TEXCOORD1; - float2 originalTexcoord : TEXCOORD2; - UNITY_VERTEX_OUTPUT_STEREO - }; - - sampler2D _MainTex; - fixed4 _Color; - float4 _ClipRect; - float4 _MainTex_ST; - float _RadiusX; - float _RadiusY; - float _ScaleX; - float _ScaleY; - float _AntialiasThreshold; - - float circleDelta(float2 texcoord) { - if (_RadiusX <= 0.0001 || _RadiusY <= 0.0001) return 0; - float x = (2 * (texcoord.x - 0.5)) / _RadiusX; - float y = (2 * (texcoord.y - 0.5)) / _RadiusY; - float value = x * x + y * y; - - return smoothstep(1.0, _AntialiasThreshold, value); - } - - v2f vert(appdata_t v) - { - v2f OUT; - UNITY_SETUP_INSTANCE_ID(v); - UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); - OUT.worldPosition = v.vertex; - OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); - OUT.originalTexcoord = v.texcoord; - OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); - - OUT.color = v.color * _Color; - return OUT; - } - - fixed4 frag(v2f IN) : SV_Target - { - // scale before circle clipping - float2 size = float2(1 / _ScaleX, 1 / _ScaleY); - float2 halfSize = size * 0.5; - float2 center = float2(0.5, 0.5); - half4 color = tex2D(_MainTex, IN.texcoord * size + center - halfSize) * IN.color; - - color.a *= circleDelta(IN.texcoord); - - #ifdef UNITY_UI_CLIP_RECT - color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); - #endif - - #ifdef UNITY_UI_ALPHACLIP - clip (color.a - 0.001); - #endif - - return color; - } - ENDCG - } - } -} diff --git a/Shader/CircularMask.shader.meta b/Shader/CircularMask.shader.meta deleted file mode 100644 index c8cfb98..0000000 --- a/Shader/CircularMask.shader.meta +++ /dev/null @@ -1,10 +0,0 @@ -fileFormatVersion: 2 -guid: 1e4925d6ba257174eaef019aab0dba69 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - preprocessorOverride: 0 - userData: - assetBundleName: - assetBundleVariant: From 44fb2c354b4ee11a8a6588bb9a7311ade3349290 Mon Sep 17 00:00:00 2001 From: Mo Date: Mon, 25 Apr 2022 16:58:46 +0200 Subject: [PATCH 06/14] renamed script --- Scripts/EyeTracking.cs | 316 ++++++++++++++++++++++++++++++++++++ Scripts/EyeTracking.cs.meta | 11 ++ 2 files changed, 327 insertions(+) create mode 100644 Scripts/EyeTracking.cs create mode 100644 Scripts/EyeTracking.cs.meta diff --git a/Scripts/EyeTracking.cs b/Scripts/EyeTracking.cs new file mode 100644 index 0000000..35cd455 --- /dev/null +++ b/Scripts/EyeTracking.cs @@ -0,0 +1,316 @@ +using System; +using System.Runtime.InteropServices; +using Unity.VisualScripting; +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 + { + 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; + + + internal bool EyeTrackingAvailable { get; private set; } + +#region Unity Event Functioens + private void Start() + { + // SRanipal_Eye_v2.LaunchEyeCalibration(); // Perform calibration for eye tracking. + Invoke(nameof(SystemCheck), .5f); + Invoke(nameof(RegisterCallback), .5f); + } + + private void FixedUpdate() + { + if (!CheckFrameworkStatusErrors()) + { + EyeTrackingAvailable = false; + // Debug.LogWarning("Framework Responded failure to work."); + } + } + + private void Update() + { + if (Keyboard.current[Key.F8].wasPressedThisFrame) + { + SetDebugGazeRender(!renderGazeRays); + } + if (Keyboard.current[Key.F9].wasPressedThisFrame) + { + freezeGazeRays = !freezeGazeRays; + } + if (renderGazeRays && !freezeGazeRays) + { + UpdateGazeRays(); + } + } +#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 + private void OnDisable() + { + Release(); + } + + void OnApplicationQuit() + { + Release(); + } + + /// + /// Release callback thread when disabled or quit + /// + private static void Release() + { + if (eye_callback_registered == true) + { + SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( + Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) + ); + eye_callback_registered = false; + } + + Destroy(leftVisual); + Destroy(rightVisual); + } + + /// + /// Required class for IL2CPP scripting backend support + /// + internal class MonoPInvokeCallbackAttribute : System.Attribute + { + public MonoPInvokeCallbackAttribute() { } + } +#endregion + +#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"); + rightVisual = new GameObject("RightGazeRender"); + centreVisual = new GameObject("CentreGazeRender"); + leftGazeLine = leftVisual.AddComponent(); + { + leftGazeLine.startColor = Color.green; + leftGazeLine.endColor = Color.green; + leftGazeLine.startWidth = 0.005f; + leftGazeLine.endWidth = 0.005f; + } + rightGazeLine = rightVisual.AddComponent(); + { + rightGazeLine.startColor = Color.red; + rightGazeLine.endColor = Color.red; + rightGazeLine.startWidth = 0.005f; + rightGazeLine.endWidth = 0.005f; + } + centreGazeLine = centreVisual.AddComponent(); + { + rightGazeLine.startColor = Color.white; + rightGazeLine.endColor = Color.white; + rightGazeLine.startWidth = 0.005f; + rightGazeLine.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); + + // update render + leftGazeLine.SetPositions(new [] { leftOrigin, leftOrigin + leftDir * 20 }); + rightGazeLine.SetPositions(new [] { rightOrigin, rightOrigin + rightDir * 20 }); + centreGazeLine.SetPositions(new[] { centreOrigin, centreOrigin + centreDir * 20 }); + } +#endregion + } +} diff --git a/Scripts/EyeTracking.cs.meta b/Scripts/EyeTracking.cs.meta new file mode 100644 index 0000000..7dfa96c --- /dev/null +++ b/Scripts/EyeTracking.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7e6fb78bd046e54dbc6ec6200589850 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 822474e9896e5002a1445b93e681c2dff5bbb9df Mon Sep 17 00:00:00 2001 From: Mo Date: Mon, 25 Apr 2022 16:59:12 +0200 Subject: [PATCH 07/14] obsolete file --- pSpecs1.json | 1 - pSpecs1.json.meta | 7 ------- 2 files changed, 8 deletions(-) delete mode 100644 pSpecs1.json delete mode 100644 pSpecs1.json.meta diff --git a/pSpecs1.json b/pSpecs1.json deleted file mode 100644 index f418992..0000000 --- a/pSpecs1.json +++ /dev/null @@ -1 +0,0 @@ -{"description":"PHOSPHENE SPECIFICATIONS FILE. 'phospheneCount': the number of phosphenes. 'specifications': list of phosphenes, with their screen coordinates 'x','y' (range 0 to 1). 'z' indicates phosphene size (sigma), and 'w' is unused at the moment.","phospheneCount":1000,"specifications":[{"x":0.6039215922355652,"y":0.5372549295425415,"z":0.16862745583057404,"w":1.0},{"x":0.0117647061124444,"y":0.21960784494876862,"z":0.8627451062202454,"w":1.0},{"x":0.4156862795352936,"y":0.13725490868091584,"z":0.5764706134796143,"w":1.0},{"x":0.6784313917160034,"y":0.3019607961177826,"z":0.40784314274787905,"w":1.0},{"x":0.7137255072593689,"y":0.5843137502670288,"z":0.3450980484485626,"w":1.0},{"x":0.35686275362968447,"y":0.33725491166114809,"z":0.33725491166114809,"w":1.0},{"x":0.4313725531101227,"y":0.5607843399047852,"z":0.1411764770746231,"w":1.0},{"x":0.5921568870544434,"y":0.501960813999176,"z":0.1411764770746231,"w":1.0},{"x":0.5098039507865906,"y":0.2705882489681244,"z":0.3529411852359772,"w":1.0},{"x":0.501960813999176,"y":0.7607843279838562,"z":0.3960784375667572,"w":1.0},{"x":0.5647059082984924,"y":0.5254902243614197,"z":0.10588235408067703,"w":1.0},{"x":0.33725491166114809,"y":0.529411792755127,"z":0.2549019753932953,"w":1.0},{"x":0.3176470696926117,"y":0.364705890417099,"z":0.3529411852359772,"w":1.0},{"x":0.42352941632270815,"y":0.37254902720451357,"z":0.23137255012989045,"w":1.0},{"x":0.8745098114013672,"y":0.95686274766922,"z":0.8980392217636108,"w":1.0},{"x":0.3921568691730499,"y":0.5411764979362488,"z":0.18039216101169587,"w":1.0},{"x":0.27450981736183169,"y":0.7333333492279053,"z":0.49803921580314639,"w":1.0},{"x":0.8745098114013672,"y":0.9960784316062927,"z":0.9411764740943909,"w":1.0},{"x":0.6352941393852234,"y":0.46666666865348818,"z":0.21176470816135407,"w":1.0},{"x":0.8901960849761963,"y":0.21568627655506135,"z":0.7333333492279053,"w":1.0},{"x":0.6313725709915161,"y":0.30980393290519717,"z":0.3529411852359772,"w":1.0},{"x":0.843137264251709,"y":0.4274509847164154,"z":0.529411792755127,"w":1.0},{"x":0.1411764770746231,"y":0.6784313917160034,"z":0.6117647290229797,"w":1.0},{"x":0.8823529481887817,"y":0.729411780834198,"z":0.6745098233222961,"w":1.0},{"x":0.3803921639919281,"y":0.29411765933036806,"z":0.3686274588108063,"w":1.0},{"x":0.23529411852359773,"y":0.5333333611488342,"z":0.40784314274787905,"w":1.0},{"x":0.6196078658103943,"y":0.23529411852359773,"z":0.4470588266849518,"w":1.0},{"x":0.3137255012989044,"y":0.09019608050584793,"z":0.6941176652908325,"w":1.0},{"x":0.5098039507865906,"y":0.10196078568696976,"z":0.6117647290229797,"w":1.0},{"x":0.4588235318660736,"y":0.5372549295425415,"z":0.08627451211214066,"w":1.0},{"x":0.5333333611488342,"y":0.40392157435417178,"z":0.16078431904315949,"w":1.0},{"x":0.5176470875740051,"y":0.18431372940540315,"z":0.48235294222831728,"w":1.0},{"x":0.6470588445663452,"y":0.4745098054409027,"z":0.22745098173618318,"w":1.0},{"x":0.38823530077934267,"y":0.4313725531101227,"z":0.20392157137393952,"w":1.0},{"x":0.40392157435417178,"y":0.3686274588108063,"z":0.250980406999588,"w":1.0},{"x":0.7450980544090271,"y":0.14901961386203767,"z":0.6549019813537598,"w":1.0},{"x":0.6274510025978088,"y":0.43921568989753725,"z":0.21568627655506135,"w":1.0},{"x":0.6431372761726379,"y":0.054901961237192157,"z":0.7137255072593689,"w":1.0},{"x":0.4941176474094391,"y":0.41960784792900088,"z":0.125490203499794,"w":1.0},{"x":0.027450980618596078,"y":0.1921568661928177,"z":0.8627451062202454,"w":1.0},{"x":0.6431372761726379,"y":0.7254902124404907,"z":0.40392157435417178,"w":1.0},{"x":0.6039215922355652,"y":0.5843137502670288,"z":0.20000000298023225,"w":1.0},{"x":0.529411792755127,"y":0.47843137383461,"z":0.05882352963089943,"w":1.0},{"x":0.5882353186607361,"y":0.45490196347236636,"z":0.15294118225574494,"w":1.0},{"x":0.3803921639919281,"y":0.41960784792900088,"z":0.22745098173618318,"w":1.0},{"x":0.3960784375667572,"y":0.6039215922355652,"z":0.22745098173618318,"w":1.0},{"x":0.7568627595901489,"y":0.6941176652908325,"z":0.4901960790157318,"w":1.0},{"x":0.3843137323856354,"y":0.48235294222831728,"z":0.18431372940540315,"w":1.0},{"x":0.5215686559677124,"y":0.5254902243614197,"z":0.05098039284348488,"w":1.0},{"x":0.5098039507865906,"y":0.7568627595901489,"z":0.3921568691730499,"w":1.0},{"x":0.5882353186607361,"y":0.7058823704719544,"z":0.33725491166114809,"w":1.0},{"x":0.18431372940540315,"y":0.3137255012989044,"z":0.5647059082984924,"w":1.0},{"x":0.7137255072593689,"y":0.47843137383461,"z":0.32549020648002627,"w":1.0},{"x":0.3686274588108063,"y":0.6549019813537598,"z":0.3137255012989044,"w":1.0},{"x":0.6078431606292725,"y":0.6509804129600525,"z":0.2823529541492462,"w":1.0},{"x":0.5607843399047852,"y":0.4745098054409027,"z":0.09803921729326248,"w":1.0},{"x":0.5137255191802979,"y":0.3803921639919281,"z":0.1921568661928177,"w":1.0},{"x":0.5607843399047852,"y":0.6117647290229797,"z":0.1921568661928177,"w":1.0},{"x":0.29411765933036806,"y":0.3529411852359772,"z":0.3921568691730499,"w":1.0},{"x":0.3529411852359772,"y":0.5411764979362488,"z":0.23529411852359773,"w":1.0},{"x":0.7568627595901489,"y":0.4313725531101227,"z":0.40392157435417178,"w":1.0},{"x":0.615686297416687,"y":0.7607843279838562,"z":0.4313725531101227,"w":1.0},{"x":0.4470588266849518,"y":0.4431372582912445,"z":0.12156862765550614,"w":1.0},{"x":0.07058823853731156,"y":0.6549019813537598,"z":0.6980392336845398,"w":1.0},{"x":0.4313725531101227,"y":0.5843137502670288,"z":0.16470588743686677,"w":1.0},{"x":0.5176470875740051,"y":0.3450980484485626,"z":0.239215686917305,"w":1.0},{"x":0.6745098233222961,"y":0.9803921580314636,"z":0.7764706015586853,"w":1.0},{"x":0.4117647111415863,"y":0.5058823823928833,"z":0.1411764770746231,"w":1.0},{"x":0.4156862795352936,"y":0.5176470875740051,"z":0.13333334028720857,"w":1.0},{"x":0.572549045085907,"y":0.7764706015586853,"z":0.4313725531101227,"w":1.0},{"x":0.5215686559677124,"y":0.7843137383460999,"z":0.4313725531101227,"w":1.0},{"x":0.5254902243614197,"y":0.6666666865348816,"z":0.2549019753932953,"w":1.0},{"x":0.6901960968971252,"y":0.27843138575553896,"z":0.4470588266849518,"w":1.0},{"x":0.33725491166114809,"y":0.4000000059604645,"z":0.2980392277240753,"w":1.0},{"x":0.37254902720451357,"y":0.4588235318660736,"z":0.21176470816135407,"w":1.0},{"x":0.4313725531101227,"y":1.0,"z":0.7686274647712708,"w":1.0},{"x":0.6039215922355652,"y":0.529411792755127,"z":0.16862745583057404,"w":1.0},{"x":0.5137255191802979,"y":0.6039215922355652,"z":0.16078431904315949,"w":1.0},{"x":0.7882353067398071,"y":0.4627451002597809,"z":0.4431372582912445,"w":1.0},{"x":0.5098039507865906,"y":0.5960784554481506,"z":0.14901961386203767,"w":1.0},{"x":0.9607843160629273,"y":0.10588235408067703,"z":0.9254902005195618,"w":1.0},{"x":0.2705882489681244,"y":0.5529412031173706,"z":0.3607843220233917,"w":1.0},{"x":0.5098039507865906,"y":0.49803921580314639,"z":0.01568627543747425,"w":1.0},{"x":0.7568627595901489,"y":0.6235294342041016,"z":0.4313725531101227,"w":1.0},{"x":0.8823529481887817,"y":0.7882353067398071,"z":0.7254902124404907,"w":1.0},{"x":0.5098039507865906,"y":0.5176470875740051,"z":0.0313725508749485,"w":1.0},{"x":0.6274510025978088,"y":0.6039215922355652,"z":0.24705882370471955,"w":1.0},{"x":0.5372549295425415,"y":0.6431372761726379,"z":0.2235294133424759,"w":1.0},{"x":0.46666666865348818,"y":0.47843137383461,"z":0.06666667014360428,"w":1.0},{"x":0.11764705926179886,"y":0.545098066329956,"z":0.5921568870544434,"w":1.0},{"x":0.30980393290519717,"y":0.6784313917160034,"z":0.4000000059604645,"w":1.0},{"x":0.27450981736183169,"y":0.46666666865348818,"z":0.3529411852359772,"w":1.0},{"x":0.7019608020782471,"y":0.7372549176216126,"z":0.47058823704719546,"w":1.0},{"x":0.3333333432674408,"y":0.4431372582912445,"z":0.2705882489681244,"w":1.0},{"x":0.6313725709915161,"y":0.6000000238418579,"z":0.250980406999588,"w":1.0},{"x":0.6078431606292725,"y":0.27843138575553896,"z":0.3803921639919281,"w":1.0},{"x":0.2666666805744171,"y":0.30980393290519717,"z":0.46666666865348818,"w":1.0},{"x":0.45098039507865908,"y":0.43921568989753725,"z":0.12941177189350129,"w":1.0},{"x":0.800000011920929,"y":0.4901960790157318,"z":0.4588235318660736,"w":1.0},{"x":0.19607843458652497,"y":0.1882352977991104,"z":0.6666666865348816,"w":1.0},{"x":0.43921568989753725,"y":0.250980406999588,"z":0.3921568691730499,"w":1.0},{"x":0.4274509847164154,"y":0.364705890417099,"z":0.239215686917305,"w":1.0},{"x":0.34117648005485537,"y":0.2078431397676468,"z":0.5098039507865906,"w":1.0},{"x":0.5254902243614197,"y":0.6745098233222961,"z":0.26274511218070986,"w":1.0},{"x":0.658823549747467,"y":0.29411765933036806,"z":0.3960784375667572,"w":1.0},{"x":0.9215686321258545,"y":0.23529411852359773,"z":0.7568627595901489,"w":1.0},{"x":0.4588235318660736,"y":0.6549019813537598,"z":0.24313725531101228,"w":1.0},{"x":0.30980393290519717,"y":0.01568627543747425,"z":0.800000011920929,"w":1.0},{"x":0.6666666865348816,"y":0.3490196168422699,"z":0.34117648005485537,"w":1.0},{"x":0.6196078658103943,"y":0.6117647290229797,"z":0.24705882370471955,"w":1.0},{"x":0.46666666865348818,"y":0.21960784494876862,"z":0.43529412150382998,"w":1.0},{"x":0.5411764979362488,"y":0.18431372940540315,"z":0.48627451062202456,"w":1.0},{"x":0.5176470875740051,"y":0.7450980544090271,"z":0.37254902720451357,"w":1.0},{"x":0.5372549295425415,"y":0.5333333611488342,"z":0.07450980693101883,"w":1.0},{"x":0.4745098054409027,"y":0.5254902243614197,"z":0.05882352963089943,"w":1.0},{"x":0.3019607961177826,"y":0.2823529541492462,"z":0.45098039507865908,"w":1.0},{"x":0.4941176474094391,"y":0.9411764740943909,"z":0.6666666865348816,"w":1.0},{"x":0.5058823823928833,"y":0.5686274766921997,"z":0.10588235408067703,"w":1.0},{"x":0.23137255012989045,"y":0.6352941393852234,"z":0.4627451002597809,"w":1.0},{"x":0.13333334028720857,"y":0.7098039388656616,"z":0.6431372761726379,"w":1.0},{"x":0.47058823704719546,"y":0.7215686440467835,"z":0.34117648005485537,"w":1.0},{"x":0.6823529601097107,"y":0.6392157077789307,"z":0.3490196168422699,"w":1.0},{"x":0.47843137383461,"y":0.24313725531101228,"z":0.3960784375667572,"w":1.0},{"x":0.20392157137393952,"y":0.46666666865348818,"z":0.4588235318660736,"w":1.0},{"x":0.529411792755127,"y":0.41960784792900088,"z":0.13725490868091584,"w":1.0},{"x":0.27450981736183169,"y":0.5529412031173706,"z":0.3529411852359772,"w":1.0},{"x":0.3921568691730499,"y":0.4117647111415863,"z":0.21960784494876862,"w":1.0},{"x":0.7450980544090271,"y":0.8509804010391235,"z":0.6470588445663452,"w":1.0},{"x":0.5647059082984924,"y":0.7686274647712708,"z":0.41960784792900088,"w":1.0},{"x":0.5098039507865906,"y":0.3960784375667572,"z":0.16470588743686677,"w":1.0},{"x":0.7686274647712708,"y":0.545098066329956,"z":0.4117647111415863,"w":1.0},{"x":0.6117647290229797,"y":0.5058823823928833,"z":0.16862745583057404,"w":1.0},{"x":0.49803921580314639,"y":0.5137255191802979,"z":0.019607843831181527,"w":1.0},{"x":0.7254902124404907,"y":0.25882354378700259,"z":0.5058823823928833,"w":1.0},{"x":0.9803921580314636,"y":0.5490196347236633,"z":0.729411780834198,"w":1.0},{"x":0.3137255012989044,"y":0.6470588445663452,"z":0.364705890417099,"w":1.0},{"x":0.572549045085907,"y":0.5607843399047852,"z":0.1411764770746231,"w":1.0},{"x":0.32549020648002627,"y":0.8117647171020508,"z":0.5490196347236633,"w":1.0},{"x":0.4627451002597809,"y":0.6000000238418579,"z":0.16470588743686677,"w":1.0},{"x":0.10588235408067703,"y":0.43529412150382998,"z":0.6117647290229797,"w":1.0},{"x":0.3450980484485626,"y":0.3686274588108063,"z":0.3176470696926117,"w":1.0},{"x":0.6117647290229797,"y":0.5215686559677124,"z":0.1725490242242813,"w":1.0},{"x":0.43921568989753725,"y":0.2980392277240753,"z":0.3294117748737335,"w":1.0},{"x":0.20000000298023225,"y":0.7098039388656616,"z":0.5647059082984924,"w":1.0},{"x":0.6823529601097107,"y":0.4156862795352936,"z":0.30588236451148989,"w":1.0},{"x":0.35686275362968447,"y":0.7372549176216126,"z":0.42352941632270815,"w":1.0},{"x":0.37254902720451357,"y":0.729411780834198,"z":0.4000000059604645,"w":1.0},{"x":0.2862745225429535,"y":0.8941176533699036,"z":0.6823529601097107,"w":1.0},{"x":0.48627451062202456,"y":0.5176470875740051,"z":0.03921568766236305,"w":1.0},{"x":0.7921568751335144,"y":0.14901961386203767,"z":0.6941176652908325,"w":1.0},{"x":0.6823529601097107,"y":0.7098039388656616,"z":0.42352941632270815,"w":1.0},{"x":0.6235294342041016,"y":0.27450981736183169,"z":0.4000000059604645,"w":1.0},{"x":0.7333333492279053,"y":0.3843137323856354,"z":0.3960784375667572,"w":1.0},{"x":0.9333333373069763,"y":0.6549019813537598,"z":0.6980392336845398,"w":1.0},{"x":0.3176470696926117,"y":0.38823530077934267,"z":0.3333333432674408,"w":1.0},{"x":0.46666666865348818,"y":0.9098039269447327,"z":0.6235294342041016,"w":1.0},{"x":0.6196078658103943,"y":0.2862745225429535,"z":0.37254902720451357,"w":1.0},{"x":0.4431372582912445,"y":0.4941176474094391,"z":0.09019608050584793,"w":1.0},{"x":0.46666666865348818,"y":0.20392157137393952,"z":0.4588235318660736,"w":1.0},{"x":0.5215686559677124,"y":0.5882353186607361,"z":0.13725490868091584,"w":1.0},{"x":0.32156863808631899,"y":0.6627451181411743,"z":0.3686274588108063,"w":1.0},{"x":0.6000000238418579,"y":0.6039215922355652,"z":0.21960784494876862,"w":1.0},{"x":0.5568627715110779,"y":0.572549045085907,"z":0.1411764770746231,"w":1.0},{"x":0.7529411911964417,"y":0.7372549176216126,"z":0.5254902243614197,"w":1.0},{"x":0.48235294222831728,"y":0.43921568989753725,"z":0.10588235408067703,"w":1.0},{"x":0.5333333611488342,"y":0.6549019813537598,"z":0.239215686917305,"w":1.0},{"x":0.7215686440467835,"y":0.5333333611488342,"z":0.33725491166114809,"w":1.0},{"x":0.4588235318660736,"y":0.4313725531101227,"z":0.12941177189350129,"w":1.0},{"x":0.4627451002597809,"y":0.8901960849761963,"z":0.5960784554481506,"w":1.0},{"x":0.7960784435272217,"y":0.05098039284348488,"z":0.8196078538894653,"w":1.0},{"x":0.32156863808631899,"y":0.3294117748737335,"z":0.3803921639919281,"w":1.0},{"x":0.4588235318660736,"y":0.5058823823928833,"z":0.07058823853731156,"w":1.0},{"x":0.16862745583057404,"y":0.23529411852359773,"z":0.6509804129600525,"w":1.0},{"x":0.5764706134796143,"y":0.27843138575553896,"z":0.3607843220233917,"w":1.0},{"x":0.14509804546833039,"y":0.0941176488995552,"z":0.8274509906768799,"w":1.0},{"x":0.6039215922355652,"y":0.34117648005485537,"z":0.29411765933036806,"w":1.0},{"x":0.5372549295425415,"y":0.7176470756530762,"z":0.3333333432674408,"w":1.0},{"x":0.572549045085907,"y":0.3490196168422699,"z":0.25882354378700259,"w":1.0},{"x":0.615686297416687,"y":0.5176470875740051,"z":0.1764705926179886,"w":1.0},{"x":0.572549045085907,"y":0.08235294371843338,"z":0.6470588445663452,"w":1.0},{"x":0.2705882489681244,"y":0.7215686440467835,"z":0.48627451062202456,"w":1.0},{"x":0.4431372582912445,"y":0.3686274588108063,"z":0.2235294133424759,"w":1.0},{"x":0.572549045085907,"y":0.5411764979362488,"z":0.125490203499794,"w":1.0},{"x":0.6431372761726379,"y":0.3960784375667572,"z":0.2705882489681244,"w":1.0},{"x":0.6352941393852234,"y":0.125490203499794,"z":0.6117647290229797,"w":1.0},{"x":0.4431372582912445,"y":0.34117648005485537,"z":0.26274511218070986,"w":1.0},{"x":0.5803921818733215,"y":0.3450980484485626,"z":0.2705882489681244,"w":1.0},{"x":0.4156862795352936,"y":0.5529412031173706,"z":0.1568627506494522,"w":1.0},{"x":0.35686275362968447,"y":0.6039215922355652,"z":0.27450981736183169,"w":1.0},{"x":0.4901960790157318,"y":0.5137255191802979,"z":0.027450980618596078,"w":1.0},{"x":0.6745098233222961,"y":0.6117647290229797,"z":0.3137255012989044,"w":1.0},{"x":0.5058823823928833,"y":0.37254902720451357,"z":0.20000000298023225,"w":1.0},{"x":0.6941176652908325,"y":0.30588236451148989,"z":0.4156862795352936,"w":1.0},{"x":0.4588235318660736,"y":0.5686274766921997,"z":0.12156862765550614,"w":1.0},{"x":0.5803921818733215,"y":0.5411764979362488,"z":0.13725490868091584,"w":1.0},{"x":0.7568627595901489,"y":0.1568627506494522,"z":0.6509804129600525,"w":1.0},{"x":0.49803921580314639,"y":0.7921568751335144,"z":0.4470588266849518,"w":1.0},{"x":0.05882352963089943,"y":0.46666666865348818,"z":0.6745098233222961,"w":1.0},{"x":0.5058823823928833,"y":0.4627451002597809,"z":0.062745101749897,"w":1.0},{"x":0.7098039388656616,"y":0.5333333611488342,"z":0.32549020648002627,"w":1.0},{"x":0.48627451062202456,"y":0.33725491166114809,"z":0.2549019753932953,"w":1.0},{"x":0.7098039388656616,"y":0.16470588743686677,"z":0.6039215922355652,"w":1.0},{"x":0.3294117748737335,"y":0.6627451181411743,"z":0.3607843220233917,"w":1.0},{"x":0.4470588266849518,"y":0.6313725709915161,"z":0.21960784494876862,"w":1.0},{"x":0.43921568989753725,"y":0.8078431487083435,"z":0.4745098054409027,"w":1.0},{"x":0.32549020648002627,"y":0.7372549176216126,"z":0.4470588266849518,"w":1.0},{"x":0.5843137502670288,"y":0.41960784792900088,"z":0.1764705926179886,"w":1.0},{"x":0.6313725709915161,"y":0.3921568691730499,"z":0.25882354378700259,"w":1.0},{"x":0.5215686559677124,"y":0.34117648005485537,"z":0.250980406999588,"w":1.0},{"x":0.16470588743686677,"y":0.8078431487083435,"z":0.6941176652908325,"w":1.0},{"x":0.35686275362968447,"y":0.37254902720451357,"z":0.2980392277240753,"w":1.0},{"x":0.49803921580314639,"y":0.3607843220233917,"z":0.21960784494876862,"w":1.0},{"x":0.6705882549285889,"y":0.8392156958580017,"z":0.572549045085907,"w":1.0},{"x":0.26274511218070986,"y":0.3137255012989044,"z":0.4627451002597809,"w":1.0},{"x":0.6000000238418579,"y":0.5333333611488342,"z":0.1568627506494522,"w":1.0},{"x":0.6235294342041016,"y":0.20392157137393952,"z":0.4941176474094391,"w":1.0},{"x":0.46666666865348818,"y":0.4745098054409027,"z":0.06666667014360428,"w":1.0},{"x":0.7333333492279053,"y":0.5803921818733215,"z":0.3764705955982208,"w":1.0},{"x":0.42352941632270815,"y":0.7176470756530762,"z":0.3490196168422699,"w":1.0},{"x":0.2980392277240753,"y":0.4901960790157318,"z":0.3137255012989044,"w":1.0},{"x":0.572549045085907,"y":0.45098039507865908,"z":0.13725490868091584,"w":1.0},{"x":0.5607843399047852,"y":0.24313725531101228,"z":0.40784314274787905,"w":1.0},{"x":0.3960784375667572,"y":0.529411792755127,"z":0.16862745583057404,"w":1.0},{"x":0.5764706134796143,"y":0.3333333432674408,"z":0.2823529541492462,"w":1.0},{"x":0.5803921818733215,"y":0.729411780834198,"z":0.3686274588108063,"w":1.0},{"x":0.24705882370471955,"y":0.5803921818733215,"z":0.40392157435417178,"w":1.0},{"x":0.3843137323856354,"y":0.6352941393852234,"z":0.2705882489681244,"w":1.0},{"x":0.250980406999588,"y":0.5333333611488342,"z":0.3843137323856354,"w":1.0},{"x":0.5058823823928833,"y":0.6901960968971252,"z":0.29019609093666079,"w":1.0},{"x":0.3803921639919281,"y":0.7019608020782471,"z":0.35686275362968447,"w":1.0},{"x":0.7333333492279053,"y":0.32156863808631899,"z":0.45098039507865908,"w":1.0},{"x":0.5529412031173706,"y":0.43921568989753725,"z":0.125490203499794,"w":1.0},{"x":0.6745098233222961,"y":0.41960784792900088,"z":0.29411765933036806,"w":1.0},{"x":0.47843137383461,"y":0.6196078658103943,"z":0.18431372940540315,"w":1.0},{"x":0.19607843458652497,"y":0.7254902124404907,"z":0.5764706134796143,"w":1.0},{"x":0.6039215922355652,"y":0.4470588266849518,"z":0.18039216101169587,"w":1.0},{"x":0.27843138575553896,"y":0.6431372761726379,"z":0.40392157435417178,"w":1.0},{"x":0.5333333611488342,"y":0.5529412031173706,"z":0.0941176488995552,"w":1.0},{"x":0.7019608020782471,"y":0.2705882489681244,"z":0.47058823704719546,"w":1.0},{"x":0.4117647111415863,"y":0.6274510025978088,"z":0.239215686917305,"w":1.0},{"x":0.6745098233222961,"y":0.04313725605607033,"z":0.7450980544090271,"w":1.0},{"x":0.3450980484485626,"y":0.7686274647712708,"z":0.4745098054409027,"w":1.0},{"x":0.5921568870544434,"y":0.615686297416687,"z":0.21960784494876862,"w":1.0},{"x":0.3019607961177826,"y":0.572549045085907,"z":0.3294117748737335,"w":1.0},{"x":0.658823549747467,"y":0.46666666865348818,"z":0.24705882370471955,"w":1.0},{"x":0.364705890417099,"y":0.5490196347236633,"z":0.2235294133424759,"w":1.0},{"x":0.6117647290229797,"y":0.6431372761726379,"z":0.27450981736183169,"w":1.0},{"x":0.5764706134796143,"y":0.5607843399047852,"z":0.14901961386203767,"w":1.0},{"x":0.5372549295425415,"y":0.529411792755127,"z":0.07058823853731156,"w":1.0},{"x":0.43921568989753725,"y":0.9607843160629273,"z":0.7058823704719544,"w":1.0},{"x":0.6039215922355652,"y":0.4000000059604645,"z":0.21960784494876862,"w":1.0},{"x":0.4000000059604645,"y":0.658823549747467,"z":0.29019609093666079,"w":1.0},{"x":0.3686274588108063,"y":0.2549019753932953,"z":0.4313725531101227,"w":1.0},{"x":0.5411764979362488,"y":0.6313725709915161,"z":0.2078431397676468,"w":1.0},{"x":0.239215686917305,"y":0.5333333611488342,"z":0.40392157435417178,"w":1.0},{"x":0.48627451062202456,"y":0.5098039507865906,"z":0.027450980618596078,"w":1.0},{"x":0.47058823704719546,"y":0.7882353067398071,"z":0.43921568989753725,"w":1.0},{"x":0.5686274766921997,"y":0.3843137323856354,"z":0.2078431397676468,"w":1.0},{"x":0.25882354378700259,"y":0.6039215922355652,"z":0.4000000059604645,"w":1.0},{"x":0.5137255191802979,"y":0.5843137502670288,"z":0.13333334028720857,"w":1.0},{"x":0.6980392336845398,"y":0.2980392277240753,"z":0.4313725531101227,"w":1.0},{"x":0.21176470816135407,"y":0.2549019753932953,"z":0.5803921818733215,"w":1.0},{"x":0.4431372582912445,"y":0.615686297416687,"z":0.19607843458652497,"w":1.0},{"x":0.3803921639919281,"y":0.5098039507865906,"z":0.1882352977991104,"w":1.0},{"x":0.45098039507865908,"y":0.6117647290229797,"z":0.1882352977991104,"w":1.0},{"x":0.5843137502670288,"y":0.3333333432674408,"z":0.2862745225429535,"w":1.0},{"x":0.250980406999588,"y":0.47843137383461,"z":0.3843137323856354,"w":1.0},{"x":0.6745098233222961,"y":0.48627451062202456,"z":0.26274511218070986,"w":1.0},{"x":0.48627451062202456,"y":0.5137255191802979,"z":0.03529411926865578,"w":1.0},{"x":0.3294117748737335,"y":0.3529411852359772,"z":0.3450980484485626,"w":1.0},{"x":0.7490196228027344,"y":0.6235294342041016,"z":0.41960784792900088,"w":1.0},{"x":0.529411792755127,"y":0.8392156958580017,"z":0.5176470875740051,"w":1.0},{"x":0.5176470875740051,"y":0.615686297416687,"z":0.1764705926179886,"w":1.0},{"x":0.4000000059604645,"y":0.43529412150382998,"z":0.1882352977991104,"w":1.0},{"x":0.5372549295425415,"y":0.4588235318660736,"z":0.09019608050584793,"w":1.0},{"x":0.615686297416687,"y":0.8705882430076599,"z":0.5882353186607361,"w":1.0},{"x":0.7411764860153198,"y":0.6509804129600525,"z":0.4313725531101227,"w":1.0},{"x":0.545098066329956,"y":0.7176470756530762,"z":0.33725491166114809,"w":1.0},{"x":0.4470588266849518,"y":0.8156862854957581,"z":0.48627451062202456,"w":1.0},{"x":0.3176470696926117,"y":0.45490196347236636,"z":0.29411765933036806,"w":1.0},{"x":0.3529411852359772,"y":0.3019607961177826,"z":0.3843137323856354,"w":1.0},{"x":0.0784313753247261,"y":0.32156863808631899,"z":0.7058823704719544,"w":1.0},{"x":0.22745098173618318,"y":0.5529412031173706,"z":0.4274509847164154,"w":1.0},{"x":0.5647059082984924,"y":0.5647059082984924,"z":0.13333334028720857,"w":1.0},{"x":0.6431372761726379,"y":0.6941176652908325,"z":0.3686274588108063,"w":1.0},{"x":0.43921568989753725,"y":0.40392157435417178,"z":0.18039216101169587,"w":1.0},{"x":0.43921568989753725,"y":0.37254902720451357,"z":0.21960784494876862,"w":1.0},{"x":0.47843137383461,"y":0.6196078658103943,"z":0.18431372940540315,"w":1.0},{"x":0.5176470875740051,"y":0.5411764979362488,"z":0.06666667014360428,"w":1.0},{"x":0.7686274647712708,"y":0.1921568661928177,"z":0.6274510025978088,"w":1.0},{"x":0.13333334028720857,"y":0.6509804129600525,"z":0.6078431606292725,"w":1.0},{"x":0.5882353186607361,"y":0.09803921729326248,"z":0.6274510025978088,"w":1.0},{"x":0.20000000298023225,"y":0.7019608020782471,"z":0.5490196347236633,"w":1.0},{"x":0.6392157077789307,"y":0.2078431397676468,"z":0.49803921580314639,"w":1.0},{"x":0.6039215922355652,"y":0.5843137502670288,"z":0.20392157137393952,"w":1.0},{"x":0.7529411911964417,"y":0.3960784375667572,"z":0.4156862795352936,"w":1.0},{"x":0.3176470696926117,"y":0.3843137323856354,"z":0.33725491166114809,"w":1.0},{"x":0.38823530077934267,"y":0.5960784554481506,"z":0.22745098173618318,"w":1.0},{"x":0.3803921639919281,"y":0.6117647290229797,"z":0.250980406999588,"w":1.0},{"x":0.6470588445663452,"y":0.7647058963775635,"z":0.4588235318660736,"w":1.0},{"x":0.3686274588108063,"y":0.4000000059604645,"z":0.2549019753932953,"w":1.0},{"x":0.19607843458652497,"y":0.5882353186607361,"z":0.48627451062202456,"w":1.0},{"x":0.6549019813537598,"y":0.7176470756530762,"z":0.40784314274787905,"w":1.0},{"x":0.6431372761726379,"y":0.6196078658103943,"z":0.2823529541492462,"w":1.0},{"x":0.3333333432674408,"y":0.3803921639919281,"z":0.3137255012989044,"w":1.0},{"x":0.6627451181411743,"y":0.5921568870544434,"z":0.2823529541492462,"w":1.0},{"x":0.5058823823928833,"y":0.47843137383461,"z":0.04313725605607033,"w":1.0},{"x":0.6941176652908325,"y":0.8235294222831726,"z":0.572549045085907,"w":1.0},{"x":0.1921568661928177,"y":0.6235294342041016,"z":0.5058823823928833,"w":1.0},{"x":0.29019609093666079,"y":0.5411764979362488,"z":0.3294117748737335,"w":1.0},{"x":0.8117647171020508,"y":0.6470588445663452,"z":0.5215686559677124,"w":1.0},{"x":0.5372549295425415,"y":0.21176470816135407,"z":0.45098039507865908,"w":1.0},{"x":0.10980392247438431,"y":0.3921568691730499,"z":0.6196078658103943,"w":1.0},{"x":0.5647059082984924,"y":0.4588235318660736,"z":0.11764705926179886,"w":1.0},{"x":0.38823530077934267,"y":0.45098039507865908,"z":0.1921568661928177,"w":1.0},{"x":0.6196078658103943,"y":0.5176470875740051,"z":0.18431372940540315,"w":1.0},{"x":0.6705882549285889,"y":0.7490196228027344,"z":0.45490196347236636,"w":1.0},{"x":0.25882354378700259,"y":0.3294117748737335,"z":0.45490196347236636,"w":1.0},{"x":0.4274509847164154,"y":0.7137255072593689,"z":0.3450980484485626,"w":1.0},{"x":0.7803921699523926,"y":0.33725491166114809,"z":0.4941176474094391,"w":1.0},{"x":0.4470588266849518,"y":0.37254902720451357,"z":0.21568627655506135,"w":1.0},{"x":0.5254902243614197,"y":0.5803921818733215,"z":0.12941177189350129,"w":1.0},{"x":0.40784314274787905,"y":0.615686297416687,"z":0.22745098173618318,"w":1.0},{"x":0.47843137383461,"y":0.5529412031173706,"z":0.08627451211214066,"w":1.0},{"x":0.43921568989753725,"y":0.6392157077789307,"z":0.23529411852359773,"w":1.0},{"x":0.5647059082984924,"y":0.545098066329956,"z":0.11764705926179886,"w":1.0},{"x":0.6431372761726379,"y":0.250980406999588,"z":0.43921568989753725,"w":1.0},{"x":0.6823529601097107,"y":0.545098066329956,"z":0.2823529541492462,"w":1.0},{"x":0.5058823823928833,"y":0.6509804129600525,"z":0.22745098173618318,"w":1.0},{"x":0.5254902243614197,"y":0.2862745225429535,"z":0.3333333432674408,"w":1.0},{"x":0.8509804010391235,"y":0.33725491166114809,"z":0.5921568870544434,"w":1.0},{"x":0.40784314274787905,"y":0.41960784792900088,"z":0.1921568661928177,"w":1.0},{"x":0.6078431606292725,"y":0.30980393290519717,"z":0.33725491166114809,"w":1.0},{"x":0.6078431606292725,"y":0.6431372761726379,"z":0.27450981736183169,"w":1.0},{"x":0.529411792755127,"y":0.7529411911964417,"z":0.38823530077934267,"w":1.0},{"x":0.24313725531101228,"y":0.1921568661928177,"z":0.615686297416687,"w":1.0},{"x":0.37254902720451357,"y":0.3803921639919281,"z":0.2705882489681244,"w":1.0},{"x":0.7098039388656616,"y":0.26274511218070986,"z":0.48627451062202456,"w":1.0},{"x":0.5098039507865906,"y":0.5372549295425415,"z":0.054901961237192157,"w":1.0},{"x":0.48627451062202456,"y":0.7647058963775635,"z":0.40392157435417178,"w":1.0},{"x":0.5058823823928833,"y":0.1568627506494522,"z":0.529411792755127,"w":1.0},{"x":0.6039215922355652,"y":0.40784314274787905,"z":0.21568627655506135,"w":1.0},{"x":0.7333333492279053,"y":0.47058823704719546,"z":0.3607843220233917,"w":1.0},{"x":0.4745098054409027,"y":0.572549045085907,"z":0.11764705926179886,"w":1.0},{"x":0.3960784375667572,"y":0.3921568691730499,"z":0.23529411852359773,"w":1.0},{"x":0.7803921699523926,"y":0.5960784554481506,"z":0.4470588266849518,"w":1.0},{"x":0.5960784554481506,"y":0.48627451062202456,"z":0.14509804546833039,"w":1.0},{"x":0.7607843279838562,"y":0.8392156958580017,"z":0.6509804129600525,"w":1.0},{"x":0.364705890417099,"y":0.3176470696926117,"z":0.3529411852359772,"w":1.0},{"x":0.8117647171020508,"y":0.9490196108818054,"z":0.8274509906768799,"w":1.0},{"x":0.4588235318660736,"y":0.8078431487083435,"z":0.47058823704719546,"w":1.0},{"x":0.6549019813537598,"y":0.47843137383461,"z":0.239215686917305,"w":1.0},{"x":0.27843138575553896,"y":0.6980392336845398,"z":0.45490196347236636,"w":1.0},{"x":0.572549045085907,"y":0.49803921580314639,"z":0.10980392247438431,"w":1.0},{"x":0.4588235318660736,"y":0.364705890417099,"z":0.21960784494876862,"w":1.0},{"x":0.12156862765550614,"y":0.5137255191802979,"z":0.5843137502670288,"w":1.0},{"x":0.01568627543747425,"y":0.14901961386203767,"z":0.9137254953384399,"w":1.0},{"x":0.6470588445663452,"y":0.45098039507865908,"z":0.23529411852359773,"w":1.0},{"x":0.33725491166114809,"y":0.5333333611488342,"z":0.2549019753932953,"w":1.0},{"x":0.3490196168422699,"y":0.24313725531101228,"z":0.4588235318660736,"w":1.0},{"x":0.48235294222831728,"y":0.5098039507865906,"z":0.03529411926865578,"w":1.0},{"x":0.5137255191802979,"y":0.5215686559677124,"z":0.03921568766236305,"w":1.0},{"x":0.5960784554481506,"y":0.4274509847164154,"z":0.18431372940540315,"w":1.0},{"x":0.3803921639919281,"y":0.2078431397676468,"z":0.48627451062202456,"w":1.0},{"x":0.6117647290229797,"y":0.886274516582489,"z":0.6078431606292725,"w":1.0},{"x":0.7372549176216126,"y":0.5568627715110779,"z":0.37254902720451357,"w":1.0},{"x":0.529411792755127,"y":0.49803921580314639,"z":0.0470588244497776,"w":1.0},{"x":0.20392157137393952,"y":0.30980393290519717,"z":0.5411764979362488,"w":1.0},{"x":0.3450980484485626,"y":0.6666666865348816,"z":0.3490196168422699,"w":1.0},{"x":0.6039215922355652,"y":0.6196078658103943,"z":0.239215686917305,"w":1.0},{"x":0.5254902243614197,"y":0.43529412150382998,"z":0.10980392247438431,"w":1.0},{"x":0.43921568989753725,"y":0.47843137383461,"z":0.10588235408067703,"w":1.0},{"x":0.38823530077934267,"y":0.3686274588108063,"z":0.2666666805744171,"w":1.0},{"x":0.35686275362968447,"y":0.615686297416687,"z":0.2823529541492462,"w":1.0},{"x":0.1921568661928177,"y":1.0,"z":0.8980392217636108,"w":1.0},{"x":0.45490196347236636,"y":0.6000000238418579,"z":0.16862745583057404,"w":1.0},{"x":0.5686274766921997,"y":0.5803921818733215,"z":0.1568627506494522,"w":1.0},{"x":0.47058823704719546,"y":0.40392157435417178,"z":0.1568627506494522,"w":1.0},{"x":0.8666666746139526,"y":0.3607843220233917,"z":0.6000000238418579,"w":1.0},{"x":0.8588235378265381,"y":0.4313725531101227,"z":0.5568627715110779,"w":1.0},{"x":0.800000011920929,"y":0.5215686559677124,"z":0.45490196347236636,"w":1.0},{"x":0.7529411911964417,"y":0.3764705955982208,"z":0.4274509847164154,"w":1.0},{"x":0.1725490242242813,"y":0.03529411926865578,"z":0.8666666746139526,"w":1.0},{"x":0.7647058963775635,"y":0.5490196347236633,"z":0.40784314274787905,"w":1.0},{"x":0.4941176474094391,"y":0.5137255191802979,"z":0.0235294122248888,"w":1.0},{"x":0.6313725709915161,"y":0.43529412150382998,"z":0.2235294133424759,"w":1.0},{"x":0.2235294133424759,"y":0.48235294222831728,"z":0.4274509847164154,"w":1.0},{"x":0.5647059082984924,"y":0.41960784792900088,"z":0.16078431904315949,"w":1.0},{"x":0.8509804010391235,"y":0.5254902243614197,"z":0.5333333611488342,"w":1.0},{"x":0.34117648005485537,"y":0.7098039388656616,"z":0.40392157435417178,"w":1.0},{"x":0.7529411911964417,"y":0.6705882549285889,"z":0.4588235318660736,"w":1.0},{"x":0.34117648005485537,"y":0.5764706134796143,"z":0.2705882489681244,"w":1.0},{"x":0.27843138575553896,"y":0.6000000238418579,"z":0.37254902720451357,"w":1.0},{"x":0.38823530077934267,"y":0.24705882370471955,"z":0.4313725531101227,"w":1.0},{"x":0.26274511218070986,"y":0.529411792755127,"z":0.3686274588108063,"w":1.0},{"x":0.37254902720451357,"y":0.4588235318660736,"z":0.2078431397676468,"w":1.0},{"x":0.34117648005485537,"y":0.4274509847164154,"z":0.2705882489681244,"w":1.0},{"x":0.43921568989753725,"y":0.2666666805744171,"z":0.37254902720451357,"w":1.0},{"x":0.3686274588108063,"y":0.5137255191802979,"z":0.2078431397676468,"w":1.0},{"x":0.6431372761726379,"y":0.8196078538894653,"z":0.529411792755127,"w":1.0},{"x":0.5411764979362488,"y":0.5058823823928833,"z":0.06666667014360428,"w":1.0},{"x":0.7254902124404907,"y":0.4274509847164154,"z":0.3607843220233917,"w":1.0},{"x":0.33725491166114809,"y":0.7098039388656616,"z":0.40392157435417178,"w":1.0},{"x":0.7686274647712708,"y":0.6352941393852234,"z":0.45490196347236636,"w":1.0},{"x":0.6313725709915161,"y":0.5098039507865906,"z":0.20000000298023225,"w":1.0},{"x":0.6235294342041016,"y":0.27843138575553896,"z":0.3921568691730499,"w":1.0},{"x":0.2666666805744171,"y":0.3294117748737335,"z":0.4470588266849518,"w":1.0},{"x":0.46666666865348818,"y":0.4313725531101227,"z":0.12156862765550614,"w":1.0},{"x":0.5372549295425415,"y":0.3803921639919281,"z":0.19607843458652497,"w":1.0},{"x":0.4000000059604645,"y":0.40784314274787905,"z":0.21568627655506135,"w":1.0},{"x":0.23529411852359773,"y":0.3333333432674408,"z":0.48235294222831728,"w":1.0},{"x":0.5647059082984924,"y":0.46666666865348818,"z":0.11372549086809159,"w":1.0},{"x":0.5686274766921997,"y":0.6941176652908325,"z":0.30980393290519717,"w":1.0},{"x":0.06666667014360428,"y":0.24705882370471955,"z":0.7686274647712708,"w":1.0},{"x":0.3686274588108063,"y":0.5686274766921997,"z":0.22745098173618318,"w":1.0},{"x":0.5137255191802979,"y":0.5215686559677124,"z":0.03921568766236305,"w":1.0},{"x":0.18039216101169587,"y":0.43921568989753725,"z":0.49803921580314639,"w":1.0},{"x":0.239215686917305,"y":0.5176470875740051,"z":0.4000000059604645,"w":1.0},{"x":0.4588235318660736,"y":0.4745098054409027,"z":0.08235294371843338,"w":1.0},{"x":0.7019608020782471,"y":0.7215686440467835,"z":0.45098039507865908,"w":1.0},{"x":0.545098066329956,"y":0.7568627595901489,"z":0.3960784375667572,"w":1.0},{"x":0.5058823823928833,"y":0.529411792755127,"z":0.04313725605607033,"w":1.0},{"x":0.4156862795352936,"y":0.7411764860153198,"z":0.38823530077934267,"w":1.0},{"x":0.007843137718737126,"y":0.2862745225429535,"z":0.8196078538894653,"w":1.0},{"x":0.8274509906768799,"y":0.8470588326454163,"z":0.7254902124404907,"w":1.0},{"x":0.5843137502670288,"y":0.6823529601097107,"z":0.3019607961177826,"w":1.0},{"x":0.007843137718737126,"y":0.7254902124404907,"z":0.8274509906768799,"w":1.0},{"x":0.5176470875740051,"y":0.800000011920929,"z":0.4588235318660736,"w":1.0},{"x":0.21176470816135407,"y":0.615686297416687,"z":0.4745098054409027,"w":1.0},{"x":0.6078431606292725,"y":0.4627451002597809,"z":0.1725490242242813,"w":1.0},{"x":0.6823529601097107,"y":0.35686275362968447,"z":0.3529411852359772,"w":1.0},{"x":0.6549019813537598,"y":0.3764705955982208,"z":0.30588236451148989,"w":1.0},{"x":0.5960784554481506,"y":0.7254902124404907,"z":0.37254902720451357,"w":1.0},{"x":0.5098039507865906,"y":0.5372549295425415,"z":0.054901961237192157,"w":1.0},{"x":0.5372549295425415,"y":0.9607843160629273,"z":0.7019608020782471,"w":1.0},{"x":0.6117647290229797,"y":0.26274511218070986,"z":0.40392157435417178,"w":1.0},{"x":0.34117648005485537,"y":0.41960784792900088,"z":0.27450981736183169,"w":1.0},{"x":0.6000000238418579,"y":0.6549019813537598,"z":0.27843138575553896,"w":1.0},{"x":0.545098066329956,"y":0.800000011920929,"z":0.4588235318660736,"w":1.0},{"x":0.6078431606292725,"y":0.3921568691730499,"z":0.23137255012989045,"w":1.0},{"x":0.35686275362968447,"y":0.10980392247438431,"z":0.6392157077789307,"w":1.0},{"x":0.4117647111415863,"y":0.3333333432674408,"z":0.29019609093666079,"w":1.0},{"x":0.21176470816135407,"y":0.3843137323856354,"z":0.47843137383461,"w":1.0},{"x":0.7960784435272217,"y":0.5215686559677124,"z":0.45490196347236636,"w":1.0},{"x":0.886274516582489,"y":0.4431372582912445,"z":0.5960784554481506,"w":1.0},{"x":0.05882352963089943,"y":0.8705882430076599,"z":0.8784313797950745,"w":1.0},{"x":1.0,"y":0.4941176474094391,"z":0.7607843279838562,"w":1.0},{"x":0.32156863808631899,"y":0.3137255012989044,"z":0.4000000059604645,"w":1.0},{"x":0.1411764770746231,"y":0.4000000059604645,"z":0.572549045085907,"w":1.0},{"x":0.3176470696926117,"y":0.8666666746139526,"z":0.6235294342041016,"w":1.0},{"x":0.772549033164978,"y":0.45098039507865908,"z":0.41960784792900088,"w":1.0},{"x":0.8941176533699036,"y":0.615686297416687,"z":0.6196078658103943,"w":1.0},{"x":0.7333333492279053,"y":0.4941176474094391,"z":0.35686275362968447,"w":1.0},{"x":0.16470588743686677,"y":0.9333333373069763,"z":0.8352941274642944,"w":1.0},{"x":0.5411764979362488,"y":0.8352941274642944,"z":0.5098039507865906,"w":1.0},{"x":0.529411792755127,"y":0.3764705955982208,"z":0.20000000298023225,"w":1.0},{"x":0.6901960968971252,"y":0.545098066329956,"z":0.29411765933036806,"w":1.0},{"x":0.6352941393852234,"y":0.8117647171020508,"z":0.5137255191802979,"w":1.0},{"x":0.49803921580314639,"y":0.6039215922355652,"z":0.1568627506494522,"w":1.0},{"x":0.6509804129600525,"y":0.4627451002597809,"z":0.239215686917305,"w":1.0},{"x":0.5490196347236633,"y":0.4745098054409027,"z":0.08627451211214066,"w":1.0},{"x":0.37254902720451357,"y":0.6352941393852234,"z":0.2862745225429535,"w":1.0},{"x":0.3490196168422699,"y":0.9254902005195618,"z":0.686274528503418,"w":1.0},{"x":0.772549033164978,"y":0.6196078658103943,"z":0.45098039507865908,"w":1.0},{"x":0.5764706134796143,"y":0.47843137383461,"z":0.12156862765550614,"w":1.0},{"x":0.5411764979362488,"y":0.33725491166114809,"z":0.25882354378700259,"w":1.0},{"x":0.5803921818733215,"y":0.30980393290519717,"z":0.32156863808631899,"w":1.0},{"x":0.6274510025978088,"y":0.12156862765550614,"z":0.615686297416687,"w":1.0},{"x":0.6549019813537598,"y":0.35686275362968447,"z":0.32156863808631899,"w":1.0},{"x":0.5176470875740051,"y":0.501960813999176,"z":0.027450980618596078,"w":1.0},{"x":0.3843137323856354,"y":0.47058823704719546,"z":0.1882352977991104,"w":1.0},{"x":0.6039215922355652,"y":0.615686297416687,"z":0.23529411852359773,"w":1.0},{"x":0.9490196108818054,"y":0.027450980618596078,"z":0.9921568632125855,"w":1.0},{"x":0.3843137323856354,"y":0.1921568661928177,"z":0.5058823823928833,"w":1.0},{"x":0.25882354378700259,"y":0.658823549747467,"z":0.4431372582912445,"w":1.0},{"x":0.572549045085907,"y":0.2862745225429535,"z":0.3490196168422699,"w":1.0},{"x":0.5137255191802979,"y":0.5843137502670288,"z":0.12941177189350129,"w":1.0},{"x":0.37254902720451357,"y":0.7568627595901489,"z":0.43921568989753725,"w":1.0},{"x":0.5764706134796143,"y":0.3960784375667572,"z":0.19607843458652497,"w":1.0},{"x":0.20000000298023225,"y":0.15294118225574494,"z":0.7019608020782471,"w":1.0},{"x":0.5137255191802979,"y":0.48235294222831728,"z":0.03529411926865578,"w":1.0},{"x":0.7450980544090271,"y":0.7215686440467835,"z":0.49803921580314639,"w":1.0},{"x":0.6274510025978088,"y":0.6431372761726379,"z":0.29019609093666079,"w":1.0},{"x":0.529411792755127,"y":0.48235294222831728,"z":0.05882352963089943,"w":1.0},{"x":0.37254902720451357,"y":0.6431372761726379,"z":0.29411765933036806,"w":1.0},{"x":0.5882353186607361,"y":0.12156862765550614,"z":0.5960784554481506,"w":1.0},{"x":0.545098066329956,"y":0.6509804129600525,"z":0.24313725531101228,"w":1.0},{"x":0.47058823704719546,"y":0.5254902243614197,"z":0.062745101749897,"w":1.0},{"x":0.5372549295425415,"y":0.6823529601097107,"z":0.2823529541492462,"w":1.0},{"x":0.6549019813537598,"y":0.43921568989753725,"z":0.2549019753932953,"w":1.0},{"x":0.615686297416687,"y":0.5529412031173706,"z":0.1882352977991104,"w":1.0},{"x":0.6941176652908325,"y":0.8274509906768799,"z":0.5764706134796143,"w":1.0},{"x":0.6352941393852234,"y":0.5490196347236633,"z":0.21568627655506135,"w":1.0},{"x":0.49803921580314639,"y":0.5960784554481506,"z":0.14509804546833039,"w":1.0},{"x":0.054901961237192157,"y":0.6274510025978088,"z":0.7058823704719544,"w":1.0},{"x":0.7411764860153198,"y":0.658823549747467,"z":0.43921568989753725,"w":1.0},{"x":0.29411765933036806,"y":0.4000000059604645,"z":0.3529411852359772,"w":1.0},{"x":0.22745098173618318,"y":0.29019609093666079,"z":0.529411792755127,"w":1.0},{"x":0.5176470875740051,"y":0.615686297416687,"z":0.18039216101169587,"w":1.0},{"x":0.501960813999176,"y":0.3529411852359772,"z":0.23137255012989045,"w":1.0},{"x":0.3294117748737335,"y":0.5176470875740051,"z":0.2666666805744171,"w":1.0},{"x":0.6235294342041016,"y":0.43529412150382998,"z":0.21176470816135407,"w":1.0},{"x":0.7254902124404907,"y":0.49803921580314639,"z":0.3450980484485626,"w":1.0},{"x":0.8666666746139526,"y":0.5686274766921997,"z":0.5647059082984924,"w":1.0},{"x":0.572549045085907,"y":0.37254902720451357,"z":0.23137255012989045,"w":1.0},{"x":0.3333333432674408,"y":0.46666666865348818,"z":0.2666666805744171,"w":1.0},{"x":0.48627451062202456,"y":0.5058823823928833,"z":0.027450980618596078,"w":1.0},{"x":0.22745098173618318,"y":0.5686274766921997,"z":0.4313725531101227,"w":1.0},{"x":0.4627451002597809,"y":0.5803921818733215,"z":0.13725490868091584,"w":1.0},{"x":0.4470588266849518,"y":0.5333333611488342,"z":0.10196078568696976,"w":1.0},{"x":0.6470588445663452,"y":0.6235294342041016,"z":0.29411765933036806,"w":1.0},{"x":0.5529412031173706,"y":0.4313725531101227,"z":0.13725490868091584,"w":1.0},{"x":0.24705882370471955,"y":0.7254902124404907,"z":0.5176470875740051,"w":1.0},{"x":0.6196078658103943,"y":0.545098066329956,"z":0.19607843458652497,"w":1.0},{"x":0.5568627715110779,"y":0.501960813999176,"z":0.08235294371843338,"w":1.0},{"x":0.239215686917305,"y":0.7333333492279053,"z":0.5372549295425415,"w":1.0},{"x":0.45098039507865908,"y":0.9137254953384399,"z":0.6352941393852234,"w":1.0},{"x":0.4274509847164154,"y":0.529411792755127,"z":0.125490203499794,"w":1.0},{"x":0.4274509847164154,"y":0.3686274588108063,"z":0.239215686917305,"w":1.0},{"x":0.007843137718737126,"y":0.19607843458652497,"z":0.886274516582489,"w":1.0},{"x":0.4588235318660736,"y":0.5333333611488342,"z":0.08627451211214066,"w":1.0},{"x":0.4627451002597809,"y":0.47058823704719546,"z":0.08235294371843338,"w":1.0},{"x":0.1921568661928177,"y":0.5843137502670288,"z":0.4901960790157318,"w":1.0},{"x":0.46666666865348818,"y":0.5882353186607361,"z":0.1411764770746231,"w":1.0},{"x":0.18431372940540315,"y":0.5176470875740051,"z":0.4901960790157318,"w":1.0},{"x":0.5137255191802979,"y":0.7411764860153198,"z":0.3686274588108063,"w":1.0},{"x":0.6745098233222961,"y":0.4627451002597809,"z":0.27450981736183169,"w":1.0},{"x":0.35686275362968447,"y":0.5764706134796143,"z":0.24705882370471955,"w":1.0},{"x":0.4745098054409027,"y":0.6509804129600525,"z":0.23529411852359773,"w":1.0},{"x":0.5333333611488342,"y":0.4588235318660736,"z":0.08627451211214066,"w":1.0},{"x":0.20000000298023225,"y":0.5882353186607361,"z":0.47843137383461,"w":1.0},{"x":0.7254902124404907,"y":0.7176470756530762,"z":0.4745098054409027,"w":1.0},{"x":0.22745098173618318,"y":0.572549045085907,"z":0.43529412150382998,"w":1.0},{"x":0.4941176474094391,"y":0.48627451062202456,"z":0.027450980618596078,"w":1.0},{"x":0.29411765933036806,"y":0.5647059082984924,"z":0.3333333432674408,"w":1.0},{"x":0.5137255191802979,"y":0.5372549295425415,"z":0.05882352963089943,"w":1.0},{"x":0.5490196347236633,"y":0.6235294342041016,"z":0.20000000298023225,"w":1.0},{"x":0.47843137383461,"y":0.6274510025978088,"z":0.19607843458652497,"w":1.0},{"x":0.7058823704719544,"y":0.3529411852359772,"z":0.38823530077934267,"w":1.0},{"x":0.501960813999176,"y":0.3607843220233917,"z":0.21568627655506135,"w":1.0},{"x":0.03921568766236305,"y":0.5803921818733215,"z":0.7137255072593689,"w":1.0},{"x":0.5137255191802979,"y":0.21960784494876862,"z":0.4313725531101227,"w":1.0},{"x":0.5921568870544434,"y":0.8156862854957581,"z":0.49803921580314639,"w":1.0},{"x":0.2549019753932953,"y":0.501960813999176,"z":0.3764705955982208,"w":1.0},{"x":0.21960784494876862,"y":0.40784314274787905,"z":0.45490196347236636,"w":1.0},{"x":0.364705890417099,"y":0.6745098233222961,"z":0.33725491166114809,"w":1.0},{"x":0.45098039507865908,"y":0.6627451181411743,"z":0.25882354378700259,"w":1.0},{"x":0.47058823704719546,"y":0.529411792755127,"z":0.06666667014360428,"w":1.0},{"x":0.3803921639919281,"y":0.4431372582912445,"z":0.20392157137393952,"w":1.0},{"x":0.5411764979362488,"y":0.250980406999588,"z":0.38823530077934267,"w":1.0},{"x":0.800000011920929,"y":0.5098039507865906,"z":0.45490196347236636,"w":1.0},{"x":0.5215686559677124,"y":0.3960784375667572,"z":0.16470588743686677,"w":1.0},{"x":0.5803921818733215,"y":0.2235294133424759,"z":0.4431372582912445,"w":1.0},{"x":0.5568627715110779,"y":0.3764705955982208,"z":0.2078431397676468,"w":1.0},{"x":0.886274516582489,"y":0.16078431904315949,"z":0.7843137383460999,"w":1.0},{"x":0.4000000059604645,"y":0.43921568989753725,"z":0.18431372940540315,"w":1.0},{"x":0.8745098114013672,"y":0.3137255012989044,"z":0.6352941393852234,"w":1.0},{"x":0.48235294222831728,"y":0.501960813999176,"z":0.03529411926865578,"w":1.0},{"x":0.5098039507865906,"y":0.47843137383461,"z":0.03921568766236305,"w":1.0},{"x":0.3019607961177826,"y":0.6745098233222961,"z":0.40392157435417178,"w":1.0},{"x":0.08627451211214066,"y":0.34117648005485537,"z":0.6823529601097107,"w":1.0},{"x":0.5647059082984924,"y":0.5098039507865906,"z":0.10196078568696976,"w":1.0},{"x":0.26274511218070986,"y":0.7333333492279053,"z":0.5058823823928833,"w":1.0},{"x":0.5137255191802979,"y":0.7843137383460999,"z":0.43529412150382998,"w":1.0},{"x":0.41960784792900088,"y":0.5882353186607361,"z":0.18039216101169587,"w":1.0},{"x":0.45490196347236636,"y":0.6196078658103943,"z":0.19607843458652497,"w":1.0},{"x":0.7843137383460999,"y":0.729411780834198,"z":0.5529412031173706,"w":1.0},{"x":0.3450980484485626,"y":0.47843137383461,"z":0.24705882370471955,"w":1.0},{"x":0.7098039388656616,"y":0.9176470637321472,"z":0.7098039388656616,"w":1.0},{"x":0.5137255191802979,"y":0.4941176474094391,"z":0.0235294122248888,"w":1.0},{"x":0.21176470816135407,"y":0.41960784792900088,"z":0.4588235318660736,"w":1.0},{"x":0.729411780834198,"y":0.5098039507865906,"z":0.3490196168422699,"w":1.0},{"x":0.3490196168422699,"y":0.729411780834198,"z":0.4156862795352936,"w":1.0},{"x":0.4156862795352936,"y":0.2235294133424759,"z":0.4470588266849518,"w":1.0},{"x":0.37254902720451357,"y":0.6196078658103943,"z":0.2666666805744171,"w":1.0},{"x":0.6941176652908325,"y":0.6313725709915161,"z":0.3529411852359772,"w":1.0},{"x":0.8784313797950745,"y":0.7411764860153198,"z":0.6784313917160034,"w":1.0},{"x":0.9921568632125855,"y":0.29411765933036806,"z":0.8078431487083435,"w":1.0},{"x":0.364705890417099,"y":0.7058823704719544,"z":0.3764705955982208,"w":1.0},{"x":0.47843137383461,"y":0.4313725531101227,"z":0.11764705926179886,"w":1.0},{"x":0.7647058963775635,"y":0.4274509847164154,"z":0.4156862795352936,"w":1.0},{"x":0.47843137383461,"y":0.8470588326454163,"z":0.5254902243614197,"w":1.0},{"x":0.3450980484485626,"y":0.5607843399047852,"z":0.2549019753932953,"w":1.0},{"x":0.3450980484485626,"y":0.6431372761726379,"z":0.32156863808631899,"w":1.0},{"x":0.8235294222831726,"y":0.5411764979362488,"z":0.4941176474094391,"w":1.0},{"x":0.529411792755127,"y":0.38823530077934267,"z":0.18431372940540315,"w":1.0},{"x":0.7137255072593689,"y":0.7019608020782471,"z":0.4470588266849518,"w":1.0},{"x":0.4901960790157318,"y":0.7921568751335144,"z":0.4431372582912445,"w":1.0},{"x":0.9450980424880981,"y":0.33725491166114809,"z":0.7254902124404907,"w":1.0},{"x":0.5176470875740051,"y":0.364705890417099,"z":0.21176470816135407,"w":1.0},{"x":0.6745098233222961,"y":0.2980392277240753,"z":0.4117647111415863,"w":1.0},{"x":0.3019607961177826,"y":0.7176470756530762,"z":0.45098039507865908,"w":1.0},{"x":0.5764706134796143,"y":0.7803921699523926,"z":0.43921568989753725,"w":1.0},{"x":0.40392157435417178,"y":0.3803921639919281,"z":0.239215686917305,"w":1.0},{"x":0.9686274528503418,"y":0.5960784554481506,"z":0.729411780834198,"w":1.0},{"x":0.8235294222831726,"y":0.07058823853731156,"z":0.8196078538894653,"w":1.0},{"x":0.0941176488995552,"y":0.3137255012989044,"z":0.6823529601097107,"w":1.0},{"x":0.7764706015586853,"y":0.40392157435417178,"z":0.4470588266849518,"w":1.0},{"x":0.42352941632270815,"y":0.6235294342041016,"z":0.2235294133424759,"w":1.0},{"x":0.8117647171020508,"y":0.41960784792900088,"z":0.4901960790157318,"w":1.0},{"x":0.3764705955982208,"y":0.4274509847164154,"z":0.2235294133424759,"w":1.0},{"x":0.364705890417099,"y":0.29019609093666079,"z":0.3843137323856354,"w":1.0},{"x":0.7019608020782471,"y":0.32156863808631899,"z":0.4117647111415863,"w":1.0},{"x":0.4117647111415863,"y":0.5803921818733215,"z":0.18431372940540315,"w":1.0},{"x":0.7960784435272217,"y":0.47058823704719546,"z":0.45490196347236636,"w":1.0},{"x":0.5254902243614197,"y":0.4000000059604645,"z":0.16078431904315949,"w":1.0},{"x":0.4313725531101227,"y":0.9215686321258545,"z":0.6470588445663452,"w":1.0},{"x":0.6196078658103943,"y":0.019607843831181527,"z":0.7607843279838562,"w":1.0},{"x":0.9019607901573181,"y":0.9647058844566345,"z":0.9333333373069763,"w":1.0},{"x":0.529411792755127,"y":0.5254902243614197,"z":0.05882352963089943,"w":1.0},{"x":0.843137264251709,"y":0.32549020648002627,"z":0.5882353186607361,"w":1.0},{"x":0.3137255012989044,"y":0.7137255072593689,"z":0.4313725531101227,"w":1.0},{"x":0.3450980484485626,"y":0.2862745225429535,"z":0.40784314274787905,"w":1.0},{"x":0.1882352977991104,"y":0.6980392336845398,"z":0.5607843399047852,"w":1.0},{"x":0.250980406999588,"y":0.5137255191802979,"z":0.3803921639919281,"w":1.0},{"x":0.5254902243614197,"y":0.5764706134796143,"z":0.125490203499794,"w":1.0},{"x":0.8941176533699036,"y":0.5607843399047852,"z":0.6039215922355652,"w":1.0},{"x":0.3686274588108063,"y":0.2705882489681244,"z":0.4117647111415863,"w":1.0},{"x":0.7019608020782471,"y":0.5254902243614197,"z":0.30588236451148989,"w":1.0},{"x":0.22745098173618318,"y":0.4588235318660736,"z":0.4274509847164154,"w":1.0},{"x":0.7058823704719544,"y":0.3921568691730499,"z":0.35686275362968447,"w":1.0},{"x":0.6078431606292725,"y":0.4117647111415863,"z":0.21568627655506135,"w":1.0},{"x":0.2705882489681244,"y":0.6392157077789307,"z":0.4117647111415863,"w":1.0},{"x":0.29019609093666079,"y":0.5803921818733215,"z":0.3450980484485626,"w":1.0},{"x":0.6117647290229797,"y":0.6509804129600525,"z":0.2823529541492462,"w":1.0},{"x":0.658823549747467,"y":0.41960784792900088,"z":0.27450981736183169,"w":1.0},{"x":0.615686297416687,"y":0.239215686917305,"z":0.43529412150382998,"w":1.0},{"x":0.7843137383460999,"y":0.501960813999176,"z":0.4313725531101227,"w":1.0},{"x":0.5490196347236633,"y":0.34117648005485537,"z":0.2549019753932953,"w":1.0},{"x":0.6784313917160034,"y":0.6666666865348816,"z":0.37254902720451357,"w":1.0},{"x":0.2980392277240753,"y":0.6705882549285889,"z":0.40392157435417178,"w":1.0},{"x":0.3333333432674408,"y":0.3921568691730499,"z":0.30980393290519717,"w":1.0},{"x":0.30980393290519717,"y":0.7176470756530762,"z":0.4431372582912445,"w":1.0},{"x":0.545098066329956,"y":0.5568627715110779,"z":0.10980392247438431,"w":1.0},{"x":0.8196078538894653,"y":0.5529412031173706,"z":0.4901960790157318,"w":1.0},{"x":0.29411765933036806,"y":0.3686274588108063,"z":0.3764705955982208,"w":1.0},{"x":0.7490196228027344,"y":0.47843137383461,"z":0.3803921639919281,"w":1.0},{"x":0.49803921580314639,"y":0.26274511218070986,"z":0.364705890417099,"w":1.0},{"x":0.5843137502670288,"y":0.7254902124404907,"z":0.364705890417099,"w":1.0},{"x":0.5647059082984924,"y":0.5215686559677124,"z":0.10588235408067703,"w":1.0},{"x":0.47058823704719546,"y":0.6823529601097107,"z":0.2823529541492462,"w":1.0},{"x":0.5098039507865906,"y":0.5058823823928833,"z":0.019607843831181527,"w":1.0},{"x":0.7607843279838562,"y":0.40392157435417178,"z":0.42352941632270815,"w":1.0},{"x":0.6509804129600525,"y":0.7490196228027344,"z":0.4431372582912445,"w":1.0},{"x":0.4745098054409027,"y":0.3450980484485626,"z":0.24313725531101228,"w":1.0},{"x":0.615686297416687,"y":0.29019609093666079,"z":0.3686274588108063,"w":1.0},{"x":0.08235294371843338,"y":0.04313725605607033,"z":0.9450980424880981,"w":1.0},{"x":0.8823529481887817,"y":0.5254902243614197,"z":0.5843137502670288,"w":1.0},{"x":0.37254902720451357,"y":0.6078431606292725,"z":0.2549019753932953,"w":1.0},{"x":0.6196078658103943,"y":0.4901960790157318,"z":0.18431372940540315,"w":1.0},{"x":0.6470588445663452,"y":0.7843137383460999,"z":0.48627451062202456,"w":1.0},{"x":0.6235294342041016,"y":0.5843137502670288,"z":0.22745098173618318,"w":1.0},{"x":0.5647059082984924,"y":0.37254902720451357,"z":0.21960784494876862,"w":1.0},{"x":0.6823529601097107,"y":0.07058823853731156,"z":0.7137255072593689,"w":1.0},{"x":0.6470588445663452,"y":0.4117647111415863,"z":0.25882354378700259,"w":1.0},{"x":0.29411765933036806,"y":0.6627451181411743,"z":0.40392157435417178,"w":1.0},{"x":0.30588236451148989,"y":0.2549019753932953,"z":0.48627451062202456,"w":1.0},{"x":0.658823549747467,"y":0.4901960790157318,"z":0.239215686917305,"w":1.0},{"x":0.5686274766921997,"y":0.5058823823928833,"z":0.10588235408067703,"w":1.0},{"x":0.6431372761726379,"y":0.9921568632125855,"z":0.7764706015586853,"w":1.0},{"x":0.6745098233222961,"y":0.5843137502670288,"z":0.29019609093666079,"w":1.0},{"x":0.3294117748737335,"y":0.48235294222831728,"z":0.2666666805744171,"w":1.0},{"x":0.8705882430076599,"y":0.729411780834198,"z":0.6627451181411743,"w":1.0},{"x":0.729411780834198,"y":0.45490196347236636,"z":0.3529411852359772,"w":1.0},{"x":0.5058823823928833,"y":0.49803921580314639,"z":0.0117647061124444,"w":1.0},{"x":0.5098039507865906,"y":0.07058823853731156,"z":0.658823549747467,"w":1.0},{"x":0.4627451002597809,"y":0.6745098233222961,"z":0.2705882489681244,"w":1.0},{"x":0.3843137323856354,"y":0.4745098054409027,"z":0.18431372940540315,"w":1.0},{"x":0.7490196228027344,"y":0.43921568989753725,"z":0.3921568691730499,"w":1.0},{"x":0.8352941274642944,"y":0.5215686559677124,"z":0.5098039507865906,"w":1.0},{"x":0.3137255012989044,"y":0.2862745225429535,"z":0.43529412150382998,"w":1.0},{"x":0.6823529601097107,"y":0.6705882549285889,"z":0.3803921639919281,"w":1.0},{"x":0.7333333492279053,"y":0.43921568989753725,"z":0.3686274588108063,"w":1.0},{"x":0.5176470875740051,"y":0.5098039507865906,"z":0.027450980618596078,"w":1.0},{"x":0.41960784792900088,"y":0.47058823704719546,"z":0.13333334028720857,"w":1.0},{"x":0.43921568989753725,"y":0.34117648005485537,"z":0.2666666805744171,"w":1.0},{"x":0.8509804010391235,"y":0.5372549295425415,"z":0.5372549295425415,"w":1.0},{"x":0.27450981736183169,"y":0.7529411911964417,"z":0.5137255191802979,"w":1.0},{"x":0.4588235318660736,"y":0.729411780834198,"z":0.3529411852359772,"w":1.0},{"x":0.7960784435272217,"y":0.501960813999176,"z":0.4470588266849518,"w":1.0},{"x":0.49803921580314639,"y":0.3803921639919281,"z":0.1882352977991104,"w":1.0},{"x":0.9137254953384399,"y":0.6549019813537598,"z":0.6705882549285889,"w":1.0},{"x":0.615686297416687,"y":0.239215686917305,"z":0.43921568989753725,"w":1.0},{"x":0.5058823823928833,"y":0.843137264251709,"z":0.5176470875740051,"w":1.0},{"x":0.21568627655506135,"y":0.5647059082984924,"z":0.45098039507865908,"w":1.0},{"x":0.6431372761726379,"y":0.48627451062202456,"z":0.21960784494876862,"w":1.0},{"x":0.2078431397676468,"y":0.5686274766921997,"z":0.4627451002597809,"w":1.0},{"x":0.7686274647712708,"y":0.47843137383461,"z":0.4117647111415863,"w":1.0},{"x":0.49803921580314639,"y":0.5098039507865906,"z":0.019607843831181527,"w":1.0},{"x":0.49803921580314639,"y":0.5686274766921997,"z":0.10196078568696976,"w":1.0},{"x":0.9725490212440491,"y":0.7960784435272217,"z":0.843137264251709,"w":1.0},{"x":0.4745098054409027,"y":0.09803921729326248,"z":0.6196078658103943,"w":1.0},{"x":0.239215686917305,"y":0.5372549295425415,"z":0.40392157435417178,"w":1.0},{"x":0.29019609093666079,"y":0.7921568751335144,"z":0.545098066329956,"w":1.0},{"x":0.29411765933036806,"y":0.4313725531101227,"z":0.33725491166114809,"w":1.0},{"x":0.22745098173618318,"y":0.45490196347236636,"z":0.4274509847164154,"w":1.0},{"x":0.5098039507865906,"y":0.545098066329956,"z":0.06666667014360428,"w":1.0},{"x":0.7098039388656616,"y":0.3607843220233917,"z":0.38823530077934267,"w":1.0},{"x":0.6745098233222961,"y":0.3176470696926117,"z":0.38823530077934267,"w":1.0},{"x":0.7058823704719544,"y":0.501960813999176,"z":0.3137255012989044,"w":1.0},{"x":0.2823529541492462,"y":0.7372549176216126,"z":0.4901960790157318,"w":1.0},{"x":0.3176470696926117,"y":0.6352941393852234,"z":0.3490196168422699,"w":1.0},{"x":0.4000000059604645,"y":0.7921568751335144,"z":0.47058823704719546,"w":1.0},{"x":0.43921568989753725,"y":0.30588236451148989,"z":0.3137255012989044,"w":1.0},{"x":0.3529411852359772,"y":0.5098039507865906,"z":0.22745098173618318,"w":1.0},{"x":0.6666666865348816,"y":0.7411764860153198,"z":0.4431372582912445,"w":1.0},{"x":0.32156863808631899,"y":0.2980392277240753,"z":0.4156862795352936,"w":1.0},{"x":0.5333333611488342,"y":0.501960813999176,"z":0.05098039284348488,"w":1.0},{"x":0.529411792755127,"y":0.4901960790157318,"z":0.0470588244497776,"w":1.0},{"x":0.5843137502670288,"y":0.2823529541492462,"z":0.35686275362968447,"w":1.0},{"x":0.48235294222831728,"y":0.2666666805744171,"z":0.3607843220233917,"w":1.0},{"x":0.6549019813537598,"y":0.5411764979362488,"z":0.24313725531101228,"w":1.0},{"x":0.7215686440467835,"y":0.2666666805744171,"z":0.4941176474094391,"w":1.0},{"x":0.20000000298023225,"y":0.7647058963775635,"z":0.615686297416687,"w":1.0},{"x":0.5647059082984924,"y":0.24705882370471955,"z":0.4000000059604645,"w":1.0},{"x":0.5372549295425415,"y":0.3450980484485626,"z":0.250980406999588,"w":1.0},{"x":0.5098039507865906,"y":0.6470588445663452,"z":0.22745098173618318,"w":1.0},{"x":0.8156862854957581,"y":0.6117647290229797,"z":0.5058823823928833,"w":1.0},{"x":0.4745098054409027,"y":0.43529412150382998,"z":0.11372549086809159,"w":1.0},{"x":0.6980392336845398,"y":0.8627451062202454,"z":0.6274510025978088,"w":1.0},{"x":0.7098039388656616,"y":0.3490196168422699,"z":0.3921568691730499,"w":1.0},{"x":0.5647059082984924,"y":0.5411764979362488,"z":0.11764705926179886,"w":1.0},{"x":0.3529411852359772,"y":0.6705882549285889,"z":0.3450980484485626,"w":1.0},{"x":0.43921568989753725,"y":0.6901960968971252,"z":0.30588236451148989,"w":1.0},{"x":0.4627451002597809,"y":0.5176470875740051,"z":0.06666667014360428,"w":1.0},{"x":0.5647059082984924,"y":0.5686274766921997,"z":0.1411764770746231,"w":1.0},{"x":0.4431372582912445,"y":0.545098066329956,"z":0.11372549086809159,"w":1.0},{"x":0.6117647290229797,"y":0.5137255191802979,"z":0.1725490242242813,"w":1.0},{"x":0.6235294342041016,"y":0.686274528503418,"z":0.34117648005485537,"w":1.0},{"x":0.5058823823928833,"y":0.4745098054409027,"z":0.0470588244497776,"w":1.0},{"x":0.4156862795352936,"y":0.42352941632270815,"z":0.18431372940540315,"w":1.0},{"x":0.43921568989753725,"y":0.7333333492279053,"z":0.3686274588108063,"w":1.0},{"x":0.2862745225429535,"y":0.250980406999588,"z":0.5058823823928833,"w":1.0},{"x":0.6117647290229797,"y":0.40392157435417178,"z":0.2235294133424759,"w":1.0},{"x":0.843137264251709,"y":0.7843137383460999,"z":0.6784313917160034,"w":1.0},{"x":0.49803921580314639,"y":0.6509804129600525,"z":0.22745098173618318,"w":1.0},{"x":0.8470588326454163,"y":0.30588236451148989,"z":0.6078431606292725,"w":1.0},{"x":0.49803921580314639,"y":0.5058823823928833,"z":0.0117647061124444,"w":1.0},{"x":0.8392156958580017,"y":0.38823530077934267,"z":0.545098066329956,"w":1.0},{"x":0.5882353186607361,"y":0.8078431487083435,"z":0.48627451062202456,"w":1.0},{"x":0.4941176474094391,"y":0.6392157077789307,"z":0.21176470816135407,"w":1.0},{"x":0.38823530077934267,"y":0.23529411852359773,"z":0.4431372582912445,"w":1.0},{"x":0.5490196347236633,"y":0.6117647290229797,"z":0.1882352977991104,"w":1.0},{"x":0.2666666805744171,"y":0.3529411852359772,"z":0.42352941632270815,"w":1.0},{"x":0.47843137383461,"y":0.27450981736183169,"z":0.3490196168422699,"w":1.0},{"x":0.29411765933036806,"y":0.33725491166114809,"z":0.40392157435417178,"w":1.0},{"x":0.43529412150382998,"y":0.3960784375667572,"z":0.1921568661928177,"w":1.0},{"x":0.49803921580314639,"y":0.6745098233222961,"z":0.2666666805744171,"w":1.0},{"x":0.12941177189350129,"y":0.5686274766921997,"z":0.5803921818733215,"w":1.0},{"x":0.22745098173618318,"y":0.4000000059604645,"z":0.4470588266849518,"w":1.0},{"x":0.6980392336845398,"y":0.4000000059604645,"z":0.33725491166114809,"w":1.0},{"x":0.5764706134796143,"y":0.7529411911964417,"z":0.3960784375667572,"w":1.0},{"x":0.6117647290229797,"y":0.46666666865348818,"z":0.1764705926179886,"w":1.0},{"x":0.6117647290229797,"y":0.3490196168422699,"z":0.29019609093666079,"w":1.0},{"x":0.47843137383461,"y":0.38823530077934267,"z":0.18039216101169587,"w":1.0},{"x":0.32549020648002627,"y":0.8705882430076599,"z":0.6235294342041016,"w":1.0},{"x":0.3176470696926117,"y":0.03529411926865578,"z":0.7647058963775635,"w":1.0},{"x":0.0784313753247261,"y":0.2666666805744171,"z":0.7411764860153198,"w":1.0},{"x":0.20392157137393952,"y":0.5843137502670288,"z":0.4745098054409027,"w":1.0},{"x":0.8078431487083435,"y":0.3450980484485626,"z":0.5254902243614197,"w":1.0},{"x":0.3921568691730499,"y":0.4313725531101227,"z":0.20392157137393952,"w":1.0},{"x":0.7490196228027344,"y":0.6549019813537598,"z":0.4470588266849518,"w":1.0},{"x":0.2235294133424759,"y":0.47058823704719546,"z":0.4274509847164154,"w":1.0},{"x":0.18039216101169587,"y":0.4941176474094391,"z":0.4901960790157318,"w":1.0},{"x":0.9921568632125855,"y":0.06666667014360428,"z":1.0,"w":1.0},{"x":0.3921568691730499,"y":0.1725490242242813,"z":0.5333333611488342,"w":1.0},{"x":0.20392157137393952,"y":0.40392157435417178,"z":0.47843137383461,"w":1.0},{"x":0.5490196347236633,"y":0.3450980484485626,"z":0.250980406999588,"w":1.0},{"x":0.9058823585510254,"y":0.45098039507865908,"z":0.6196078658103943,"w":1.0},{"x":0.3137255012989044,"y":0.4901960790157318,"z":0.2862745225429535,"w":1.0},{"x":0.4941176474094391,"y":0.5921568870544434,"z":0.1411764770746231,"w":1.0},{"x":0.22745098173618318,"y":0.3843137323856354,"z":0.4588235318660736,"w":1.0},{"x":0.3294117748737335,"y":0.3607843220233917,"z":0.34117648005485537,"w":1.0},{"x":0.6039215922355652,"y":0.48627451062202456,"z":0.16078431904315949,"w":1.0},{"x":0.42352941632270815,"y":0.8588235378265381,"z":0.5607843399047852,"w":1.0},{"x":0.07058823853731156,"y":0.0784313753247261,"z":0.9176470637321472,"w":1.0},{"x":0.7137255072593689,"y":0.5098039507865906,"z":0.32549020648002627,"w":1.0},{"x":0.545098066329956,"y":0.7529411911964417,"z":0.3921568691730499,"w":1.0},{"x":0.6470588445663452,"y":0.3960784375667572,"z":0.27450981736183169,"w":1.0},{"x":0.6431372761726379,"y":0.34117648005485537,"z":0.3294117748737335,"w":1.0},{"x":0.46666666865348818,"y":0.239215686917305,"z":0.40784314274787905,"w":1.0},{"x":0.501960813999176,"y":0.4901960790157318,"z":0.0235294122248888,"w":1.0},{"x":0.4941176474094391,"y":0.250980406999588,"z":0.3843137323856354,"w":1.0},{"x":0.4941176474094391,"y":0.4470588266849518,"z":0.08627451211214066,"w":1.0},{"x":0.40784314274787905,"y":0.7372549176216126,"z":0.38823530077934267,"w":1.0},{"x":0.5882353186607361,"y":0.8313725590705872,"z":0.5215686559677124,"w":1.0},{"x":0.04313725605607033,"y":0.5137255191802979,"z":0.7019608020782471,"w":1.0},{"x":0.19607843458652497,"y":0.37254902720451357,"z":0.5058823823928833,"w":1.0},{"x":0.3176470696926117,"y":0.6941176652908325,"z":0.40392157435417178,"w":1.0},{"x":0.5176470875740051,"y":0.21568627655506135,"z":0.43921568989753725,"w":1.0},{"x":0.8392156958580017,"y":0.30980393290519717,"z":0.5921568870544434,"w":1.0},{"x":0.27450981736183169,"y":0.5843137502670288,"z":0.37254902720451357,"w":1.0},{"x":0.32549020648002627,"y":0.5490196347236633,"z":0.2823529541492462,"w":1.0},{"x":0.5137255191802979,"y":0.4588235318660736,"z":0.07450980693101883,"w":1.0},{"x":0.3686274588108063,"y":0.7019608020782471,"z":0.3686274588108063,"w":1.0},{"x":0.5137255191802979,"y":0.364705890417099,"z":0.2078431397676468,"w":1.0},{"x":0.239215686917305,"y":0.6392157077789307,"z":0.45490196347236636,"w":1.0},{"x":0.6941176652908325,"y":0.6980392336845398,"z":0.41960784792900088,"w":1.0},{"x":0.5490196347236633,"y":0.6784313917160034,"z":0.2823529541492462,"w":1.0},{"x":0.4274509847164154,"y":0.45490196347236636,"z":0.13725490868091584,"w":1.0},{"x":0.5647059082984924,"y":0.23529411852359773,"z":0.41960784792900088,"w":1.0},{"x":0.6313725709915161,"y":0.800000011920929,"z":0.49803921580314639,"w":1.0},{"x":0.5960784554481506,"y":0.7137255072593689,"z":0.3529411852359772,"w":1.0},{"x":0.49803921580314639,"y":0.686274528503418,"z":0.2823529541492462,"w":1.0},{"x":0.3803921639919281,"y":0.6901960968971252,"z":0.34117648005485537,"w":1.0},{"x":0.5960784554481506,"y":0.2862745225429535,"z":0.3607843220233917,"w":1.0},{"x":0.3019607961177826,"y":0.5803921818733215,"z":0.3294117748737335,"w":1.0},{"x":0.5058823823928833,"y":0.45490196347236636,"z":0.07450980693101883,"w":1.0},{"x":0.0313725508749485,"y":0.2862745225429535,"z":0.7882353067398071,"w":1.0},{"x":0.6196078658103943,"y":0.3960784375667572,"z":0.24313725531101228,"w":1.0},{"x":0.6705882549285889,"y":0.0235294122248888,"z":0.772549033164978,"w":1.0},{"x":0.886274516582489,"y":0.6392157077789307,"z":0.6235294342041016,"w":1.0},{"x":0.2862745225429535,"y":0.2980392277240753,"z":0.45490196347236636,"w":1.0},{"x":0.5686274766921997,"y":0.14901961386203767,"z":0.545098066329956,"w":1.0},{"x":0.49803921580314639,"y":0.5176470875740051,"z":0.027450980618596078,"w":1.0},{"x":0.5843137502670288,"y":0.7098039388656616,"z":0.34117648005485537,"w":1.0},{"x":0.7843137383460999,"y":0.6705882549285889,"z":0.5058823823928833,"w":1.0},{"x":0.4627451002597809,"y":0.364705890417099,"z":0.21960784494876862,"w":1.0},{"x":0.8470588326454163,"y":0.6470588445663452,"z":0.572549045085907,"w":1.0},{"x":0.3450980484485626,"y":0.5058823823928833,"z":0.24313725531101228,"w":1.0},{"x":0.5803921818733215,"y":0.6313725709915161,"z":0.23137255012989045,"w":1.0},{"x":0.3450980484485626,"y":0.7215686440467835,"z":0.4117647111415863,"w":1.0},{"x":0.4431372582912445,"y":0.46666666865348818,"z":0.10980392247438431,"w":1.0},{"x":0.4627451002597809,"y":0.21176470816135407,"z":0.45098039507865908,"w":1.0},{"x":0.8117647171020508,"y":0.3294117748737335,"z":0.5411764979362488,"w":1.0},{"x":0.4627451002597809,"y":0.239215686917305,"z":0.40392157435417178,"w":1.0},{"x":0.7215686440467835,"y":0.3529411852359772,"z":0.40392157435417178,"w":1.0},{"x":0.843137264251709,"y":0.9058823585510254,"z":0.8078431487083435,"w":1.0},{"x":0.8235294222831726,"y":0.6470588445663452,"z":0.5372549295425415,"w":1.0},{"x":0.6823529601097107,"y":0.46666666865348818,"z":0.2862745225429535,"w":1.0},{"x":0.6352941393852234,"y":0.5333333611488342,"z":0.21176470816135407,"w":1.0},{"x":0.0470588244497776,"y":0.33725491166114809,"z":0.7372549176216126,"w":1.0},{"x":0.3529411852359772,"y":0.5058823823928833,"z":0.22745098173618318,"w":1.0},{"x":0.5843137502670288,"y":0.30588236451148989,"z":0.3294117748737335,"w":1.0},{"x":0.4274509847164154,"y":0.10588235408067703,"z":0.6117647290229797,"w":1.0},{"x":0.8941176533699036,"y":0.062745101749897,"z":0.8980392217636108,"w":1.0},{"x":0.7764706015586853,"y":0.3803921639919281,"z":0.4588235318660736,"w":1.0},{"x":0.658823549747467,"y":0.1411764770746231,"z":0.6039215922355652,"w":1.0},{"x":0.7921568751335144,"y":0.6196078658103943,"z":0.48235294222831728,"w":1.0},{"x":0.45098039507865908,"y":0.7411764860153198,"z":0.37254902720451357,"w":1.0},{"x":0.8039215803146362,"y":0.7372549176216126,"z":0.5843137502670288,"w":1.0},{"x":0.572549045085907,"y":0.6980392336845398,"z":0.32156863808631899,"w":1.0},{"x":0.2705882489681244,"y":0.7568627595901489,"z":0.5254902243614197,"w":1.0},{"x":0.6549019813537598,"y":0.3960784375667572,"z":0.2862745225429535,"w":1.0},{"x":0.6196078658103943,"y":0.658823549747467,"z":0.3019607961177826,"w":1.0},{"x":0.800000011920929,"y":0.529411792755127,"z":0.4588235318660736,"w":1.0},{"x":0.6392157077789307,"y":0.5607843399047852,"z":0.23137255012989045,"w":1.0},{"x":0.8784313797950745,"y":0.15294118225574494,"z":0.7803921699523926,"w":1.0},{"x":0.4470588266849518,"y":0.6117647290229797,"z":0.1882352977991104,"w":1.0},{"x":0.5215686559677124,"y":0.772549033164978,"z":0.4117647111415863,"w":1.0},{"x":0.5607843399047852,"y":0.5372549295425415,"z":0.10980392247438431,"w":1.0},{"x":0.5176470875740051,"y":0.49803921580314639,"z":0.027450980618596078,"w":1.0},{"x":0.45098039507865908,"y":0.4941176474094391,"z":0.08235294371843338,"w":1.0},{"x":0.1921568661928177,"y":0.26274511218070986,"z":0.6000000238418579,"w":1.0},{"x":0.40392157435417178,"y":0.545098066329956,"z":0.16470588743686677,"w":1.0},{"x":0.4117647111415863,"y":0.5607843399047852,"z":0.16862745583057404,"w":1.0},{"x":0.5960784554481506,"y":0.5686274766921997,"z":0.18039216101169587,"w":1.0},{"x":0.572549045085907,"y":0.5960784554481506,"z":0.18039216101169587,"w":1.0},{"x":0.10980392247438431,"y":0.8627451062202454,"z":0.8156862854957581,"w":1.0},{"x":0.501960813999176,"y":0.5568627715110779,"z":0.08235294371843338,"w":1.0},{"x":0.5058823823928833,"y":0.5568627715110779,"z":0.08627451211214066,"w":1.0},{"x":0.6039215922355652,"y":0.16078431904315949,"z":0.545098066329956,"w":1.0},{"x":0.6470588445663452,"y":0.47843137383461,"z":0.2235294133424759,"w":1.0},{"x":0.545098066329956,"y":0.6823529601097107,"z":0.2862745225429535,"w":1.0},{"x":0.4274509847164154,"y":0.5372549295425415,"z":0.125490203499794,"w":1.0},{"x":0.5607843399047852,"y":0.43529412150382998,"z":0.13725490868091584,"w":1.0},{"x":0.22745098173618318,"y":0.5176470875740051,"z":0.42352941632270815,"w":1.0},{"x":0.6941176652908325,"y":0.529411792755127,"z":0.29411765933036806,"w":1.0},{"x":0.3921568691730499,"y":0.6823529601097107,"z":0.32156863808631899,"w":1.0},{"x":0.5529412031173706,"y":0.5098039507865906,"z":0.08235294371843338,"w":1.0},{"x":0.4431372582912445,"y":0.5058823823928833,"z":0.09019608050584793,"w":1.0},{"x":0.3019607961177826,"y":0.3137255012989044,"z":0.41960784792900088,"w":1.0},{"x":0.6392157077789307,"y":0.6196078658103943,"z":0.27843138575553896,"w":1.0},{"x":0.5058823823928833,"y":0.49803921580314639,"z":0.0117647061124444,"w":1.0},{"x":0.11764705926179886,"y":0.7764706015586853,"z":0.7176470756530762,"w":1.0},{"x":0.43921568989753725,"y":0.41960784792900088,"z":0.16078431904315949,"w":1.0},{"x":0.25882354378700259,"y":0.8470588326454163,"z":0.6431372761726379,"w":1.0},{"x":0.5647059082984924,"y":0.23137255012989045,"z":0.4274509847164154,"w":1.0},{"x":0.38823530077934267,"y":0.5215686559677124,"z":0.1764705926179886,"w":1.0},{"x":0.5176470875740051,"y":0.3921568691730499,"z":0.1725490242242813,"w":1.0},{"x":0.529411792755127,"y":0.5372549295425415,"z":0.07058823853731156,"w":1.0},{"x":0.6431372761726379,"y":0.5568627715110779,"z":0.23137255012989045,"w":1.0},{"x":0.5372549295425415,"y":0.3686274588108063,"z":0.21568627655506135,"w":1.0},{"x":0.5372549295425415,"y":0.5921568870544434,"z":0.15294118225574494,"w":1.0},{"x":0.43529412150382998,"y":0.572549045085907,"z":0.14901961386203767,"w":1.0},{"x":0.33725491166114809,"y":0.4470588266849518,"z":0.26274511218070986,"w":1.0},{"x":0.7098039388656616,"y":0.6470588445663452,"z":0.3921568691730499,"w":1.0},{"x":0.7921568751335144,"y":0.48235294222831728,"z":0.4431372582912445,"w":1.0},{"x":0.30588236451148989,"y":0.3294117748737335,"z":0.4000000059604645,"w":1.0},{"x":0.48627451062202456,"y":0.4627451002597809,"z":0.06666667014360428,"w":1.0},{"x":0.572549045085907,"y":0.6666666865348816,"z":0.27843138575553896,"w":1.0},{"x":0.5686274766921997,"y":0.7764706015586853,"z":0.43529412150382998,"w":1.0},{"x":0.29019609093666079,"y":0.8078431487083435,"z":0.5686274766921997,"w":1.0},{"x":0.5686274766921997,"y":0.4941176474094391,"z":0.10196078568696976,"w":1.0},{"x":0.501960813999176,"y":0.4941176474094391,"z":0.01568627543747425,"w":1.0},{"x":0.3686274588108063,"y":0.545098066329956,"z":0.21568627655506135,"w":1.0},{"x":0.8078431487083435,"y":0.658823549747467,"z":0.529411792755127,"w":1.0},{"x":0.6627451181411743,"y":0.45490196347236636,"z":0.25882354378700259,"w":1.0},{"x":0.43921568989753725,"y":0.5607843399047852,"z":0.13333334028720857,"w":1.0},{"x":0.30588236451148989,"y":0.6627451181411743,"z":0.3843137323856354,"w":1.0},{"x":0.3450980484485626,"y":0.3921568691730499,"z":0.29411765933036806,"w":1.0},{"x":0.5529412031173706,"y":0.5607843399047852,"z":0.12156862765550614,"w":1.0},{"x":0.29411765933036806,"y":0.3450980484485626,"z":0.3960784375667572,"w":1.0},{"x":0.45098039507865908,"y":0.501960813999176,"z":0.08235294371843338,"w":1.0},{"x":0.6196078658103943,"y":0.6509804129600525,"z":0.29411765933036806,"w":1.0},{"x":0.23529411852359773,"y":0.5843137502670288,"z":0.42352941632270815,"w":1.0},{"x":0.2705882489681244,"y":0.3607843220233917,"z":0.4156862795352936,"w":1.0},{"x":0.6549019813537598,"y":0.8941176533699036,"z":0.6431372761726379,"w":1.0},{"x":0.5333333611488342,"y":0.3803921639919281,"z":0.1921568661928177,"w":1.0},{"x":0.47058823704719546,"y":0.3176470696926117,"z":0.2862745225429535,"w":1.0},{"x":0.5882353186607361,"y":0.929411768913269,"z":0.6627451181411743,"w":1.0},{"x":0.3019607961177826,"y":0.615686297416687,"z":0.3529411852359772,"w":1.0},{"x":0.48627451062202456,"y":0.3294117748737335,"z":0.2666666805744171,"w":1.0},{"x":0.4470588266849518,"y":0.5529412031173706,"z":0.11764705926179886,"w":1.0},{"x":0.5058823823928833,"y":0.501960813999176,"z":0.007843137718737126,"w":1.0},{"x":0.5411764979362488,"y":0.5411764979362488,"z":0.09019608050584793,"w":1.0},{"x":0.47058823704719546,"y":0.4000000059604645,"z":0.16470588743686677,"w":1.0},{"x":0.43921568989753725,"y":0.42352941632270815,"z":0.1568627506494522,"w":1.0},{"x":0.5490196347236633,"y":0.4941176474094391,"z":0.07450980693101883,"w":1.0},{"x":0.48235294222831728,"y":0.5411764979362488,"z":0.07058823853731156,"w":1.0},{"x":0.35686275362968447,"y":0.14509804546833039,"z":0.5882353186607361,"w":1.0},{"x":0.4313725531101227,"y":0.6549019813537598,"z":0.25882354378700259,"w":1.0},{"x":0.6941176652908325,"y":0.33725491166114809,"z":0.3843137323856354,"w":1.0},{"x":0.29019609093666079,"y":0.45490196347236636,"z":0.3294117748737335,"w":1.0},{"x":0.3450980484485626,"y":0.32156863808631899,"z":0.3686274588108063,"w":1.0},{"x":0.3333333432674408,"y":0.48235294222831728,"z":0.26274511218070986,"w":1.0},{"x":0.43921568989753725,"y":0.4588235318660736,"z":0.11764705926179886,"w":1.0},{"x":0.4745098054409027,"y":0.7490196228027344,"z":0.3843137323856354,"w":1.0},{"x":0.6745098233222961,"y":0.5882353186607361,"z":0.29411765933036806,"w":1.0},{"x":0.40392157435417178,"y":0.15294118225574494,"z":0.5529412031173706,"w":1.0},{"x":0.43921568989753725,"y":0.3333333432674408,"z":0.27843138575553896,"w":1.0},{"x":0.6941176652908325,"y":0.6745098233222961,"z":0.3960784375667572,"w":1.0},{"x":0.3490196168422699,"y":0.43529412150382998,"z":0.2549019753932953,"w":1.0},{"x":0.8352941274642944,"y":0.24313725531101228,"z":0.6392157077789307,"w":1.0},{"x":0.4627451002597809,"y":0.6901960968971252,"z":0.29411765933036806,"w":1.0},{"x":0.5098039507865906,"y":0.4901960790157318,"z":0.027450980618596078,"w":1.0},{"x":0.6901960968971252,"y":0.49803921580314639,"z":0.2862745225429535,"w":1.0},{"x":0.46666666865348818,"y":0.5215686559677124,"z":0.06666667014360428,"w":1.0},{"x":0.45490196347236636,"y":0.40784314274787905,"z":0.16470588743686677,"w":1.0},{"x":0.40392157435417178,"y":0.7176470756530762,"z":0.364705890417099,"w":1.0},{"x":0.45490196347236636,"y":0.5215686559677124,"z":0.08235294371843338,"w":1.0},{"x":0.10980392247438431,"y":0.3764705955982208,"z":0.6313725709915161,"w":1.0},{"x":0.8039215803146362,"y":0.45098039507865908,"z":0.47058823704719546,"w":1.0},{"x":0.5372549295425415,"y":0.4274509847164154,"z":0.125490203499794,"w":1.0},{"x":0.7019608020782471,"y":0.34117648005485537,"z":0.3960784375667572,"w":1.0},{"x":0.7333333492279053,"y":0.4745098054409027,"z":0.35686275362968447,"w":1.0},{"x":0.19607843458652497,"y":0.18039216101169587,"z":0.6745098233222961,"w":1.0},{"x":0.8784313797950745,"y":0.49803921580314639,"z":0.572549045085907,"w":1.0},{"x":0.5529412031173706,"y":0.5333333611488342,"z":0.09019608050584793,"w":1.0},{"x":0.23529411852359773,"y":0.10196078568696976,"z":0.7333333492279053,"w":1.0},{"x":0.6431372761726379,"y":0.48235294222831728,"z":0.21960784494876862,"w":1.0},{"x":0.3019607961177826,"y":0.4745098054409027,"z":0.30980393290519717,"w":1.0},{"x":0.4627451002597809,"y":0.7215686440467835,"z":0.34117648005485537,"w":1.0},{"x":0.24705882370471955,"y":0.7411764860153198,"z":0.5333333611488342,"w":1.0},{"x":0.21176470816135407,"y":0.0784313753247261,"z":0.7803921699523926,"w":1.0},{"x":0.6078431606292725,"y":0.16078431904315949,"z":0.545098066329956,"w":1.0},{"x":0.6000000238418579,"y":0.545098066329956,"z":0.16470588743686677,"w":1.0},{"x":0.007843137718737126,"y":0.8745098114013672,"z":0.9450980424880981,"w":1.0},{"x":0.16470588743686677,"y":0.7647058963775635,"z":0.6509804129600525,"w":1.0},{"x":0.19607843458652497,"y":0.772549033164978,"z":0.6235294342041016,"w":1.0},{"x":0.7607843279838562,"y":0.4745098054409027,"z":0.4000000059604645,"w":1.0},{"x":0.7058823704719544,"y":0.4941176474094391,"z":0.3137255012989044,"w":1.0},{"x":0.8352941274642944,"y":0.2666666805744171,"z":0.6196078658103943,"w":1.0},{"x":0.4588235318660736,"y":0.3137255012989044,"z":0.2980392277240753,"w":1.0},{"x":0.615686297416687,"y":0.5607843399047852,"z":0.20000000298023225,"w":1.0},{"x":0.5411764979362488,"y":0.5411764979362488,"z":0.08627451211214066,"w":1.0},{"x":0.5333333611488342,"y":0.9254902005195618,"z":0.6470588445663452,"w":1.0},{"x":0.3921568691730499,"y":0.6627451181411743,"z":0.2980392277240753,"w":1.0},{"x":0.7215686440467835,"y":0.09019608050584793,"z":0.7137255072593689,"w":1.0},{"x":0.6235294342041016,"y":0.7764706015586853,"z":0.4588235318660736,"w":1.0},{"x":0.572549045085907,"y":0.09019608050584793,"z":0.6392157077789307,"w":1.0},{"x":0.501960813999176,"y":0.5058823823928833,"z":0.007843137718737126,"w":1.0},{"x":0.3176470696926117,"y":0.6823529601097107,"z":0.3960784375667572,"w":1.0},{"x":0.5960784554481506,"y":0.501960813999176,"z":0.14901961386203767,"w":1.0},{"x":0.5607843399047852,"y":0.6666666865348816,"z":0.2705882489681244,"w":1.0},{"x":0.6509804129600525,"y":0.40784314274787905,"z":0.2705882489681244,"w":1.0},{"x":0.5098039507865906,"y":0.5215686559677124,"z":0.03529411926865578,"w":1.0},{"x":0.5411764979362488,"y":0.4274509847164154,"z":0.12941177189350129,"w":1.0},{"x":0.2705882489681244,"y":0.5960784554481506,"z":0.3843137323856354,"w":1.0},{"x":0.7450980544090271,"y":0.3294117748737335,"z":0.45490196347236636,"w":1.0},{"x":0.6078431606292725,"y":0.3686274588108063,"z":0.25882354378700259,"w":1.0},{"x":0.41960784792900088,"y":0.4313725531101227,"z":0.16862745583057404,"w":1.0},{"x":0.7411764860153198,"y":0.9058823585510254,"z":0.7176470756530762,"w":1.0},{"x":0.8039215803146362,"y":0.6431372761726379,"z":0.5098039507865906,"w":1.0},{"x":0.7647058963775635,"y":0.5372549295425415,"z":0.40784314274787905,"w":1.0},{"x":0.5215686559677124,"y":0.6705882549285889,"z":0.25882354378700259,"w":1.0},{"x":0.33725491166114809,"y":0.32156863808631899,"z":0.37254902720451357,"w":1.0},{"x":0.30588236451148989,"y":0.32549020648002627,"z":0.40392157435417178,"w":1.0},{"x":0.6352941393852234,"y":0.6705882549285889,"z":0.3294117748737335,"w":1.0},{"x":0.21568627655506135,"y":0.7450980544090271,"z":0.572549045085907,"w":1.0},{"x":0.5098039507865906,"y":0.6745098233222961,"z":0.2666666805744171,"w":1.0},{"x":0.33725491166114809,"y":0.37254902720451357,"z":0.32156863808631899,"w":1.0},{"x":0.7764706015586853,"y":0.27450981736183169,"z":0.5411764979362488,"w":1.0},{"x":0.5803921818733215,"y":0.4470588266849518,"z":0.14901961386203767,"w":1.0},{"x":0.40784314274787905,"y":0.5647059082984924,"z":0.1725490242242813,"w":1.0},{"x":0.6745098233222961,"y":0.5843137502670288,"z":0.29019609093666079,"w":1.0},{"x":0.686274528503418,"y":0.4156862795352936,"z":0.3137255012989044,"w":1.0},{"x":0.501960813999176,"y":0.5098039507865906,"z":0.01568627543747425,"w":1.0},{"x":0.5490196347236633,"y":0.8117647171020508,"z":0.47843137383461,"w":1.0},{"x":0.25882354378700259,"y":0.686274528503418,"z":0.47058823704719546,"w":1.0}]} \ No newline at end of file diff --git a/pSpecs1.json.meta b/pSpecs1.json.meta deleted file mode 100644 index b17619c..0000000 --- a/pSpecs1.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b003ce129f5413f40b83eca2229754aa -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From 47e170aa869173098d999a01c36b1566e2c3a8f6 Mon Sep 17 00:00:00 2001 From: Mo Date: Mon, 25 Apr 2022 17:00:00 +0200 Subject: [PATCH 08/14] Moved to OnRenderImage; cleaned up code; leads to pink screen on test PC --- Scripts/PhospheneSimulator.cs | 226 ++++++++++++++++------------------ 1 file changed, 105 insertions(+), 121 deletions(-) diff --git a/Scripts/PhospheneSimulator.cs b/Scripts/PhospheneSimulator.cs index fe3ee3d..7ec67c8 100644 --- a/Scripts/PhospheneSimulator.cs +++ b/Scripts/PhospheneSimulator.cs @@ -1,208 +1,192 @@ 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 UnityEngine.InputSystem; -using System.Collections; namespace Xarphos.Scripts { - // [RequireComponent(typeof(Renderer))] - public class PhospheneSimulator : MonoBehaviour { - public Camera TargetCamera; + public Camera targetCamera; // Image processing settings - float phospheneFiltering = 0.0f; - float edgeDetection = 0.0f; + private float _phospheneFiltering; + private float _edgeDetection; // EyeTracking - protected Vector2 eyePosition; - protected int gazeLocking; // used as boolean (sent to shader) - protected bool camLocking; + protected Vector2 EyePosition; + protected int GazeLocking; // used as boolean (sent to shader) + protected bool CamLocking; // Image processing settings [SerializeField] protected SurfaceReplacement.ReplacementModes surfaceReplacementMode; + private readonly int _nModes = System.Enum.GetValues(typeof(SurfaceReplacement.ReplacementModes)).Length; [SerializeField] protected Vector2Int resolution; // Render textures - [SerializeField] protected RenderTexture inputRT; - [SerializeField] protected RenderTexture activationMask; - [SerializeField] 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 ImgProcMode = Shader.PropertyToID("_Mode"); + private static readonly int ImgMatMainTex = Shader.PropertyToID("_MainTex"); + + #endregion protected void Awake() { - TargetCamera ??= GetComponent(); + targetCamera ??= GetComponent(); // Initialize the array of phosphenes - phosphenes = PhospheneConfig.InitPhosphenesFromJSON(phospheneConfigFile); - nPhosphenes = phosphenes.Length; - phospheneBuffer = new ComputeBuffer(nPhosphenes, sizeof(float)*5); - phospheneBuffer.SetData(phosphenes); + _phosphenes = PhospheneConfig.InitPhosphenesFromJSON(phospheneConfigFile); + _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); - - - } - - 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); + PhospheneMaterial.SetBuffer(PhosMatPhosphenes, _phospheneBuffer); + PhospheneMaterial.SetInt(PhosMatNPhosphenes, _nPhosphenes); + PhospheneMaterial.SetFloat(PhosMatFilter, _phospheneFiltering); + temporalDynamicsCs.SetBuffer(0,TempDynPhosphenes, _phospheneBuffer); } - void OnPreRender() { - // Render to the input render texture - TargetCamera.targetTexture = inputRT; - } - - - IEnumerator blitToScreen() + private void OnRenderImage(RenderTexture src, RenderTexture target) { - // Wait until all reder textures are rendered - yield return new WaitForEndOfFrame(); - - // Target tex has to be (temporarilty) set to null - TargetCamera.targetTexture = null; - - // Simulate the phosphenes (based on the shared phosphene buffer) - Graphics.Blit(null as RenderTexture, phospheneRT, phospheneMaterial); - - // Blit to the screen - Graphics.Blit(phospheneRT, null as RenderTexture); - yield return null; + // 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 OnDisable(){ - phospheneBuffer.Release(); + private void OnDisable(){ + _phospheneBuffer.Release(); } - void nextSurfaceReplacementMode(){ - var nModes = System.Enum.GetValues(typeof(SurfaceReplacement.ReplacementModes)).Length; - surfaceReplacementMode += 1; - - 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) - } + private void NextSurfaceReplacementMode(){ + surfaceReplacementMode = (SurfaceReplacement.ReplacementModes)((int)(surfaceReplacementMode + 1) % _nModes); + // Replace surfaces with the surface replacement shader + SurfaceReplacement.ActivateReplacementShader(targetCamera, surfaceReplacementMode); } 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;} + 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; + 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;} + 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; + EyePosition.x = 0.5f; } - if (Keyboard.current[Key.G].isPressed) + if (Keyboard.current[Key.G].wasPressedThisFrame) { - gazeLocking = 1-gazeLocking; + GazeLocking = 1-GazeLocking; } - if (Keyboard.current[Key.C].isPressed) + if (Keyboard.current[Key.C].wasPressedThisFrame) { - camLocking = !camLocking; + CamLocking = !CamLocking; } - if (Keyboard.current[Key.T].isPressed) + if (Keyboard.current[Key.T].wasPressedThisFrame) { - nextSurfaceReplacementMode(); + NextSurfaceReplacementMode(); } - if (Keyboard.current[Key.E].isPressed) + if (Keyboard.current[Key.E].wasPressedThisFrame) { - edgeDetection = 1-edgeDetection; - imageProcessingMaterial.SetFloat("_Mode", edgeDetection); + _edgeDetection = 1-_edgeDetection; + ImageProcessingMaterial.SetFloat(ImgProcMode, _edgeDetection); } - if (Keyboard.current[Key.P].isPressed) + if (Keyboard.current[Key.P].wasPressedThisFrame) { - phospheneFiltering = 1-phospheneFiltering; - phospheneMaterial.SetFloat("_PhospheneFilter", phospheneFiltering); + _phospheneFiltering = 1-_phospheneFiltering; + PhospheneMaterial.SetFloat(PhosMatFilter, _phospheneFiltering); } - phospheneMaterial.SetVector("_EyePosition", eyePosition); - phospheneMaterial.SetInt("_GazeLocked", gazeLocking); + PhospheneMaterial.SetVector(PhosMatPosition, EyePosition); + PhospheneMaterial.SetInt(PhosMatGazeLocked, GazeLocking); } } From ac58f4e1b8b3139fa81b78d532a6820e98dc75bc Mon Sep 17 00:00:00 2001 From: Mo Date: Mon, 25 Apr 2022 17:00:39 +0200 Subject: [PATCH 09/14] handle 'None' shader in function and make target cam explicit --- Scripts/SurfaceReplacement.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) 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) From f6073a741ec17d8b7f5377101d838ba388432c0d Mon Sep 17 00:00:00 2001 From: Mo Nipshagen Date: Tue, 26 Apr 2022 23:14:27 +0200 Subject: [PATCH 10/14] added include according to IDE resolve --- Shader/SurfaceReplacement.shader | 1 + 1 file changed, 1 insertion(+) 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; From 680a23cc6b364af77c91e9f958e913e50fdd49d4 Mon Sep 17 00:00:00 2001 From: Mo Nipshagen Date: Tue, 26 Apr 2022 23:14:42 +0200 Subject: [PATCH 11/14] centralised input --- Scripts/EyeTracking.cs | 2 +- Scripts/PhospheneSimulator.cs | 61 ++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/Scripts/EyeTracking.cs b/Scripts/EyeTracking.cs index 35cd455..f27e708 100644 --- a/Scripts/EyeTracking.cs +++ b/Scripts/EyeTracking.cs @@ -297,7 +297,7 @@ private void UpdateGazeRays() 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 + // transform from local space var t = mainCam.transform; leftOrigin = t.TransformPoint(leftOrigin); rightOrigin = t.TransformPoint(rightOrigin); diff --git a/Scripts/PhospheneSimulator.cs b/Scripts/PhospheneSimulator.cs index 7ec67c8..cbc5779 100644 --- a/Scripts/PhospheneSimulator.cs +++ b/Scripts/PhospheneSimulator.cs @@ -129,12 +129,44 @@ private void OnDisable(){ _phospheneBuffer.Release(); } + public void NextSurfaceReplacementMode(InputAction.CallbackContext ctx) => NextSurfaceReplacementMode(); + private void NextSurfaceReplacementMode(){ surfaceReplacementMode = (SurfaceReplacement.ReplacementModes)((int)(surfaceReplacementMode + 1) % _nModes); // Replace surfaces with the surface replacement shader SurfaceReplacement.ActivateReplacementShader(targetCamera, surfaceReplacementMode); } + public void TogglePhospheneSim(InputAction.CallbackContext ctx) => TogglePhospheneSim(); + + public void TogglePhospheneSim() + { + _phospheneFiltering = 1-_phospheneFiltering; + PhospheneMaterial.SetFloat(PhosMatFilter, _phospheneFiltering); + } + + public void ToggleEdgeDetection(InputAction.CallbackContext ctx) => ToggleEdgeDetection(); + + private void ToggleEdgeDetection() + { + _edgeDetection = 1-_edgeDetection; + ImageProcessingMaterial.SetFloat(ImgProcMode, _edgeDetection); + } + + public void ToggleCamLocking(InputAction.CallbackContext ctx) => ToggleCamLocking(); + + public void ToggleCamLocking() + { + CamLocking = !CamLocking; + } + + public void ToggleGazeLocking(InputAction.CallbackContext ctx) => ToggleGazeLocking(); + + public void ToggleGazeLocking() + { + GazeLocking = 1-GazeLocking; + PhospheneMaterial.SetInt(PhosMatGazeLocked, GazeLocking); + } protected void Update() { @@ -158,36 +190,7 @@ protected void Update() EyePosition.x = 0.5f; } - if (Keyboard.current[Key.G].wasPressedThisFrame) - { - GazeLocking = 1-GazeLocking; - } - - if (Keyboard.current[Key.C].wasPressedThisFrame) - { - CamLocking = !CamLocking; - } - - if (Keyboard.current[Key.T].wasPressedThisFrame) - { - NextSurfaceReplacementMode(); - } - - if (Keyboard.current[Key.E].wasPressedThisFrame) - { - _edgeDetection = 1-_edgeDetection; - ImageProcessingMaterial.SetFloat(ImgProcMode, _edgeDetection); - } - - if (Keyboard.current[Key.P].wasPressedThisFrame) - { - _phospheneFiltering = 1-_phospheneFiltering; - PhospheneMaterial.SetFloat(PhosMatFilter, _phospheneFiltering); - } - PhospheneMaterial.SetVector(PhosMatPosition, EyePosition); - PhospheneMaterial.SetInt(PhosMatGazeLocked, GazeLocking); } - } } From adcaa66ac7c95c98b67d157a3c897f5b814e8c88 Mon Sep 17 00:00:00 2001 From: Mo Date: Thu, 28 Apr 2022 21:17:44 +0200 Subject: [PATCH 12/14] trialling eye tracking to screen --- Scripts/EyeTracking.cs | 127 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 13 deletions(-) diff --git a/Scripts/EyeTracking.cs b/Scripts/EyeTracking.cs index f27e708..9d061e8 100644 --- a/Scripts/EyeTracking.cs +++ b/Scripts/EyeTracking.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using Unity.VisualScripting; +using UnityEditor; using UnityEngine; using UnityEngine.InputSystem; using ViveSR.anipal; @@ -36,6 +37,8 @@ public class EyeTracking : MonoBehaviour private static float time_stamp; private static int frame; + private PhospheneSimulator sim; + internal bool EyeTrackingAvailable { get; private set; } @@ -45,6 +48,8 @@ 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() @@ -58,6 +63,10 @@ private void FixedUpdate() private void Update() { + Debug.Log($"Gaze Origins:: Left: {gaze_origin_L}; Right: {gaze_origin_R}; Combined: {eyeData.verbose_data.combined.eye_data.gaze_origin_mm}"); + Debug.Log($"Gaze Convergence Data: Valid: {eyeData.verbose_data.combined.convergence_distance_validity}; Dist: {eyeData.verbose_data.combined.convergence_distance_mm:F}"); + GazeIntersection(); + if (Keyboard.current[Key.F8].wasPressedThisFrame) { SetDebugGazeRender(!renderGazeRays); @@ -207,16 +216,18 @@ private int Gcf(int a, int b) } #region EyeData Clean Up & Necessities - private void OnDisable() + void OnApplicationQuit() { Release(); } - void OnApplicationQuit() + private void OnDisable() { Release(); } + + /// /// Release callback thread when disabled or quit /// @@ -230,8 +241,12 @@ private static void Release() eye_callback_registered = false; } + Destroy(leftGazeLine.material); + Destroy(rightGazeLine.material); + Destroy(centreGazeLine.material); Destroy(leftVisual); Destroy(rightVisual); + Destroy(centreVisual); } /// @@ -257,28 +272,36 @@ private void SetDebugGazeRender(bool status) { 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.startColor = Color.green; - leftGazeLine.endColor = Color.green; + 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.startColor = Color.red; - rightGazeLine.endColor = Color.red; + rightGazeLine.material = new Material(Shader.Find("Standard")); + rightGazeLine.material.SetColor("_Color", Color.red); rightGazeLine.startWidth = 0.005f; rightGazeLine.endWidth = 0.005f; } centreGazeLine = centreVisual.AddComponent(); { - rightGazeLine.startColor = Color.white; - rightGazeLine.endColor = Color.white; - rightGazeLine.startWidth = 0.005f; - rightGazeLine.endWidth = 0.005f; + centreGazeLine.material = new Material(Shader.Find("Standard")); + centreGazeLine.material.SetColor("_Color", Color.cyan); + centreGazeLine.startWidth = 0.005f; + centreGazeLine.endWidth = 0.005f; } } @@ -306,11 +329,89 @@ private void UpdateGazeRays() 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(new [] { leftOrigin, leftOrigin + leftDir * 20 }); - rightGazeLine.SetPositions(new [] { rightOrigin, rightOrigin + rightDir * 20 }); - centreGazeLine.SetPositions(new[] { centreOrigin, centreOrigin + centreDir * 20 }); + 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 + +private Vector3 left2Frustrum, right2Frustrum, comb2Frustrum, combConverged2Screen2Frustrum; + 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, 1f, 20f, eyeData); + var frustrumPos = cam.WorldToViewportPoint(focusInfo.point); + frustrumPos.z = cam.nearClipPlane; + combConverged2Screen2Frustrum = cam.ViewportToWorldPoint(frustrumPos); + } + + 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); + } + + void 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; + + } + + #endregion } } From 7ff73c27973e39a4255bcef4f4fdad257d2bbccf Mon Sep 17 00:00:00 2001 From: Mo Date: Fri, 29 Apr 2022 17:06:49 +0200 Subject: [PATCH 13/14] working eye tracking via gaze ray cast --- Scripts/EyeTracking.cs | 196 +++++++++++++++++++++++++++++----- Scripts/PhospheneSimulator.cs | 40 ++++--- 2 files changed, 186 insertions(+), 50 deletions(-) diff --git a/Scripts/EyeTracking.cs b/Scripts/EyeTracking.cs index 9d061e8..8208276 100644 --- a/Scripts/EyeTracking.cs +++ b/Scripts/EyeTracking.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using TMPro; using Unity.VisualScripting; using UnityEditor; using UnityEngine; @@ -13,6 +14,10 @@ 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; @@ -63,22 +68,19 @@ private void FixedUpdate() private void Update() { - Debug.Log($"Gaze Origins:: Left: {gaze_origin_L}; Right: {gaze_origin_R}; Combined: {eyeData.verbose_data.combined.eye_data.gaze_origin_mm}"); - Debug.Log($"Gaze Convergence Data: Valid: {eyeData.verbose_data.combined.convergence_distance_validity}; Dist: {eyeData.verbose_data.combined.convergence_distance_mm:F}"); - GazeIntersection(); + // ToDo: Set camera to only render clip of actual screen + + // Gaze Debugging + GazeTestsUpdate(); - if (Keyboard.current[Key.F8].wasPressedThisFrame) - { - SetDebugGazeRender(!renderGazeRays); - } - if (Keyboard.current[Key.F9].wasPressedThisFrame) - { - freezeGazeRays = !freezeGazeRays; - } - if (renderGazeRays && !freezeGazeRays) - { - UpdateGazeRays(); - } + 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 @@ -231,32 +233,73 @@ private void OnDisable() /// /// Release callback thread when disabled or quit /// - private static void Release() + private void Release() { - if (eye_callback_registered == true) + Debug.Log("Releasing..."); + if (eye_callback_registered) { SRanipal_Eye_v2.WrapperUnRegisterEyeDataCallback( Marshal.GetFunctionPointerForDelegate((SRanipal_Eye_v2.CallbackBasic)EyeCallback) ); eye_callback_registered = false; } - - Destroy(leftGazeLine.material); - Destroy(rightGazeLine.material); - Destroy(centreGazeLine.material); - Destroy(leftVisual); - Destroy(rightVisual); - Destroy(centreVisual); + // Gaze Debugging + if (DebugGazeRays) GazeTestsRelease(); + Debug.Log("Releasing Done."); } /// /// Required class for IL2CPP scripting backend support /// - internal class MonoPInvokeCallbackAttribute : System.Attribute + internal class MonoPInvokeCallbackAttribute : Attribute { } +#endregion + + private void GazeTestsUpdate() { - public MonoPInvokeCallbackAttribute() { } + 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); + } } -#endregion #region Debug Gaze Rendering private static bool renderGazeRays, freezeGazeRays; @@ -351,7 +394,13 @@ private void UpdateGazeRays() #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; @@ -383,10 +432,23 @@ void GazeIntersection() right2Frustrum = cam.transform.TransformPoint(intersectionRight); comb2Frustrum = cam.transform.TransformPoint(intersectionCombined); - SRanipal_Eye_v2.Focus(GazeIndex.COMBINE, out _, out var focusInfo, 1f, 20f, eyeData); + 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() @@ -401,7 +463,7 @@ private void OnDrawGizmosSelected() Gizmos.DrawSphere(combConverged2Screen2Frustrum, .01f); } - void MinDistanceGazeVectors() + float MinDistanceGazeVectors() { var cross = Vector3.Cross(eyeData.verbose_data.left.gaze_direction_normalized, eyeData.verbose_data.right.gaze_direction_normalized); @@ -410,6 +472,82 @@ void MinDistanceGazeVectors() 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/PhospheneSimulator.cs b/Scripts/PhospheneSimulator.cs index cbc5779..74375d4 100644 --- a/Scripts/PhospheneSimulator.cs +++ b/Scripts/PhospheneSimulator.cs @@ -6,7 +6,7 @@ namespace Xarphos.Scripts public class PhospheneSimulator : MonoBehaviour { public Camera targetCamera; - + public bool manualEyePos; // Image processing settings private float _phospheneFiltering; @@ -168,29 +168,27 @@ public void ToggleGazeLocking() PhospheneMaterial.SetInt(PhosMatGazeLocked, GazeLocking); } + public void SetEyePosition(Vector2 pos) + { + EyePosition = pos; + PhospheneMaterial.SetVector(PhosMatPosition, EyePosition); + } + protected void Update() { - 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 (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; - PhospheneMaterial.SetVector(PhosMatPosition, EyePosition); + 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); + } } } } From a161f80203493107c3dcd97a80abd2ef42eef2de Mon Sep 17 00:00:00 2001 From: Mo Date: Tue, 10 May 2022 17:00:22 +0200 Subject: [PATCH 14/14] Fit jaap into input scheme --- Scripts/PhospheneSimulator.cs | 75 ++-- Xarphos-Basement.cs | 666 +++++++++++++++++++++++++++++ Xarphos-Basement.cs.meta | 11 + Xarphos-Basement.inputactions | 433 +++++++++++++++++++ Xarphos-Basement.inputactions.meta | 14 + 5 files changed, 1164 insertions(+), 35 deletions(-) create mode 100644 Xarphos-Basement.cs create mode 100644 Xarphos-Basement.cs.meta create mode 100644 Xarphos-Basement.inputactions create mode 100644 Xarphos-Basement.inputactions.meta diff --git a/Scripts/PhospheneSimulator.cs b/Scripts/PhospheneSimulator.cs index 3bdff8c..1995648 100644 --- a/Scripts/PhospheneSimulator.cs +++ b/Scripts/PhospheneSimulator.cs @@ -18,9 +18,10 @@ public class PhospheneSimulator : MonoBehaviour protected bool CamLocking; // Image processing settings - [SerializeField] protected DSPVEyeTracking.EyeTrackingConditions eyeTrackingCondition; + [SerializeField] protected EyeTracking.EyeTrackingConditions eyeTrackingCondition; [SerializeField] protected SurfaceReplacement.ReplacementModes surfaceReplacementMode; - private readonly int _nModes = System.Enum.GetValues(typeof(SurfaceReplacement.ReplacementModes)).Length; + 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; @@ -66,6 +67,7 @@ public class PhospheneSimulator : MonoBehaviour 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"); @@ -110,8 +112,8 @@ protected void Awake() 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) @@ -137,11 +139,37 @@ private void OnDisable(){ public void NextSurfaceReplacementMode(InputAction.CallbackContext ctx) => NextSurfaceReplacementMode(); private void NextSurfaceReplacementMode(){ - surfaceReplacementMode = (SurfaceReplacement.ReplacementModes)((int)(surfaceReplacementMode + 1) % _nModes); + 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(); + + private void NextEyeTrackingCondition() + { + eyeTrackingCondition = (EyeTracking.EyeTrackingConditions)((int)(eyeTrackingCondition + 1) % _nEyeTrackingModes); + + 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; + } + } + public void TogglePhospheneSim(InputAction.CallbackContext ctx) => TogglePhospheneSim(); public void TogglePhospheneSim() @@ -179,31 +207,6 @@ public void SetEyePosition(Vector2 pos) PhospheneMaterial.SetVector(PhosMatPosition, EyePosition); } - 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); - } - } - protected void Update() { if (manualEyePos) @@ -216,12 +219,14 @@ protected void Update() 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); - } + if (Keyboard.current[Key.C].isPressed) + { + NextEyeTrackingCondition(); + print("Condition: " + eyeTrackingCondition); } } } 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: