// Copyright 2016 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using UnityEngine; using UnityEngine.EventSystems; /// This script provides shared functionality used by all Gvr raycasters. public abstract class GvrBasePointerRaycaster : BaseRaycaster { public enum RaycastMode { /// Default method for casting ray. /// Casts a ray from the camera through the target of the pointer. /// This is ideal for reticles that are always rendered on top. /// The object that is selected will always be the object that appears /// underneath the reticle from the perspective of the camera. /// This also prevents the reticle from appearing to "jump" when it starts/stops hitting an object. /// /// Note: This will prevent the user from pointing around an object to hit something that is out of sight. /// This isn't a problem in a typical use case. Camera, /// Cast a ray directly from the pointer origin. /// This is ideal for full-length laser pointers. Direct } /// Determines which raycast mode to use for this raycaster. public RaycastMode raycastMode = RaycastMode.Camera; private Ray lastRay; /// Returns the pointer's maximum distance from the pointer's origin. public float MaxPointerDistance { get { if (GvrPointerManager.Pointer == null) { return 0.0f; } return GvrPointerManager.Pointer.MaxPointerDistance; } } /// Returns the pointer's radius to use for the raycast. public float PointerRadius { get { if (GvrPointerManager.Pointer == null) { return 0.0f; } float enterRadius, exitRadius; GvrPointerManager.Pointer.GetPointerRadius(out enterRadius, out exitRadius); if (GvrPointerManager.Pointer.ShouldUseExitRadiusForRaycast) { return exitRadius; } else { return enterRadius; } } } protected GvrBasePointerRaycaster() { } /// Returns true if the pointer and the pointer's transform are both /// available through the GvrPointerManager. public bool IsPointerAvailable() { if (GvrPointerManager.Pointer == null) { return false; } if (GvrPointerManager.Pointer.PointerTransform == null) { return false; } return true; } public Ray GetLastRay() { return lastRay; } /// Calculates the ray to use for raycasting based on /// the selected raycast mode. protected Ray GetRay() { if (!IsPointerAvailable()) { Debug.LogError("Calling GetRay when the pointer isn't available."); lastRay = new Ray(); return lastRay; } Transform pointerTransform = GvrPointerManager.Pointer.PointerTransform; switch (raycastMode) { case RaycastMode.Camera: Vector3 rayPointerStart = pointerTransform.position; Vector3 rayPointerEnd = rayPointerStart + (pointerTransform.forward * MaxPointerDistance); Vector3 cameraLocation = Camera.main.transform.position; Vector3 finalRayDirection = rayPointerEnd - cameraLocation; finalRayDirection.Normalize(); Vector3 finalRayStart = cameraLocation + (finalRayDirection * Camera.main.nearClipPlane); lastRay = new Ray(finalRayStart, finalRayDirection); break; case RaycastMode.Direct: lastRay = new Ray(pointerTransform.position, pointerTransform.forward); break; default: lastRay = new Ray(); break; } return lastRay; } }