public static Vector2 GetRetinalDiameter(this HeadsetModel headset) { return(new Vector2( headset.GetRetinalDiameter(Axis.Horizontal), headset.GetRetinalDiameter(Axis.Vertical) )); }
/// <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)); }
/// <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)); }
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()); }
/* * 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); }
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(); }