using System.Collections.Generic; using UnityEngine; using Rokid.UXR.Config; using Rokid.UXR.Utility; namespace Rokid.UXR.Interaction { public class HandRender : AutoInjectBehaviour { /// /// Is handtype /// public HandType handType; /// /// Is draw handmesh /// public bool drawMesh = false; /// /// Is draw skeleton /// public bool drawSkeleton = true; /// /// Is draw skeleton line only drawSkeleton is true will draw /// public bool drawSkeletonLine = false; /// /// Is draw hand root axis /// public bool drawHandRootAxis = false; /// /// Is show debugtext /// public bool showDebugText = false; /// /// Bone node templates are used to generate bone /// public GameObject skeletonNode; /// /// The bone alignment template is used to create the lines before the bone /// public LineRenderer skeletonLine; /// /// Coordinate axis /// s [SerializeField, Autowrited("HandRootAxis")] private Transform handRootAxis; /// /// 手的渲染 /// [SerializeField, Autowrited("RKHandVisual")] private HandVisual handVisual; /// /// 调试模式的手 /// [SerializeField, Autowrited("HandGestureInEditor")] private Transform handVisualInEditor; private TextMesh debugText; private Dictionary skeletonLineDict = new Dictionary(); private Dictionary skeletonDict = new Dictionary(); private void Start() { GesEventInput.OnTrackedFailed += OnTrackedFailed; Init(); #if UNITY_EDITOR handVisualInEditor?.gameObject.SetActive(true); #else Destroy(handVisualInEditor?.gameObject); #endif } private void OnEnable() { GesEventInput.OnRenderHand += OnRenderHand; } private void OnDisable() { GesEventInput.OnRenderHand -= OnRenderHand; } private void Init() { if (Utils.IsAndroidPlatfrom() && drawMesh == false) { Destroy(handVisual.GetComponent()); handVisual.gameObject.SetActive(false); } if (UXRSDKConfig.Instance.URPActive) { handVisual.UpdateHandMeshMaterials(new Material[]{ Resources.Load("Materials/URP/RokidHand"), Resources.Load("Materials/URP/HandMesh_Finger") }); } if (showDebugText) { if (debugText == null) { debugText = new GameObject("_debug_text").AddComponent(); debugText.fontSize = 120; debugText.characterSize = 0.001f; debugText.transform.parent = transform; debugText.color = Color.green; debugText.transform.localScale = Vector3.one; debugText.transform.localRotation = Quaternion.Euler(0.0f, 0.0f, 0.0f); } debugText.gameObject.SetActive(false); } } private void OnDestroy() { GesEventInput.OnTrackedFailed -= OnTrackedFailed; } private void OnTrackedFailed(HandType handType) { if (handType == this.handType || handType == HandType.None) { if (drawHandRootAxis) handRootAxis.gameObject.SetActive(false); if (showDebugText) debugText.gameObject.SetActive(false); } } private void OnRenderHand(HandType handType, GestureBean bean) { if (handType == this.handType) { if (bean.skeletons != null && bean.skeletons.Length > 0) { if (drawSkeleton) DrawSkeleton(bean.skeletons, bean.skeletonsRot); if (drawHandRootAxis) { handRootAxis.gameObject.SetActive(true); handRootAxis.transform.SetPose(GesEventInput.Instance.GetHandPose(handType)); } } } } void DrawSkeleton(Vector3[] skeletons, Quaternion[] rotations) { if (skeletons.Length == 0 || drawSkeleton == false) { return; } //绘制骨骼点 for (int i = 0; i < skeletons.Length; i++) { GameObject go = null; SkeletonIndexFlag indexFlag = (SkeletonIndexFlag)i; if (skeletonDict.ContainsKey(indexFlag)) { go = skeletonDict[indexFlag]; } else { go = GameObject.Instantiate(skeletonNode); go.GetComponent().enabled = true; go.name = indexFlag.ToString(); go.transform.SetParent(transform); skeletonDict.Add(indexFlag, go); } go.gameObject.SetActive(true); go.transform.position = skeletons[i]; go.transform.rotation = rotations[i]; } if (drawSkeletonLine) { for (int i = 0; i < 5; i++) { LineRenderer skeletonLine = null; string lineName = handType == HandType.RightHand ? "right_skeletonLine" + i : "left_skeletonLine" + i; if (skeletonLineDict.ContainsKey(lineName)) { skeletonLine = skeletonLineDict[lineName]; } else { skeletonLine = GameObject.Instantiate(this.skeletonLine); skeletonLine.name = lineName; skeletonLineDict.Add(lineName, skeletonLine); } skeletonLine.gameObject.SetActive(true); skeletonLine.transform.SetParent(transform); for (int j = 0; j < 5; j++) { int index = j == 0 ? 0 : i * 4 + j; skeletonLine.SetPosition(j, skeletons[index]); } } } } private void Update() { if (showDebugText) { debugText.gameObject.SetActive(true); debugText.transform.SetPose(GesEventInput.Instance.GetHandPose(handType)); if (handType == HandType.RightHand) { debugText.transform.position += new Vector3(-0.05f, 0.1f, 0.0f); debugText.alignment = TextAlignment.Right; debugText.anchor = TextAnchor.UpperRight; } else { debugText.transform.position += new Vector3(0.05f, 0.1f, 0.0f); debugText.alignment = TextAlignment.Left; debugText.anchor = TextAnchor.UpperLeft; } debugText.text = string.Format( "WristPos: {0}\n" + "GestureType: {1}\n" + "HandType: {2}\n" + "HandOrientation: {3}\n" + "HandRotation: {4}\n", GesEventInput.Instance.GetSkeletonPose(SkeletonIndexFlag.WRIST, handType).position.ToString("0.000"), GesEventInput.Instance.GetGesture(handType).gesType.ToString(), handType.ToString(), GesEventInput.Instance.GetGesture(handType).handOrientation == 0 ? HandOrientation.Palm : HandOrientation.Back, GesEventInput.Instance.GetHandPose(handType).rotation.eulerAngles.ToString("0.000")); } else { if (debugText != null) { Destroy(debugText.gameObject); } } } } }