//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== using UnityEngine; using System.Collections.Generic; #if ZED_URP using UnityEngine.Rendering.Universal; #endif /// /// Contols the ZEDSkeletonTracking . Links the SDK to Unity /// [DisallowMultipleComponent] public class ZEDSkeletonTrackingViewer : MonoBehaviour { /// /// The scene's ZEDManager. /// If you want to visualize detections from multiple ZEDs at once you will need multiple ZED3DSkeletonVisualizer commponents in the scene. /// [Tooltip("The scene's ZEDManager.\r\n" + "If you want to visualize detections from multiple ZEDs at once you will need multiple ZED3DSkeletonVisualizer commponents in the scene. ")] public ZEDManager zedManager; [Tooltip("The camera view to display ZED images")] public Camera viewCamera; /// /// Activate skeleton tracking when play mode is on and ZED ready /// [Header("Game Control")] public bool startObjectDetectionAutomatically = true; /// /// Vizualisation mode. Use a 3D model or only display the skeleton /// [Header("Vizualisation Mode")] /// /// Display 3D avatar. If set to false, only display bones and joint /// [Tooltip("Display 3D avatar. If set to false, only display bones and joint")] public bool useAvatar = true; [Space(5)] [Header("State Filters")] [Tooltip("Display objects that are actively being tracked by object tracking, where valid positions are known. ")] public bool showON = true; /// /// Display objects that were actively being tracked by object tracking, but that were lost very recently. /// [Tooltip("Display objects that were actively being tracked by object tracking, but that were lost very recently.")] public bool showSEARCHING = false; /// /// Display objects that are visible but not actively being tracked by object tracking (usually because object tracking is disabled in ZEDManager). /// [Tooltip("Display objects that are visible but not actively being tracked by object tracking (usually because object tracking is disabled in ZEDManager).")] public bool showOFF = false; [Header("Avatar Control")] /// /// Avatar game object /// public GameObject Avatar; [Space(5)] [Range(-2.0f, 2.0f)] public float heightOffset = 0.0f; public Dictionary avatarControlList; /// /// Start this instance. /// private void Start() { QualitySettings.vSyncCount = 1; // Activate vsync avatarControlList = new Dictionary (); if (!zedManager) { zedManager = FindObjectOfType(); } if (zedManager) { #if ZED_URP UniversalAdditionalCameraData urpCamData = zedManager.GetLeftCamera().GetComponent(); urpCamData.renderPostProcessing = true; urpCamData.renderShadows = false; #endif zedManager.OnZEDReady += OnZEDReady; zedManager.OnObjectDetection += updateSkeletonData; } if (zedManager.objectDetectionModel == sl.DETECTION_MODEL.MULTI_CLASS_BOX || zedManager.objectDetectionModel == sl.DETECTION_MODEL.MULTI_CLASS_BOX_ACCURATE || zedManager.objectDetectionModel == sl.DETECTION_MODEL.MULTI_CLASS_BOX_MEDIUM ) { Debug.LogWarning("MULTI_CLASS_BOX model can't be used for skeleton tracking, please use either HUMAN_BODY_FAST or HUMAN_BODY_ACCURATE"); } if (zedManager.objectDetectionBodyFormat == sl.BODY_FORMAT.POSE_18) { Debug.LogWarning(" BODY_FORMAT must be set to POSE_34 to animate 3D Avatars !"); return; } } private void OnZEDReady() { if (startObjectDetectionAutomatically && !zedManager.IsObjectDetectionRunning) { zedManager.StartObjectDetection(); } } private void OnDestroy() { if (zedManager) { zedManager.OnObjectDetection -= updateSkeletonData; zedManager.OnZEDReady -= OnZEDReady; } } /// /// Updates the skeleton data from ZEDCamera call and send it to Skeleton Handler script. /// private void updateSkeletonData(DetectionFrame dframe) { List remainingKeyList = new List(avatarControlList.Keys); List newobjects = dframe.GetFilteredObjectList(showON, showSEARCHING, showOFF); foreach (DetectedObject dobj in newobjects) { int person_id = dobj.rawObjectData.id; //Avatar controller already exist --> update position if (avatarControlList.ContainsKey(person_id)) { SkeletonHandler handler = avatarControlList[person_id]; UpdateAvatarControl(handler,dobj.rawObjectData, useAvatar); // remove keys from list remainingKeyList.Remove(person_id); } else { SkeletonHandler handler = ScriptableObject.CreateInstance(); Vector3 spawnPosition = zedManager.GetZedRootTansform().TransformPoint(dobj.rawObjectData.rootWorldPosition); handler.Create(Avatar); handler.initSkeleton(person_id); avatarControlList.Add(person_id, handler); UpdateAvatarControl(handler, dobj.rawObjectData, useAvatar); } } foreach (int index in remainingKeyList) { SkeletonHandler handler = avatarControlList[index]; handler.Destroy(); avatarControlList.Remove(index); } } public void Update() { if (Input.GetKeyDown(KeyCode.Space)) { useAvatar = !useAvatar; if (useAvatar) { if (zedManager.objectDetectionBodyFitting) Debug.Log(" Switch to Avatar mode"); } else Debug.Log(" Switch to Skeleton mode"); } if (Input.GetKeyDown(KeyCode.DownArrow)) { heightOffset -= 0.02f; } else if (Input.GetKeyDown(KeyCode.UpArrow)) { heightOffset += 0.02f; } if (useAvatar) { foreach (var skelet in avatarControlList) { skelet.Value.Move(); } } UpdateViewCameraPosition(); } /// /// Function to update avatar control with data from ZED SDK. /// /// Handler. /// P. private void UpdateAvatarControl(SkeletonHandler handler, sl.ObjectDataSDK data, bool useAvatar) { Vector3[] worldJointsPos = new Vector3[34]; Quaternion[] worldJointsRot = new Quaternion[34]; for (int i = 0; i < 34; i++) { worldJointsPos[i] = zedManager.GetZedRootTansform().TransformPoint(data.skeletonJointPosition[i]); worldJointsRot[i] = data.localOrientationPerJoint[i].normalized; } handler.setControlWithJointPosition(worldJointsPos, worldJointsRot, zedManager.GetZedRootTansform().rotation * data.globalRootOrientation, useAvatar); handler.SetHeightOffset(heightOffset); } void UpdateViewCameraPosition() { viewCamera.transform.position = zedManager.transform.localPosition; viewCamera.transform.rotation = zedManager.transform.localRotation; } }