Instantly share code, notes, and snippets.

Embed
What would you like to do?
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using NUnit.Framework;
using Object = UnityEngine.Object;
// LINK: Original code for solution: http://goo.gl/cAlqjS (see Gibbonator's solution)
// LINK: Extend editor so we can set sorting layers on andything with a mesh renderer: http://goo.gl/VehK0j
public enum ReticleTargetState { None = 0, UGUIFlat, UGUICurved, World }
public class Reticle : MonoBehaviour
{
public Camera CameraLeft; // NOTE: set in editor
public Camera CameraRight; // NOTE: set in editor
public Ray FocusRay;
public RaycastHit FocusHitPoint;
public GameObject Target;
public ReticleTargetState TargetState = ReticleTargetState.None;
float distance;
Color nextColor = Color.white;
Transform centerEye;
Vector3 originalScale;
MappedGraphicRaycaster mappedRaycaster; // override 'Raycast' to remap input for curved surface
GraphicRaycaster normalRaycaster; // used to look for any UGUI elements
List<RaycastResult> mappedResults = new List<RaycastResult>(0);
List<RaycastResult> normalResults = new List<RaycastResult>(0);
GameObject normalCanvasGO;
GameObject curvedCanvasGO;
void Awake ()
{
normalCanvasGO = GameObject.FindGameObjectWithTag("FlatUI");
curvedCanvasGO = GameObject.FindGameObjectWithTag("CurvedUI");
originalScale = transform.localScale;
centerEye = GameObject.Find ("OVRCameraRig/TrackingSpace/CenterEyeAnchor").transform;
Assert.NotNull(centerEye);
if(normalCanvasGO != null)
normalRaycaster = normalCanvasGO.GetComponentInChildren<GraphicRaycaster>();
if(curvedCanvasGO != null)
mappedRaycaster = curvedCanvasGO.GetComponentInChildren<GraphicRaycaster>() as MappedGraphicRaycaster;
}
void LateUpdate ()
{
distance = CameraLeft.farClipPlane * 0.99f;
// use graphic raycaster to check for relevant ugui images first (item menu, etc.)
// LINK: http://answers.unity3d.com/questions/821590/unity-46-how-to-raycast-against-ugui-objects-from.html
PointerEventData pointer = new PointerEventData(EventSystem.current);
// var viewportCenter = new Vector3(.5f, .5f, CameraLeft.nearClipPlane);
// pointer.position = CameraLeft.ViewportToScreenPoint(viewportCenter);
//pointer.position = new Vector2(Screen.width/2, Screen.height/2);
//pointer.delta = Vector2.zero;
var viewportCenter = CameraLeft.WorldToScreenPoint(transform.position);
pointer.position = CameraLeft.ViewportToScreenPoint(viewportCenter);
normalResults.Clear();
mappedResults.Clear();
GameObject newTarget = null;
string extraContext;
if(normalRaycaster != null)
normalRaycaster.Raycast(pointer, normalResults);
if(mappedRaycaster != null)
{
mappedRaycaster.Raycast(pointer, mappedResults);
}
if(mappedResults.Count > 0)
{
print ("HERE!");
TargetState = ReticleTargetState.UGUICurved; // mapped (i.e. curved)
extraContext = string.Format("graphic (mapped) raycast hit (count: {0})", mappedResults.Count);
distance = mappedResults[0].distance;
newTarget = mappedResults[0].gameObject;
}
else if(normalResults != null && normalResults.Count > 0)
{
TargetState = ReticleTargetState.UGUIFlat; // normal
extraContext = string.Format("graphic raycast hit (count: {0})", normalResults.Count);
distance = normalResults[0].distance;
newTarget = normalResults[0].gameObject;
}
else
{
// do a physics raycast against the world geometry
FocusRay.origin = centerEye.position;
FocusRay.direction = centerEye.forward;
if(Physics.Raycast(FocusRay, out FocusHitPoint))
{
TargetState = ReticleTargetState.World;
extraContext = "world space hit";
distance = FocusHitPoint.distance;
newTarget = FocusHitPoint.transform.gameObject;
extraContext = "";
}
else
{
// no ui or world hit
TargetState = ReticleTargetState.None;
extraContext = "";
newTarget = null;
}
}
// throw message on target update
if(Target != newTarget)
{
string oldTargetS = Target == null ? "null" : Target.name;
string newTargetS = newTarget == null ? "null" : newTarget.name;
Debug.Log(string.Format("Reticle.Update: target change ({0} -> {1})\n{2}", oldTargetS, newTargetS, extraContext));
Target = newTarget;
updateBaseColor();
}
setColor();
// adjust position and rotation relative to eye
transform.position = centerEye.position + centerEye.forward * distance;
transform.LookAt(centerEye.position);
transform.Rotate(0f, 180f, 0f);
// adjust scale (scale up a little when very close, see ~minute 43:45 in LINK below)
// https://www.youtube.com/watch?v=LLKYbwNnKDg&list=UUTlgIRnl3viQb1zCJqFJwqw
// if(distance < 10)
// {
// distance *= 1 + 5 * Mathf.Exp (-distance);
// }
transform.localScale = originalScale * distance;
}
void updateBaseColor()
{
switch(TargetState)
{
case ReticleTargetState.UGUIFlat:
nextColor = Color.green;
break;
case ReticleTargetState.UGUICurved:
nextColor = Color.magenta;
break;
case ReticleTargetState.World:
nextColor = Color.blue;
break;
default:
nextColor = Color.red;
break;
}
}
void setColor()
{
// get r,g,b
float r = nextColor.r;
float g = nextColor.g;
float b = nextColor.b;
// get alpha
//float a = 1f;
float a = distance.Remap(0f, CameraLeft.farClipPlane, 0f, 1f);
renderer.material.SetColor("_Color", new Color(r,g,b,a));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment