666 lines
26 KiB
C#
666 lines
26 KiB
C#
|
//======= Copyright (c) Stereolabs Corporation, All rights reserved. ===============
|
|||
|
|
|||
|
using UnityEngine;
|
|||
|
using System.Collections.Generic;
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
using UnityEditor;
|
|||
|
#endif
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Manages the ZED SDK's plane detection feature.
|
|||
|
/// This allows you to check a point on the screen to see if it's part of a real-life plane, such as
|
|||
|
/// a floor, wall, tabletop, etc. If it is, this component will create a GameObject representing that
|
|||
|
/// plane with its proper world position and boundaries.
|
|||
|
/// If this component exists in your scene, you can also click the screen to detect planes there.
|
|||
|
/// By default it adds a MeshCollider, so that physics objects can interact with it properly, and a
|
|||
|
/// MeshRenderer, so that it's visible.
|
|||
|
/// Planes are rendered with ZEDPlaneRenderer, so they aren't occluded, thereby avoiding Z-fighting with the
|
|||
|
/// surfaces they represent.
|
|||
|
/// </summary>
|
|||
|
[DisallowMultipleComponent]
|
|||
|
public class ZEDPlaneDetectionManager : MonoBehaviour
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// GameObject all planes are parented to. Created at runtime, called '[ZED Planes]' in Hierarchy.
|
|||
|
/// </summary>
|
|||
|
private GameObject holder;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Whether a floor plane has been detected during runtime.
|
|||
|
/// This won't happen unless DetectFloorPlane() is called.
|
|||
|
/// </summary>
|
|||
|
private bool hasDetectedFloor = false;
|
|||
|
/// <summary>
|
|||
|
/// Public accessor for hasDetectedFloor, which is whether a floor plane has been detected during runtime.
|
|||
|
/// </summary>
|
|||
|
public bool HasDetectedFloor
|
|||
|
{
|
|||
|
get { return hasDetectedFloor; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// GameObject holding floorPlane, which representing the floor plane, if one has been detected.
|
|||
|
/// </summary>
|
|||
|
private GameObject floorPlaneGO;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// ZEDPlaneGameObject representing the floor plane, if one has been detected.
|
|||
|
/// This reference is used to clear the existing floor plane if a new one is detected.
|
|||
|
/// </summary>
|
|||
|
private ZEDPlaneGameObject floorPlane = null;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Returns the ZEDPlaneGameObject representing the floor, if the floor has been detected.
|
|||
|
/// </summary>
|
|||
|
public ZEDPlaneGameObject getFloorPlane
|
|||
|
{
|
|||
|
get { return floorPlane; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// How many hit planes have been detected. Used to assign the index of hitPlaneList
|
|||
|
/// to the ZEDPlaneGameObject's themselves, and to name their GameObjects.
|
|||
|
/// </summary>
|
|||
|
private int planeHitCount = 0;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// All the hit planes that have been detected using DetectPlaneAtHit().
|
|||
|
/// </summary>
|
|||
|
public List<ZEDPlaneGameObject> hitPlaneList = null;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Buffer for holding a new plane's vertex data from the SDK.
|
|||
|
/// </summary>
|
|||
|
private Vector3[] planeMeshVertices;
|
|||
|
/// <summary>
|
|||
|
/// Buffer for holding a new plane's triangle data from the SDK.
|
|||
|
/// </summary>
|
|||
|
private int[] planeMeshTriangles;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Whether we're displaying the planes in the Scene view using ZEDPlaneRenderer. Usually the same as isVisibleInSceneOption.
|
|||
|
/// </summary>
|
|||
|
public static bool isSceneDisplay = true;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Whether we're displaying the planes in the Game view using ZEDPlaneRenderer. Usually the same as isVisibleInGameOption.
|
|||
|
/// Used by ZEDRenderingPlane to know if it should draw the meshes in its OnRenderImage() method.
|
|||
|
/// </summary>
|
|||
|
public static bool isGameDisplay = false;
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Whether the planes can collide with virtual objects (with colliders). Changing this enables/disables
|
|||
|
/// mesh colliders on all new and existing planes.
|
|||
|
/// </summary>
|
|||
|
public bool planesHavePhysics
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return addPhysicsOption;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (addPhysicsOption != value)
|
|||
|
{
|
|||
|
willUpdatePhysics = true;
|
|||
|
addPhysicsOption = value;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// Whether the planes can collide with virtual objects (with colliders).
|
|||
|
/// To update publicly or at runtime, use planesHavePhysics instead.
|
|||
|
/// </summary>
|
|||
|
[SerializeField]
|
|||
|
private bool addPhysicsOption = true;
|
|||
|
/// <summary>
|
|||
|
/// If true, existing planes will have their colliders updated
|
|||
|
/// based on addPhhysicsOption in the next Update() step.
|
|||
|
/// </summary>
|
|||
|
private bool willUpdatePhysics = false;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Whether the planes are drawn. Changing this setting enables/disables the plane's MeshRenderers.
|
|||
|
/// Note that if disabled, planes will not be drawn in the Game view regardless of the planesVisibleInGame setting.
|
|||
|
/// </summary>
|
|||
|
public bool planesVisibleInScene
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return isVisibleInSceneOption;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (value != isVisibleInSceneOption)
|
|||
|
{
|
|||
|
|
|||
|
isVisibleInSceneOption = value;
|
|||
|
willUpdateSceneVisibility = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// Whether the planes are drawn.
|
|||
|
/// To update publicly or at runtime, use planesVisibleInScene instead.
|
|||
|
/// </summary>
|
|||
|
[SerializeField]
|
|||
|
private bool isVisibleInSceneOption = true;
|
|||
|
/// <summary>
|
|||
|
/// If true, existing planes will have their visibility updated
|
|||
|
/// based on isVisibleInSceneOption in the next Update() step.
|
|||
|
/// </summary>
|
|||
|
private bool willUpdateSceneVisibility = true;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build.
|
|||
|
/// </summary>
|
|||
|
public bool planesVisibleInGame
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return isVisibleInGameOption;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (value != isVisibleInGameOption)
|
|||
|
{
|
|||
|
isVisibleInGameOption = value;
|
|||
|
willUpdateGameVisibility = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build.
|
|||
|
/// To update publicly or at runtime, use planesVisibleInGame instead.
|
|||
|
/// </summary>
|
|||
|
[SerializeField]
|
|||
|
private bool isVisibleInGameOption = true;
|
|||
|
/// <summary>
|
|||
|
/// If true, existing planes will have their in-game visibility updated
|
|||
|
/// based on isVisibleInGameOption in the next Update() step.
|
|||
|
/// </summary>
|
|||
|
private bool willUpdateGameVisibility = true;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Overrides the default wireframe material used to draw planes in the Scene and Game view.
|
|||
|
/// Leave this setting to null to draw the default wireframes.
|
|||
|
/// </summary>
|
|||
|
public Material overrideMaterial = null; //If null, shows wireframe. Otherwise, displays your custom material.
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// How high the player's head is from the floor. Filled in when DetectFloorPlane() is called.
|
|||
|
/// </summary>
|
|||
|
private float estimatedPlayerHeight = 0.0f;
|
|||
|
/// <summary>
|
|||
|
/// Public accessor for estimatedPlayerHeight, which is how high the player's head was when DetectFloorPlane() was last called.
|
|||
|
/// </summary>
|
|||
|
public float GetEstimatedPlayerHeight
|
|||
|
{
|
|||
|
get { return estimatedPlayerHeight; }
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Assign references, create the holder gameobject, and other misc. initialization.
|
|||
|
/// </summary>
|
|||
|
private void Start()
|
|||
|
{
|
|||
|
//Create a holder for all the planes
|
|||
|
holder = new GameObject();
|
|||
|
holder.name = "[ZED Planes]";
|
|||
|
holder.transform.parent = this.transform;
|
|||
|
holder.transform.position = Vector3.zero;
|
|||
|
holder.transform.rotation = Quaternion.identity;
|
|||
|
StaticBatchingUtility.Combine(holder);
|
|||
|
|
|||
|
//initialize Vertices/Triangles with enough length
|
|||
|
planeMeshVertices = new Vector3[65000];
|
|||
|
planeMeshTriangles = new int[65000];
|
|||
|
|
|||
|
//floorPlaneGO = holder.AddComponent<ZEDPlaneGameObject> ();
|
|||
|
hitPlaneList = new List<ZEDPlaneGameObject>();
|
|||
|
}
|
|||
|
|
|||
|
public void OnDisable()
|
|||
|
{
|
|||
|
foreach (Transform child in holder.transform)
|
|||
|
{
|
|||
|
Destroy(child.gameObject);
|
|||
|
|
|||
|
Destroy(holder);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Transforms the plane mesh from Camera frame to local frame, where each vertex is relative to the plane's center.
|
|||
|
/// Used because plane data from the ZED SDK is relative to the camera, not the world.
|
|||
|
/// </summary>
|
|||
|
/// <param name="camera">Camera transform.</param>
|
|||
|
/// <param name="srcVertices">Source vertices (in camera space).</param>
|
|||
|
/// <param name="srcTriangles">Source triangles (in camera space).</param>
|
|||
|
/// <param name="dstVertices">Dst vertices (in world space).</param>
|
|||
|
/// <param name="dstTriangles">Dst triangles (in world space).</param>
|
|||
|
/// <param name="numVertices">Number of vertices.</param>
|
|||
|
/// <param name="numTriangles">Number of triangles.</param>
|
|||
|
private void TransformCameraToLocalMesh(Transform camera, Vector3[] srcVertices, int[] srcTriangles, Vector3[] dstVertices, int[] dstTriangles, int numVertices, int numTriangles, Vector3 centerpos)
|
|||
|
{
|
|||
|
if (numVertices == 0 || numTriangles == 0)
|
|||
|
return; //Plane is empty.
|
|||
|
|
|||
|
System.Array.Copy(srcVertices, dstVertices, numVertices);
|
|||
|
System.Buffer.BlockCopy(srcTriangles, 0, dstTriangles, 0, numTriangles * sizeof(int));
|
|||
|
|
|||
|
for (int i = 0; i < numVertices; i++)
|
|||
|
{
|
|||
|
dstVertices[i] -= centerpos;
|
|||
|
dstVertices[i] = camera.transform.rotation * dstVertices[i];
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Detects the floor plane. Replaces the current floor plane, if there is one, unlike DetectPlaneAtHit().
|
|||
|
/// If a floor is detected, also assigns the user's height from the floor to estimatedPlayerHeight.
|
|||
|
/// <para>Uses the first available ZEDManager in the scene.</para>
|
|||
|
/// </summary>
|
|||
|
/// <returns><c>true</c>, if floor plane was detected, <c>false</c> otherwise.</returns>
|
|||
|
public bool DetectFloorPlane(bool auto)
|
|||
|
{
|
|||
|
//Find the first available ZEDManager.
|
|||
|
List<ZEDManager> managers = ZEDManager.GetInstances();
|
|||
|
if (managers.Count == 0) return false; //No ZEDManager to use.
|
|||
|
else return DetectFloorPlane(managers[0], auto);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Detects the floor plane. Replaces the current floor plane, if there is one, unlike DetectPlaneAtHit().
|
|||
|
/// If a floor is detected, also assigns the user's height from the floor to estimatedPlayerHeight.
|
|||
|
/// <para>Note that this can't be called the first frame the ZED is ready. Use a coroutine to wait one frame,
|
|||
|
/// or until ZEDManager.isZEDReady is true.</para>
|
|||
|
/// </summary>
|
|||
|
/// <returns><c>true</c>, if floor plane was detected, <c>false</c> otherwise.</returns>
|
|||
|
public bool DetectFloorPlane(ZEDManager manager, bool auto)
|
|||
|
{
|
|||
|
if (!manager.IsZEDReady)
|
|||
|
return false; //Do nothing if the ZED isn't finished initializing.
|
|||
|
|
|||
|
sl.ZEDCamera zedcam = manager.zedCamera;
|
|||
|
Camera cam = manager.GetMainCamera();
|
|||
|
|
|||
|
ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData();
|
|||
|
if (zedcam.findFloorPlane(ref plane, out estimatedPlayerHeight, Quaternion.identity, Vector3.zero) == sl.ERROR_CODE.SUCCESS) //We found a plane.
|
|||
|
{
|
|||
|
int numVertices, numTriangles = 0;
|
|||
|
zedcam.convertFloorPlaneToMesh(planeMeshVertices, planeMeshTriangles, out numVertices, out numTriangles);
|
|||
|
if (numVertices > 0 && numTriangles > 0)
|
|||
|
{
|
|||
|
Vector3[] worldPlaneVertices = new Vector3[numVertices];
|
|||
|
int[] worldPlaneTriangles = new int[numTriangles];
|
|||
|
TransformCameraToLocalMesh(cam.transform, planeMeshVertices, planeMeshTriangles, worldPlaneVertices, worldPlaneTriangles, numVertices, numTriangles, plane.PlaneCenter);
|
|||
|
|
|||
|
hasDetectedFloor = true;
|
|||
|
|
|||
|
if (!floorPlaneGO)
|
|||
|
{ //Make the GameObject.
|
|||
|
floorPlaneGO = new GameObject("Floor Plane");
|
|||
|
floorPlaneGO.transform.SetParent(holder.transform);
|
|||
|
}
|
|||
|
|
|||
|
if (!floorPlaneGO) //Make the GameObject.
|
|||
|
{
|
|||
|
floorPlaneGO = new GameObject("Floor Plane");
|
|||
|
floorPlaneGO.transform.SetParent(holder.transform);
|
|||
|
}
|
|||
|
|
|||
|
//Move the GameObject to the center of the plane. Note that the plane data's center is relative to the camera.
|
|||
|
floorPlaneGO.transform.position = cam.transform.position; //Add the camera's world position
|
|||
|
floorPlaneGO.transform.position += cam.transform.rotation * plane.PlaneCenter; //Add the center of the plane
|
|||
|
|
|||
|
if (!floorPlane) //Add a new ZEDPlaneGameObject to the floor plane if it doesn't already exist.
|
|||
|
{
|
|||
|
floorPlane = floorPlaneGO.AddComponent<ZEDPlaneGameObject>();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (!floorPlane.IsCreated) //Call ZEDPlaneGameObject.Create() on the floor ZEDPlaneGameObject if it hasn't yet been run.
|
|||
|
{
|
|||
|
if (overrideMaterial != null) floorPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, 0, overrideMaterial);
|
|||
|
else floorPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, 0);
|
|||
|
floorPlane.SetPhysics(addPhysicsOption);
|
|||
|
}
|
|||
|
else //Update the ZEDPlaneGameObject with the new plane's data.
|
|||
|
{
|
|||
|
floorPlane.UpdateFloorPlane(!auto, plane, worldPlaneVertices, worldPlaneTriangles, overrideMaterial);
|
|||
|
floorPlane.SetPhysics(addPhysicsOption);
|
|||
|
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Detects the plane around screen-space coordinates specified.
|
|||
|
/// <para>Uses the first available ZEDManager in the scene.</para>
|
|||
|
/// </summary>
|
|||
|
/// <returns><c>true</c>, if plane at hit was detected, <c>false</c> otherwise.</returns>
|
|||
|
/// <param name="screenPos">Position of the pixel in screen space (2D).</param>
|
|||
|
public bool DetectPlaneAtHit(Vector2 screenPos)
|
|||
|
{
|
|||
|
//Find the first available ZEDManager.
|
|||
|
List<ZEDManager> managers = ZEDManager.GetInstances();
|
|||
|
if (managers.Count == 0) return false; //No ZEDManager to use.
|
|||
|
else if (managers.Count > 1) //They're using multiple cameras but using the first available manager. Not ideal.
|
|||
|
{
|
|||
|
Debug.LogWarning("Using DetectPlaneAtHit without specifying a manager while multiple ZEDManagers are present. " +
|
|||
|
"This can cause planes to be calculated by the wrong camera. It's recommended to use the (ZEDManager, Vector2) overload.");
|
|||
|
}
|
|||
|
return DetectPlaneAtHit(managers[0], screenPos);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Detects the plane around screen-space coordinates specified.
|
|||
|
/// </summary>
|
|||
|
/// <returns><c>true</c>, if plane at hit was detected, <c>false</c> otherwise.</returns>
|
|||
|
/// <param name="screenPos">Position of the pixel in screen space (2D).</param>
|
|||
|
public bool DetectPlaneAtHit(ZEDManager manager, Vector2 screenPos)
|
|||
|
{
|
|||
|
if (!manager.IsZEDReady)
|
|||
|
return false; //Do nothing if the ZED isn't finished initializing.
|
|||
|
|
|||
|
sl.ZEDCamera zedcam = manager.zedCamera;
|
|||
|
Camera cam = manager.GetMainCamera();
|
|||
|
|
|||
|
ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData();
|
|||
|
if (zedcam.findPlaneAtHit(ref plane, screenPos) == sl.ERROR_CODE.SUCCESS) //We found a plane.
|
|||
|
{
|
|||
|
int numVertices, numTriangles = 0;
|
|||
|
zedcam.convertHitPlaneToMesh(planeMeshVertices, planeMeshTriangles, out numVertices, out numTriangles);
|
|||
|
if (numVertices > 0 && numTriangles > 0)
|
|||
|
{
|
|||
|
GameObject newhitGO = new GameObject(); //Make a new GameObject to hold the new plane.
|
|||
|
newhitGO.transform.SetParent(holder.transform);
|
|||
|
|
|||
|
Vector3[] worldPlaneVertices = new Vector3[numVertices];
|
|||
|
int[] worldPlaneTriangles = new int[numTriangles];
|
|||
|
TransformCameraToLocalMesh(cam.transform, planeMeshVertices, planeMeshTriangles, worldPlaneVertices, worldPlaneTriangles, numVertices, numTriangles, plane.PlaneCenter);
|
|||
|
|
|||
|
//Move the GameObject to the center of the plane. Note that the plane data's center is relative to the camera.
|
|||
|
newhitGO.transform.position = cam.transform.position; //Add the camera's world position
|
|||
|
newhitGO.transform.position += cam.transform.rotation * plane.PlaneCenter; //Add the center of the plane
|
|||
|
|
|||
|
ZEDPlaneGameObject hitPlane = newhitGO.AddComponent<ZEDPlaneGameObject>();
|
|||
|
|
|||
|
if (overrideMaterial != null) hitPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, planeHitCount + 1, overrideMaterial);
|
|||
|
else hitPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, planeHitCount + 1);
|
|||
|
|
|||
|
hitPlane.SetPhysics(addPhysicsOption);
|
|||
|
//hitPlane.SetVisible(isVisibleInSceneOption);
|
|||
|
hitPlaneList.Add(hitPlane);
|
|||
|
planeHitCount++;
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Check if the screen was clicked. If so, check for a plane where the click happened using DetectPlaneAtHit().
|
|||
|
/// </summary>
|
|||
|
void Update()
|
|||
|
{
|
|||
|
//Detect hits when you click on the screen.
|
|||
|
if (Input.GetMouseButtonDown(0))
|
|||
|
{
|
|||
|
Vector2 ScreenPosition = Input.mousePosition;
|
|||
|
|
|||
|
List<ZEDManager> managers = ZEDManager.GetInstances();
|
|||
|
if (managers.Count == 1) //There's only one ZEDManager, so use that one.
|
|||
|
DetectPlaneAtHit(managers[0], ScreenPosition);
|
|||
|
else if (managers.Count > 1)
|
|||
|
{
|
|||
|
//There are at least two ZEDManagers rendering. Find the one that's likely the last to render, so it's the one the user clicked on.
|
|||
|
float highestdepth = Mathf.NegativeInfinity;
|
|||
|
ZEDManager highestmanager = managers[0];
|
|||
|
foreach (ZEDManager manager in managers)
|
|||
|
{
|
|||
|
float depth = manager.GetMainCamera().depth;
|
|||
|
if (depth >= highestdepth)
|
|||
|
{
|
|||
|
highestdepth = depth;
|
|||
|
highestmanager = manager;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DetectPlaneAtHit(highestmanager, ScreenPosition);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//Update plane physics if needed.
|
|||
|
if (willUpdatePhysics)
|
|||
|
{
|
|||
|
if (floorPlane != null && floorPlane.IsCreated)
|
|||
|
{
|
|||
|
floorPlane.SetPhysics(addPhysicsOption);
|
|||
|
}
|
|||
|
if (hitPlaneList != null)
|
|||
|
{
|
|||
|
foreach (ZEDPlaneGameObject c in hitPlaneList)
|
|||
|
{
|
|||
|
if (c.IsCreated)
|
|||
|
c.SetPhysics(addPhysicsOption);
|
|||
|
}
|
|||
|
}
|
|||
|
willUpdatePhysics = false;
|
|||
|
}
|
|||
|
|
|||
|
//Update visibility if needed.
|
|||
|
if (willUpdateSceneVisibility)
|
|||
|
{
|
|||
|
/*if (floorPlane != null && floorPlane.IsCreated)
|
|||
|
{
|
|||
|
floorPlane.SetVisible(isVisibleInSceneOption);
|
|||
|
}
|
|||
|
if (hitPlaneList != null)
|
|||
|
{
|
|||
|
foreach (ZEDPlaneGameObject c in hitPlaneList)
|
|||
|
{
|
|||
|
c.SetVisible(isVisibleInSceneOption);
|
|||
|
}
|
|||
|
}*/
|
|||
|
SwitchSceneDisplay();
|
|||
|
willUpdateSceneVisibility = false;
|
|||
|
}
|
|||
|
|
|||
|
//Update in-game visibility if needed.
|
|||
|
if (willUpdateGameVisibility)
|
|||
|
{
|
|||
|
SwitchGameDisplay();
|
|||
|
willUpdateGameVisibility = false;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Switches the isGameDisplay setting, used to know if planes should be rendered to the Scene window.
|
|||
|
/// </summary>
|
|||
|
public void SwitchSceneDisplay()
|
|||
|
{
|
|||
|
isSceneDisplay = isVisibleInSceneOption;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Switches the isGameDisplay setting, used to know if planes should be rendered to the Game window.
|
|||
|
/// </summary>
|
|||
|
public void SwitchGameDisplay()
|
|||
|
{
|
|||
|
isGameDisplay = isVisibleInGameOption;
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
/// <summary>
|
|||
|
/// Called when the Inspector is visible or changes. Updates plane physics and visibility settings.
|
|||
|
/// </summary>
|
|||
|
void OnValidate()
|
|||
|
{
|
|||
|
if (floorPlane != null && floorPlane.IsCreated)
|
|||
|
{
|
|||
|
floorPlane.SetPhysics(addPhysicsOption);
|
|||
|
|
|||
|
//floorPlane.SetVisible(isVisibleInSceneOption);
|
|||
|
}
|
|||
|
|
|||
|
if (hitPlaneList != null)
|
|||
|
foreach (ZEDPlaneGameObject c in hitPlaneList)
|
|||
|
{
|
|||
|
if (c.IsCreated)
|
|||
|
c.SetPhysics(addPhysicsOption);
|
|||
|
|
|||
|
//c.SetVisible(isVisibleInSceneOption);
|
|||
|
}
|
|||
|
|
|||
|
SwitchSceneDisplay();
|
|||
|
SwitchGameDisplay();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
/// <summary>
|
|||
|
/// Custom Inspector editor for ZEDPlaneDetectionManager.
|
|||
|
/// Adds a button to detect the floor, and causes planes to get updated instantly when their visibility settings change.
|
|||
|
/// </summary>
|
|||
|
[CustomEditor(typeof(ZEDPlaneDetectionManager))]
|
|||
|
public class ZEDPlaneDetectionEditor : Editor
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// The ZEDPlaneDetectionManager component that this editor is displaying.
|
|||
|
/// </summary>
|
|||
|
private ZEDPlaneDetectionManager planeDetector;
|
|||
|
|
|||
|
// private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) };
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Serializable version of ZEDPlaneDetectionManager's addPhysicsOption property.
|
|||
|
/// </summary>
|
|||
|
private SerializedProperty addPhysicsOption;
|
|||
|
/// <summary>
|
|||
|
/// Serializable version of ZEDPlaneDetectionManager's isVisibleInSceneOption property.
|
|||
|
/// </summary>
|
|||
|
private SerializedProperty isVisibleInSceneOption;
|
|||
|
/// <summary>
|
|||
|
/// Serializable version of ZEDPlaneDetectionManager's isVisibleInGameOption property.
|
|||
|
/// </summary>
|
|||
|
private SerializedProperty isVisibleInGameOption;
|
|||
|
/// <summary>
|
|||
|
/// Serializable version of ZEDPlaneDetectionManager's overrideMaterialOption property.
|
|||
|
/// </summary>
|
|||
|
private SerializedProperty overrideMaterialOption;
|
|||
|
|
|||
|
|
|||
|
private ZEDPlaneDetectionManager Target
|
|||
|
{
|
|||
|
get { return (ZEDPlaneDetectionManager)target; }
|
|||
|
}
|
|||
|
|
|||
|
public void OnEnable()
|
|||
|
{
|
|||
|
//Assign the serialized properties to their appropriate properties.
|
|||
|
planeDetector = (ZEDPlaneDetectionManager)target;
|
|||
|
addPhysicsOption = serializedObject.FindProperty("addPhysicsOption");
|
|||
|
isVisibleInSceneOption = serializedObject.FindProperty("isVisibleInSceneOption");
|
|||
|
isVisibleInGameOption = serializedObject.FindProperty("isVisibleInGameOption");
|
|||
|
overrideMaterialOption = serializedObject.FindProperty("overrideMaterial");
|
|||
|
}
|
|||
|
|
|||
|
public override void OnInspectorGUI()
|
|||
|
{
|
|||
|
//bool cameraIsReady = planeDetector.Manager != null ? planeDetector.Manager.zedCamera.IsCameraReady : false;
|
|||
|
|
|||
|
serializedObject.Update();
|
|||
|
|
|||
|
GUILayout.Space(20);
|
|||
|
EditorGUILayout.BeginHorizontal();
|
|||
|
GUILayout.Label("Detection Parameters", EditorStyles.boldLabel);
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
EditorGUILayout.EndHorizontal();
|
|||
|
|
|||
|
//GUI.enabled = cameraIsReady;
|
|||
|
EditorGUILayout.BeginHorizontal();
|
|||
|
GUIContent floordetectionlabel = new GUIContent("Single-shot Floor Detection", "Attempt to detect a floor plane in the current view.");
|
|||
|
GUILayout.Label(floordetectionlabel); GUILayout.Space(20);
|
|||
|
|
|||
|
GUIContent floordetectbuttonlabel = new GUIContent("Detect", "Attempt to detect a floor plane in the current view.");
|
|||
|
if (GUILayout.Button(floordetectbuttonlabel))
|
|||
|
{
|
|||
|
planeDetector.DetectFloorPlane(false);
|
|||
|
}
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
EditorGUILayout.EndHorizontal();
|
|||
|
|
|||
|
GUI.enabled = true;
|
|||
|
GUILayout.Space(20);
|
|||
|
EditorGUILayout.BeginHorizontal();
|
|||
|
GUILayout.Label("Visualization", EditorStyles.boldLabel);
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
EditorGUILayout.EndHorizontal();
|
|||
|
|
|||
|
GUIContent visiblescenelabel = new GUIContent("Visible in Scene", "Whether the planes are drawn in Unity's Scene view.");
|
|||
|
GUIContent visiblegamelabel = new GUIContent("Visible in Game", "Whether the planes are drawn in Unity's Game view.");
|
|||
|
isVisibleInSceneOption.boolValue = EditorGUILayout.Toggle(visiblescenelabel, isVisibleInSceneOption.boolValue);
|
|||
|
|
|||
|
#if !UNITY_2018_1_OR_NEWER
|
|||
|
if (!isVisibleInSceneOption.boolValue)
|
|||
|
{
|
|||
|
//Older Unity versions have a bug that will spam errors if Visible In Scene is disabled. Warn the user.
|
|||
|
GUIStyle warningmessagestyle = new GUIStyle(EditorStyles.label);
|
|||
|
warningmessagestyle.normal.textColor = Color.gray;
|
|||
|
warningmessagestyle.wordWrap = true;
|
|||
|
warningmessagestyle.fontSize = 9;
|
|||
|
|
|||
|
string warningtext = "Warning: Disabling Visible in Scene causes Unity versions 2017 and lower to spam error messages. This is due to a Unity bug and does not effect the scene.";
|
|||
|
Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(warningtext, ""), warningmessagestyle);
|
|||
|
EditorGUI.LabelField(labelrect, warningtext, warningmessagestyle);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
isVisibleInGameOption.boolValue = EditorGUILayout.Toggle(visiblegamelabel, isVisibleInGameOption.boolValue);
|
|||
|
|
|||
|
GUIContent overridematlabel = new GUIContent("Override Material: ", "Material applied to all planes if visible. If left empty, default materials will be applied depending on the plane type.");
|
|||
|
planeDetector.overrideMaterial = (Material)EditorGUILayout.ObjectField(overridematlabel, planeDetector.overrideMaterial, typeof(Material), false);
|
|||
|
|
|||
|
|
|||
|
planeDetector.SwitchGameDisplay();
|
|||
|
GUILayout.Space(20);
|
|||
|
GUI.enabled = true;
|
|||
|
EditorGUILayout.BeginHorizontal();
|
|||
|
GUILayout.Label("Physics", EditorStyles.boldLabel);
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
EditorGUILayout.EndHorizontal();
|
|||
|
|
|||
|
GUIContent physicslabel = new GUIContent("Collisions", "Whether the planes can be collided with using physics.");
|
|||
|
addPhysicsOption.boolValue = EditorGUILayout.Toggle(physicslabel, addPhysicsOption.boolValue);
|
|||
|
|
|||
|
|
|||
|
serializedObject.ApplyModifiedProperties(); //Applies all changes to serializedproperties to the actual properties they're connected to.
|
|||
|
|
|||
|
//if (!cameraIsReady) Repaint();
|
|||
|
Repaint();
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#endif
|