Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
8.9 KiB

  1. // Tunnel Overlay|Locomotion|20140
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Applys a tunnel overlay effect to the active VR camera when the play area is moving or rotating to reduce potential nausea caused by simulation sickness.
  7. /// </summary>
  8. /// <remarks>
  9. /// **Script Usage:**
  10. /// * Place the `VRTK_TunnelOverlay` script on any active scene GameObject.
  11. ///
  12. /// > This implementation is based on a project made by SixWays at https://github.com/SixWays/UnityVrTunnelling
  13. /// </remarks>
  14. [AddComponentMenu("VRTK/Scripts/Locomotion/VRTK_TunnelOverlay")]
  15. public class VRTK_TunnelOverlay : MonoBehaviour
  16. {
  17. [Header("Movement Settings")]
  18. [Tooltip("Minimum rotation speed for the effect to activate (degrees per second).")]
  19. public float minimumRotation = 0f;
  20. [Tooltip("Maximum rotation speed for the effect have its max settings applied (degrees per second).")]
  21. public float maximumRotation = 45f;
  22. [Tooltip("Minimum movement speed for the effect to activate.")]
  23. public float minimumSpeed = 0f;
  24. [Tooltip("Maximum movement speed where the effect will have its max settings applied.")]
  25. public float maximumSpeed = 1f;
  26. [Header("Effect Settings")]
  27. [Tooltip("The color to use for the tunnel effect.")]
  28. public Color effectColor = Color.black;
  29. [Tooltip("An optional skybox texture to use for the tunnel effect.")]
  30. public Texture effectSkybox;
  31. [Tooltip("The initial amount of screen coverage the tunnel to consume without any movement.")]
  32. [Range(0f, 1f)]
  33. public float initialEffectSize = 0f;
  34. [Tooltip("Screen coverage at the maximum tracked values.")]
  35. [Range(0f, 1f)]
  36. public float maximumEffectSize = 0.65f;
  37. [Tooltip("Feather effect size around the cut-off as fraction of screen.")]
  38. [Range(0f, 0.5f)]
  39. public float featherSize = 0.1f;
  40. [Tooltip("Smooth out radius over time.")]
  41. public float smoothingTime = 0.15f;
  42. protected Transform headset;
  43. protected Camera headsetCamera;
  44. protected Transform playarea;
  45. protected VRTK_TunnelEffect cameraEffect;
  46. protected float angularVelocity;
  47. protected float angularVelocitySlew;
  48. protected Vector3 lastForward;
  49. protected Vector3 lastPosition;
  50. protected Material matCameraEffect;
  51. protected int shaderPropertyColor;
  52. protected int shaderPropertyAV;
  53. protected int shaderPropertyFeather;
  54. protected int shaderPropertySkyboxTexture;
  55. protected Color originalColor;
  56. protected float originalAngularVelocity;
  57. protected float originalFeatherSize;
  58. protected Texture originalSkyboxTexture;
  59. protected float maximumEffectCoverage = 1.15f;
  60. protected bool createEffectSkybox = false;
  61. protected virtual void Awake()
  62. {
  63. matCameraEffect = Resources.Load<Material>("TunnelOverlay");
  64. shaderPropertyColor = Shader.PropertyToID("_Color");
  65. shaderPropertyAV = Shader.PropertyToID("_AngularVelocity");
  66. shaderPropertyFeather = Shader.PropertyToID("_FeatherSize");
  67. shaderPropertySkyboxTexture = Shader.PropertyToID("_SecondarySkyBox");
  68. VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
  69. }
  70. protected virtual void OnEnable()
  71. {
  72. headset = VRTK_DeviceFinder.HeadsetCamera();
  73. if (headset != null)
  74. {
  75. headsetCamera = headset.GetComponent<Camera>();
  76. cameraEffect = headset.GetComponent<VRTK_TunnelEffect>();
  77. }
  78. playarea = VRTK_DeviceFinder.PlayAreaTransform();
  79. originalAngularVelocity = matCameraEffect.GetFloat(shaderPropertyAV);
  80. originalFeatherSize = matCameraEffect.GetFloat(shaderPropertyFeather);
  81. originalColor = matCameraEffect.GetColor(shaderPropertyColor);
  82. CheckSkyboxTexture();
  83. if (effectSkybox != null)
  84. {
  85. originalSkyboxTexture = matCameraEffect.GetTexture(shaderPropertySkyboxTexture);
  86. matCameraEffect.SetTexture("_SecondarySkyBox", effectSkybox);
  87. }
  88. if (cameraEffect == null && headset != null)
  89. {
  90. cameraEffect = headset.gameObject.AddComponent<VRTK_TunnelEffect>();
  91. cameraEffect.SetMaterial(matCameraEffect);
  92. }
  93. }
  94. protected virtual void OnDisable()
  95. {
  96. headset = null;
  97. headsetCamera = null;
  98. playarea = null;
  99. if (cameraEffect != null)
  100. {
  101. matCameraEffect.SetTexture("_SecondarySkyBox", originalSkyboxTexture);
  102. originalSkyboxTexture = null;
  103. SetShaderFeather(originalColor, originalAngularVelocity, originalFeatherSize);
  104. matCameraEffect.SetColor(shaderPropertyColor, originalColor);
  105. Destroy(cameraEffect);
  106. }
  107. if (createEffectSkybox)
  108. {
  109. effectSkybox = null;
  110. createEffectSkybox = false;
  111. }
  112. }
  113. protected virtual void OnDestroy()
  114. {
  115. VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
  116. }
  117. protected virtual void FixedUpdate()
  118. {
  119. Vector3 fwd = playarea.forward;
  120. Vector3 pos = playarea.position;
  121. float newAngularVelocity = Vector3.Angle(lastForward, fwd) / Time.fixedDeltaTime;
  122. newAngularVelocity = (newAngularVelocity - minimumRotation) / (maximumRotation - minimumRotation);
  123. if (maximumSpeed > 0)
  124. {
  125. float speed = (pos - lastPosition).magnitude / Time.fixedDeltaTime;
  126. speed = (speed - minimumSpeed) / (maximumSpeed - minimumSpeed);
  127. if (speed > newAngularVelocity)
  128. {
  129. newAngularVelocity = speed;
  130. }
  131. }
  132. float actualInitialSize = (initialEffectSize * maximumEffectCoverage);
  133. float actualMaxSize = (maximumEffectSize * maximumEffectCoverage) - actualInitialSize;
  134. newAngularVelocity = Mathf.Clamp01(newAngularVelocity) * actualMaxSize;
  135. angularVelocity = Mathf.SmoothDamp(angularVelocity, newAngularVelocity, ref angularVelocitySlew, smoothingTime);
  136. SetShaderFeather(effectColor, angularVelocity + actualInitialSize, featherSize);
  137. lastForward = fwd;
  138. lastPosition = pos;
  139. if (effectSkybox != null)
  140. {
  141. matCameraEffect.SetMatrixArray("_EyeToWorld", new Matrix4x4[2]
  142. {
  143. headsetCamera.GetStereoViewMatrix(Camera.StereoscopicEye.Left).inverse,
  144. headsetCamera.GetStereoViewMatrix(Camera.StereoscopicEye.Right).inverse
  145. });
  146. Matrix4x4[] eyeProjection = new Matrix4x4[2];
  147. eyeProjection[0] = headsetCamera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);
  148. eyeProjection[1] = headsetCamera.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right);
  149. eyeProjection[0] = GL.GetGPUProjectionMatrix(eyeProjection[0], true).inverse;
  150. eyeProjection[1] = GL.GetGPUProjectionMatrix(eyeProjection[1], true).inverse;
  151. eyeProjection[0][1, 1] *= -1f;
  152. eyeProjection[1][1, 1] *= -1f;
  153. matCameraEffect.SetMatrixArray("_EyeProjection", eyeProjection);
  154. }
  155. }
  156. protected virtual void SetShaderFeather(Color givenTunnelColor, float givenAngularVelocity, float givenFeatherSize)
  157. {
  158. matCameraEffect.SetColor(shaderPropertyColor, givenTunnelColor);
  159. matCameraEffect.SetFloat(shaderPropertyAV, givenAngularVelocity);
  160. matCameraEffect.SetFloat(shaderPropertyFeather, givenFeatherSize);
  161. }
  162. protected virtual void CheckSkyboxTexture()
  163. {
  164. if (effectSkybox == null)
  165. {
  166. Cubemap tempTexture = new Cubemap(1, TextureFormat.ARGB32, false);
  167. tempTexture.SetPixel(CubemapFace.NegativeX, 0, 0, Color.white);
  168. tempTexture.SetPixel(CubemapFace.NegativeY, 0, 0, Color.white);
  169. tempTexture.SetPixel(CubemapFace.NegativeZ, 0, 0, Color.white);
  170. tempTexture.SetPixel(CubemapFace.PositiveX, 0, 0, Color.white);
  171. tempTexture.SetPixel(CubemapFace.PositiveY, 0, 0, Color.white);
  172. tempTexture.SetPixel(CubemapFace.PositiveZ, 0, 0, Color.white);
  173. effectSkybox = tempTexture;
  174. createEffectSkybox = true;
  175. }
  176. else if (effectColor.r < 0.15f && effectColor.g < 0.15 && effectColor.b < 0.15)
  177. {
  178. VRTK_Logger.Warn("`VRTK_TunnelOverlay` has an `Effect Skybox` texture but the `Effect Color` is too dark which will tint the texture so it is not visible.");
  179. }
  180. }
  181. }
  182. }