/// <summary> /// Identifies the binocular suppression ratio. /// </summary> /// <returns>The binocular suppression ratio.</returns> /// <param name="ratioController">Ratio controller. Where we get our signal from to alter the ratio - e.g. tilt angle of head</param> /// <param name="model">Model. The model that provides us the conflict images.</param> /// <param name="cameraRig">Camera rig. The cameras whose relative brightness we wish to alter.</param> /// <param name="stillness">Stillness. Where we get information from about whether or not the headset is still. Might have been better to pass this headset specific mechanism to the VRHeadsetInput, which could have implemented a generic interface for reporting "stillness"</param> /// <param name="indicator">Indicator. The element which informs the user about the progress of the stillness based selection</param> /// <param name="NextStep">Next step.</param> /// <param name="secondsOfStillnessForSelect">Seconds of stillness for select.</param> IEnumerator IdentifyBinocularSuppressionRatio(EyeSkillsVRHeadsetInput ratioController, ConflictZoneModel model, EyeSkillsCameraRig cameraRig, EyeSkillsVRHeadsetSelectByStillness stillness, SelectionIndicatorScaler indicator, Action <float> NextStep, float secondsOfStillnessForSelect) { float suppressionRatio = 0; float still = 0; float brightnessRatio; stillness.StartTracking(); //TODO : We probably need a maximum timeout for if the headset never appears to settle! still = stillness.getTimeStill(); while (still < secondsOfStillnessForSelect) { //Update the luminance ratio for each eye brightnessRatio = Mathf.Clamp(ratioController.getVerticalDirection(), -1, 1); cameraRig.SetBinocularSuppressionRatio(brightnessRatio); //redraw the indicator and play a rising tone?!? float percentage = (still / secondsOfStillnessForSelect); //Debug.Log("Percentage still " + percentage); indicator.SetIndicatorPercentage(percentage); yield return(null); still = stillness.getTimeStill(); //Debug.Log("ratio : "+ brightnessRatio + " %:" + percentage); } stillness.StopTracking(); indicator.Reset(); StopConflictEnvironment(); NextStep(suppressionRatio); }
/// <summary> /// Coordinating what the participant experiences on the basis of the atom's supplied physicsState. /// Doing things this way should actually simplify things like certifying the app is in known states. /// </summary> /// <param name="_completionCallback">Completion callback.</param> public override void Start(Action <String> _completionCallback) { base.Start(_completionCallback); Debug.Log("Making the camera look forward by default, without following headset rotation."); cameraRig.ImmediatelyLookToOrigin(); cameraRig.SetLeftEyePositionOnly(); cameraRig.SetRightEyePositionOnly(); Debug.Log("UIMolecule disabled by default."); DeActivateUIMolecule(); completionCallback = _completionCallback; if (atom.physicsState == 1) //Let the participant know what is coming. { ActivateUIMolecule(); audioManager.Say(atom.audioFile, delegate() { AtomExpiry(0, false, "Physics state 1 - After audio expires"); }); } else if (atom.physicsState == 2) //Present them with a conflict image { audioManager.Say(atom.audioFile, StopConflictEnvironment, 5); StartConflictEnvironment(); } else if (atom.physicsState == 3) //How did they perceive the image? The gallery. { //Allow the user to look around cameraRig.SetLeftEyeRotationAndPosition(); cameraRig.SetRightEyeRotationAndPosition(); audioManager.Say(atom.audioFile); StartPerceptionGallery(SelectedPerceptionImage); } else if (atom.physicsState == 5) //Now find out if blinkers can remove conflict for them { StartConflictEnvironment(); conflictController.OutOfConflict(); blinkerExperienceInSeconds = 6; //Allow some time after the audio has finished to keep observing audioManager.Say(atom.audioFile, delegate() { coRoutineHelper.BeginCoroutine(TimeBlinkerExperience()); }); } else if (atom.physicsState == 6) //Did the blinkers remove conflict for them? { ReviewBlinkerExperience(); } else if (atom.physicsState == 7) //TODO: Day1 - OBSOLETE? { UIMolecule m = ActivateUIMolecule(); SetDefaultVRImage(m, atom.image); ActivateContinueButton(false); ExplainBlinkerExperience(); } else if (atom.physicsState == 8) //Day2 - Present a conflict environment for ten seconds after audio ends : Similar to state 2 { audioManager.Say(atom.audioFile, StopConflictEnvironment, 10); StartConflictEnvironment(); } else if (atom.physicsState == 9) //Day2 - Show the static Blinker { Debug.Log("Explaining about Blinkers, after audio ends, we start blinking..."); //Manually start the conflict environment. StartConflictEnvironment(); conflictController.OutOfConflict(); blinkerExperienceInSeconds = 10; audioManager.Say(atom.audioFile, delegate() { coRoutineHelper.BeginCoroutine(TimeBlinkerExperience()); }); } else if (atom.physicsState == 10) //Now show the alternating Blinker toggling { blinkerExperienceInSeconds = 30; StartBlinkerEnvironment(); audioManager.Say(atom.audioFile); } else if (atom.physicsState == 11) //Present them with a conflict image { audioManager.Say(atom.audioFile, StopConflictEnvironment); StartConflictEnvironment(); } else if (atom.physicsState == 12) { //Test they can tilt their heads upwards //Get hold of the HeadsetVRInput DemoSuppression(); if (data.numberOfTiltAttempts >= maxNumberOfTiltAttempts) { data.numberOfTiltAttempts = 0; //A hack for testing. Shouldn't affect production data.Save(); } audioManager.Say(atom.audioFile, delegate(){ DetectVerticalHeadTilt(EndUpwardTiltCheck, timeToWaitForHeadTiltCheck);//We pass "0" to the EndUpwardTiltCheck to signify we ran out of time. }); } else if (atom.physicsState == 13) { DemoSuppression(); if (data.numberOfTiltAttempts >= maxNumberOfTiltAttempts) { data.numberOfTiltAttempts = 0; //A hack for testing. Shouldn't affect production data.Save(); } //Test they can tilt their heads downwards audioManager.Say(atom.audioFile, delegate() { DetectVerticalHeadTilt(EndDownwardTiltCheck, timeToWaitForHeadTiltCheck); }); } else if (atom.physicsState == 14) //Decide whether to repeat the tilt tests or not { if ((data.couldTiltUpward == false) || (data.couldTiltDownward == false)) { //Debug.Log("One of the tilts failed " + data.couldTiltUpward + data.couldTiltDownward); if (data.numberOfTiltAttempts == (maxNumberOfTiltAttempts - 1)) //We've already tried enough times and still don't have adequate tilt //Debug.Log("Too many attempts"); { data.numberOfTiltAttempts = maxNumberOfTiltAttempts; AtomExpiry(0, true, "Failed to tilt head adequately"); } else { //Let's have another go AtomExpiry(1, true, "Trying another round of head tilt tests"); } } else //They must have succeeded { AtomExpiry(2, true, "Head tilt tests succeeded"); } } else if (atom.physicsState == 15) //Time to detect the suppression ratio { //Enable head rotation cameraRig.SetLeftEyeRotationAndPosition(); cameraRig.SetRightEyeRotationAndPosition(); //Get hold of the HeadsetVRInput EyeSkillsVRHeadsetInput ratioController = GameObject.Find("Head").GetComponent <EyeSkillsVRHeadsetInput>(); //Get hold of the conflict objects StartConflictEnvironment(); //Sets conflictZoneModel SelectionIndicatorScaler indicator = cameraRig.GetComponentInChildren <SelectionIndicatorScaler>(); //Get hold of our Stillness Selector - adding it to the Head object EyeSkillsVRHeadsetSelectByStillness stillness = EyeSkillsVRHeadsetSelectByStillness.instance; audioManager.Say(atom.audioFile, delegate() { //Start a couroutine which manages the brightness control and calls a finishing function with a suppression ratio Coroutine c = coRoutineHelper.BeginCoroutine(IdentifyBinocularSuppressionRatio( ratioController, conflictController, cameraRig, stillness, indicator, delegate(float suppressionRatio) { data.binocularSuppressionRatio = suppressionRatio; data.Save(); AtomExpiry(0, false, "SuppressionRatio captured"); }, 6f )); coroutinesToShutdown.Add(c); }); } else if (atom.physicsState == 16) { ActivateUIMolecule(); //Allow the user to look around cameraRig.SetLeftEyeRotationAndPosition(); cameraRig.SetRightEyeRotationAndPosition(); audioManager.Say(atom.audioFile); StartPerceptionGallery(SelectedTolerancePerceptionImage); } }