164 lines
5.2 KiB
C#
164 lines
5.2 KiB
C#
// Copyright 2017 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 System;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
|
|
/// Visualizes a reticle using a Quad.
|
|
/// Provides tuning options to control how the reticle scales and rotates based
|
|
/// on distance from the camera.
|
|
[RequireComponent(typeof(MeshRenderer))]
|
|
[RequireComponent(typeof(MeshFilter))]
|
|
[HelpURL("https://developers.google.com/vr/unity/reference/class/GvrControllerReticleVisual")]
|
|
public class GvrControllerReticleVisual : MonoBehaviour {
|
|
[Serializable]
|
|
public struct FaceCameraData {
|
|
public bool alongXAxis;
|
|
public bool alongYAxis;
|
|
public bool alongZAxis;
|
|
|
|
public bool IsAnyAxisOff {
|
|
get {
|
|
return !alongXAxis || !alongYAxis || !alongZAxis;
|
|
}
|
|
}
|
|
|
|
public FaceCameraData(bool startEnabled) {
|
|
alongXAxis = startEnabled;
|
|
alongYAxis = startEnabled;
|
|
alongZAxis = startEnabled;
|
|
}
|
|
}
|
|
|
|
/// If set to false, the scale is simply set to the sizeMeters value.
|
|
[Tooltip("Determines if the size of the reticle is based on the distance from the camera.")]
|
|
public bool isSizeBasedOnCameraDistance = true;
|
|
|
|
/// The reticle will be scaled based on the size of the mesh so that it's size matches this size.
|
|
[Tooltip("Final size of the reticle in meters when it is 1 meter from the camera.")]
|
|
public float sizeMeters = 0.1f;
|
|
|
|
[Tooltip("Determines if the reticle will always face the camera and along what axes.")]
|
|
public FaceCameraData doesReticleFaceCamera = new FaceCameraData(true);
|
|
|
|
/// Sorting order to use for the reticle's renderer.
|
|
/// Range values come from https://docs.unity3d.com/ScriptReference/Renderer-sortingOrder.html.
|
|
[Range(-32767, 32767)]
|
|
public int sortingOrder = 0;
|
|
|
|
/// The size of the reticle's mesh in meters.
|
|
public float ReticleMeshSizeMeters { get; private set; }
|
|
|
|
/// The ratio of the reticleMeshSizeMeters to 1 meter.
|
|
/// If reticleMeshSizeMeters is 10, then reticleMeshSizeRatio is 0.1.
|
|
public float ReticleMeshSizeRatio { get; private set; }
|
|
|
|
protected MeshRenderer meshRenderer;
|
|
protected MeshFilter meshFilter;
|
|
|
|
private Vector3 preRenderLocalScale;
|
|
private Quaternion preRenderLocalRotation;
|
|
|
|
public void RefreshMesh() {
|
|
ReticleMeshSizeMeters = 1.0f;
|
|
ReticleMeshSizeRatio = 1.0f;
|
|
|
|
if (meshFilter != null && meshFilter.mesh != null) {
|
|
ReticleMeshSizeMeters = meshFilter.mesh.bounds.size.x;
|
|
if (ReticleMeshSizeMeters != 0.0f) {
|
|
ReticleMeshSizeRatio = 1.0f / ReticleMeshSizeMeters;
|
|
}
|
|
}
|
|
|
|
if (meshRenderer != null) {
|
|
meshRenderer.sortingOrder = sortingOrder;
|
|
}
|
|
}
|
|
|
|
protected virtual void Awake() {
|
|
meshRenderer = GetComponent<MeshRenderer>();
|
|
meshFilter = GetComponent<MeshFilter>();
|
|
}
|
|
|
|
protected virtual void OnEnable() {
|
|
RefreshMesh();
|
|
}
|
|
|
|
protected virtual void OnWillRenderObject() {
|
|
preRenderLocalScale = transform.localScale;
|
|
preRenderLocalRotation = transform.localRotation;
|
|
|
|
Camera camera = Camera.current;
|
|
UpdateReticleSize(camera);
|
|
UpdateReticleOrientation(camera);
|
|
}
|
|
|
|
protected virtual void OnRenderObject() {
|
|
// It is possible for paired calls to OnWillRenderObject/OnRenderObject to be nested if
|
|
// Camera.Render is explicitly called for any special effects. To avoid the reticle being
|
|
// rotated/scaled incorrectly in that case, the reticle is reset to it's pre-OnWillRenderObject
|
|
// after a render has finished.
|
|
transform.localScale = preRenderLocalScale;
|
|
transform.localRotation = preRenderLocalRotation;
|
|
}
|
|
|
|
protected virtual void UpdateReticleSize(Camera camera) {
|
|
if (camera == null) {
|
|
return;
|
|
}
|
|
|
|
float scale = sizeMeters;
|
|
|
|
if (isSizeBasedOnCameraDistance) {
|
|
float reticleDistanceFromCamera = (transform.position - camera.transform.position).magnitude;
|
|
scale *= ReticleMeshSizeRatio * reticleDistanceFromCamera;
|
|
}
|
|
|
|
transform.localScale = new Vector3(scale, scale, scale);
|
|
}
|
|
|
|
protected virtual void UpdateReticleOrientation(Camera camera) {
|
|
if (camera == null) {
|
|
return;
|
|
}
|
|
|
|
Vector3 direction = transform.position - camera.transform.position;
|
|
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
|
|
|
|
if (doesReticleFaceCamera.IsAnyAxisOff) {
|
|
Vector3 euler = transform.localEulerAngles;
|
|
if (!doesReticleFaceCamera.alongXAxis) {
|
|
euler.x = 0.0f;
|
|
}
|
|
|
|
if (!doesReticleFaceCamera.alongYAxis) {
|
|
euler.y = 0.0f;
|
|
}
|
|
|
|
if (!doesReticleFaceCamera.alongZAxis) {
|
|
euler.z = 0.0f;
|
|
}
|
|
|
|
transform.localEulerAngles = euler;
|
|
}
|
|
}
|
|
|
|
protected virtual void OnValidate() {
|
|
if (Application.isPlaying && isActiveAndEnabled) {
|
|
RefreshMesh();
|
|
}
|
|
}
|
|
}
|