예제 #1
0
 public static Vector2 GetRetinalDiameter(this HeadsetModel headset)
 {
     return(new Vector2(
                headset.GetRetinalDiameter(Axis.Horizontal),
                headset.GetRetinalDiameter(Axis.Vertical)
                ));
 }
예제 #2
0
        /// <summary>
        /// Pixel (i, j) -> Visual Angle (um)
        /// </summary>
        public static Vector2 PixelToRetina(int i, int j, HeadsetModel headset)
        {
            var horizontalDiameter = headset.GetRetinalDiameter(Axis.Horizontal);
            var verticalDiameter   = headset.GetRetinalDiameter(Axis.Vertical);

            var x = ((float)i / headset.GetWidth() - .5f) * horizontalDiameter;
            var y = ((float)j / headset.GetHeight() - .5f) * verticalDiameter;

            return(new Vector2(x, y));
        }
예제 #3
0
        /// <summary>
        /// Retinal position (um) -> Pixel (i, j)
        /// </summary>
        public static Vector2 RetinaToPixel(Vector2 retina, HeadsetModel headset)
        {
            var horizontalDiameter = headset.GetRetinalDiameter(Axis.Horizontal);
            var verticalDiameter   = headset.GetRetinalDiameter(Axis.Vertical);

            var x = (retina.x / horizontalDiameter + .5f) * headset.GetWidth();
            var y = (retina.y / verticalDiameter + .5f) * headset.GetHeight();

            return(new Vector2(x, y));
        }
예제 #4
0
        void OnGUI()
        {
            UnityGUI.Header("Coordinates");
            headset = UnityGUI.Enum("Headset", headset);

            UnityGUI.Space();

            UnityGUI.BeginHorizontal();
            UnityGUI.Label(" ", "X", UnityGUI.BoldLabel);
            UnityGUI.Label("Y", UnityGUI.BoldLabel);
            UnityGUI.EndHorizontal();

            UnityGUI.BeginHorizontal();
            UnityGUI.Label("Resolution", headset.GetWidth().ToString());
            UnityGUI.Label(headset.GetHeight().ToString());
            UnityGUI.EndHorizontal();

            UnityGUI.BeginHorizontal();
            UnityGUI.Label("Field of View", ((int)headset.GetFieldOfView(Axis.Horizontal)).ToString());
            UnityGUI.Label(((int)headset.GetFieldOfView(Axis.Vertical)).ToString());
            UnityGUI.EndHorizontal();

            UnityGUI.BeginHorizontal();
            UnityGUI.Label("Diameter (um)", ((int)headset.GetRetinalDiameter(Axis.Horizontal)).ToString());
            UnityGUI.Label(((int)headset.GetRetinalDiameter(Axis.Vertical)).ToString());
            UnityGUI.EndHorizontal();

            UnityGUI.Space();

            Draw("Pixel", ref pixel);
            Draw("Visual Angle", ref angle);
            Draw("Retina (um)", ref retina);
            Draw("Polar", ref polar);

            UnityGUI.Separator();
            UnityGUI.Header("Electrode Count");

            UnityGUI.BeginChangeCheck();
            pattern     = UnityGUI.Enum("Pattern", pattern);
            layout      = UnityGUI.Enum("Layout", layout);
            fieldOfView = UnityGUI.Float("Field of View", fieldOfView);
            var changed = UnityGUI.EndChangeCheck();

            if (changed)
            {
                numElectrodes = pattern.GetElectrodePositions(layout, fieldOfView).Length;
            }

            UnityGUI.Space();
            UnityGUI.Label("Electode Count", numElectrodes.ToString());
        }
예제 #5
0
        /*
         * Private methods
         */

        private static void StartGPU(DataType type, HeadsetModel headset, ElectrodePattern pattern, ElectrodeLayout layout, string path)
        {
            var shader = LoadAsset <ComputeShader>($"{type}");
            var kernel = shader.FindKernel("CSMain");

            var electrodeBuffer = default(ComputeBuffer);

            if (type == DataType.Phosphene)
            {
                var electrodes = pattern.GetElectrodePositions(layout);
                electrodeBuffer = new ComputeBuffer(electrodes.Length, sizeof(float) * 2);
                electrodeBuffer.SetData(electrodes);
                shader.SetBuffer(kernel, "_electrodes", electrodeBuffer);
            }

            var texture = headset.CreateRenderTexture();

            shader.SetTexture(kernel, "_result", texture);
            shader.SetVector("_headset_diameter", headset.GetRetinalDiameter());
            shader.SetVector("_headset_resolution", headset.GetResolution());

            shader.Dispatch(kernel, headset.GetWidth() / 8, headset.GetHeight() / 8, 1);
            electrodeBuffer?.Dispose();

            Texture2D asset = texture.ToTexture2D(TextureFormat.RGBAFloat, true);

            texture.Release();

            asset.anisoLevel = 0;
            asset.filterMode = FilterMode.Point;

            if (type == DataType.Phosphene)
            {
                AddRandomSeeds(asset);
            }

            SaveAsset(asset, path);
        }
예제 #6
0
        private void UpdatePerChangeData()
        {
            //
            // textures are only updated when necessary for efficiencies sake
            //

            // axon texture
            if (headset != lastHeadset)
            {
                tail.SetTexture(SP.axonTexture, epiretinalData.GetAxonTexture(headset));

                if (overrideCameraFOV)
                {
                    Prosthesis.Instance.Camera.fieldOfView = headset.GetFieldOfView(Axis.Vertical);
                }

                if (overrideRefreshRate)
                {
                    Application.targetFrameRate = headset.GetRefreshRate();
                }

                lastHeadset = headset;
            }

            // phosphene texture
            if (headset != lastHeadset || pattern != lastPattern || layout != lastLayout)
            {
                phos.SetTexture(SP.electrodeTexture, epiretinalData.GetPhospheneTexture(headset, pattern, layout));

                lastHeadset = headset;
                lastPattern = pattern;
                lastLayout  = layout;
            }

            //
            // everything else is updated every frame
            // there is already per-frame data that needs to be uploaded to graphics card anyway (e.g., eye gaze, pulse),
            //	so adding a few more floats probably isn't a big performance hit (probably, definitely not tested)
            //

            // headset diameter
            var headsetDiameter = headset.GetRetinalDiameter();

            phos.SetVector(SP.headsetDiameter, headsetDiameter);
            tail.SetVector(SP.headsetDiameter, headsetDiameter);

            // electrode radius
            phos.SetFloat(SP.electrodeRadius, layout.GetRadius(LayoutUsage.Anatomical));

            // implant radius
            var implantRadius = CoordinateSystem.FovToRetinalRadius(fieldOfView);

            phos.SetFloat(SP.polyretinaRadius, implantRadius);
            tail.SetFloat(SP.polyretinaRadius, implantRadius);

            // brightness
            phos.SetFloat(SP.brightness, brightness);

            // luminance levels
            phos.SetInt(SP.luminanceLevels, luminanceLevels);

            // luminance boost
            var range = 1 - (1f / luminanceLevels);

            phos.SetFloat(SP.luminanceBoost, luminanceBoost * range);

            // variance
            phos.SetFloat(SP.sizeVariance, sizeVariance);
            phos.SetFloat(SP.intensityVariance, intensityVariance);
            phos.SetFloat(SP.brokenChance, brokenChance);

            // decay constant
            tail.SetFloat(SP.decayConst, tailLength);

            // update decay/recovery fading parameters
            UpdateDecayParameters(decayT1, decayT2, decayThreshold);
            UpdateRecoveryParameters(recoveryDelay, recoveryTime, recoveryExponent);

            // keywords
            UpdateKeyword("USE_FADING", useFading);
            UpdateKeyword("RT_TARGET", Prosthesis.Instance.Camera.targetTexture != null);
            UpdateKeyword("OUTLINE", outlineDevice);
            UpdateTailQuality();
            UpdateTargetEye();
        }