Unity+Azure Kinect开发:衣物与用户运动方向相反问题求助
问题:Azure Kinect骨骼追踪映射Unity衣物模型时方向相反
我在开发Unity项目,使用Azure Kinect SDK追踪用户肢体动作并映射到衣物模型,但衣物运动方向与用户实际方向完全相反。尝试过调整位置计算逻辑、添加旋转偏移,问题仍未解决。当前通过Spine Chest和Pelvis关节数据更新上下衣物的位置与旋转,相关代码如下:
using Microsoft.Azure.Kinect.Sensor; using Microsoft.Azure.Kinect.BodyTracking; using UnityEngine; using UnityEngine.UI; public class KinectManager2 : MonoBehaviour { public GameObject topClothingObject; public GameObject bottomClothingObject; private Device kinectDevice; private Tracker bodyTracker; private Texture2D colorTexture; public RawImage backgroundImage; private Vector3 initialPelvisPosition; private Vector3 initialSpineChestPosition; void Start() { InitializeKinect(); InitializeBodyTracker(); } void Update() { if (kinectDevice != null) { using (Capture capture = kinectDevice.GetCapture()) { if (capture != null) { if (capture.Color != null) { ProcessColorFrame(capture.Color); } if (bodyTracker != null) { ProcessBodyFrame(capture); } } } } } void OnDestroy() { if (bodyTracker != null) { bodyTracker.Dispose(); } if (kinectDevice != null) { kinectDevice.StopCameras(); kinectDevice.Dispose(); } } private void InitializeKinect() { kinectDevice = Device.Open(); if (kinectDevice != null) { kinectDevice.StartCameras(new DeviceConfiguration { ColorFormat = ImageFormat.ColorBGRA32, ColorResolution = ColorResolution.R1080p, DepthMode = DepthMode.WFOV_Unbinned, CameraFPS = FPS.FPS15, SynchronizedImagesOnly = true }); colorTexture = new Texture2D(1920, 1080, TextureFormat.BGRA32, false); } else { Debug.LogError("Failed to open Kinect device."); } } private void InitializeBodyTracker() { if (kinectDevice != null) { bodyTracker = Tracker.Create(kinectDevice.GetCalibration(), new TrackerConfiguration { ProcessingMode = TrackerProcessingMode.Gpu, SensorOrientation = SensorOrientation.Default }); if (bodyTracker == null) { Debug.LogError("Failed to create body tracker."); } } } private void ProcessColorFrame(Microsoft.Azure.Kinect.Sensor.Image colorImage) { if (colorImage.Format == ImageFormat.ColorBGRA32) { int width = colorImage.WidthPixels; int height = colorImage.HeightPixels; byte[] colorData = new byte[width * height * 4]; colorImage.Memory.CopyTo(colorData); byte[] flippedColorData = new byte[width * height * 4]; for (int y = 0; y < height; y++) { int srcIndex = y * width * 4; int dstIndex = (height - 1 - y) * width * 4; System.Buffer.BlockCopy(colorData, srcIndex, flippedColorData, dstIndex, width * 4); } colorTexture.LoadRawTextureData(flippedColorData); colorTexture.Apply(); backgroundImage.texture = colorTexture; } else { Debug.LogError("Unsupported color image format: " + colorImage.Format); } } private void ProcessBodyFrame(Capture capture) { bodyTracker.EnqueueCapture(capture); using (Frame frame = bodyTracker.PopResult()) { if (frame != null && frame.NumberOfBodies > 0) { Body body = frame.GetBody(0); UpdateClothing(body); long latency = (long)(frame.DeviceTimestamp.TotalMilliseconds - capture.Depth.DeviceTimestamp.TotalMilliseconds); Debug.Log($"Latency: {latency} ms"); } } } private void UpdateClothing(Body body) { if (topClothingObject != null && bottomClothingObject != null) { Vector3 pelvisPosition = GetVector3FromJoint(body.Skeleton.GetJoint(JointId.Pelvis)); Vector3 spineChestPosition = GetVector3FromJoint(body.Skeleton.GetJoint(JointId.SpineChest)); float distanceToCamera = pelvisPosition.z; float scaleFactor = Mathf.Clamp(1f / (distanceToCamera * 0.01f), 0.5f, 2f); Vector3 cameraPosition = new Vector3(0f, 0f, 0f); // Assuming the Kinect camera is at the origin Vector3 topClothingPosition = spineChestPosition - cameraPosition; topClothingPosition.y += 0.2f; topClothingObject.transform.position = topClothingPosition; Vector3 bottomClothingPosition = pelvisPosition - cameraPosition; bottomClothingPosition.y -= 0.1f; bottomClothingObject.transform.position = bottomClothingPosition; Quaternion spineChestRotation = GetQuaternionFromJoint(body.Skeleton.GetJoint(JointId.SpineChest)); Quaternion topRotationOffset = Quaternion.Euler(90f, 90f, 0f); Quaternion topFinalRotation = spineChestRotation * topRotationOffset; topClothingObject.transform.rotation = topFinalRotation; Quaternion pelvisRotation = GetQuaternionFromJoint(body.Skeleton.GetJoint(JointId.Pelvis)); Quaternion bottomRotationOffset = Quaternion.Euler(0f, 120f, 10f); Quaternion bottomFinalRotation = pelvisRotation * bottomRotationOffset; bottomClothingObject.transform.rotation = bottomFinalRotation; topClothingObject.transform.localScale = Vector3.one * scaleFactor; bottomClothingObject.transform.localScale = Vector3.one * scaleFactor; } else { Debug.LogWarning("Clothing objects are null. Please assign FBX objects to the topClothingObject and bottomClothingObject variables."); } } private Quaternion GetQuaternionFromJoint(Microsoft.Azure.Kinect.BodyTracking.Joint joint) { return new Quaternion(joint.Quaternion.X, joint.Quaternion.Y, joint.Quaternion.Z, joint.Quaternion.W); } private Vector3 GetVector3FromJoint(Microsoft.Azure.Kinect.BodyTracking.Joint joint) { float scaleFactor = 0.001f; Vector3 jointPosition = new Vector3(joint.Position.X * scaleFactor, joint.Position.Y * scaleFactor, joint.Position.Z * scaleFactor); return jointPosition; } }
我也曾尝试基于Kinect相机位置计算相对位置,但问题仍未解决,希望获得修复方案让衣物与用户运动方向一致。
修复方案
1. 修正坐标系转换(核心问题)
Azure Kinect与Unity的坐标系Z轴方向相反:
- Kinect:Z轴朝向用户(向前)
- Unity:Z轴远离相机(向后)
修改GetVector3FromJoint方法,反转Z轴:
private Vector3 GetVector3FromJoint(Microsoft.Azure.Kinect.BodyTracking.Joint joint) { float scaleFactor = 0.001f; // 反转Z轴匹配Unity坐标系 Vector3 jointPosition = new Vector3(joint.Position.X * scaleFactor, joint.Position.Y * scaleFactor, -joint.Position.Z * scaleFactor); return jointPosition; }
2. 调整旋转顺序与偏移角度
Unity旋转是偏移旋转在前,关节旋转在后的乘法顺序,同时修正偏移方向:
private void UpdateClothing(Body body) { // ... 原有位置计算代码 ... // 上衣旋转:先应用偏移,再叠加关节旋转 Quaternion spineChestRotation = GetQuaternionFromJoint(body.Skeleton.GetJoint(JointId.SpineChest)); Quaternion topRotationOffset = Quaternion.Euler(90f, -90f, 0f); // 修正Y轴偏移方向 Quaternion topFinalRotation = topRotationOffset * spineChestRotation; topClothingObject.transform.rotation = topFinalRotation; // 下装旋转:同理调整偏移方向 Quaternion pelvisRotation = GetQuaternionFromJoint(body.Skeleton.GetJoint(JointId.Pelvis)); Quaternion bottomRotationOffset = Quaternion.Euler(0f, -60f, 10f); // 反转Y轴偏移角度 Quaternion bottomFinalRotation = bottomRotationOffset * pelvisRotation; bottomClothingObject.transform.rotation = bottomFinalRotation; // ... 原有缩放代码 ... }
3. 简化位置计算
转换坐标系后,无需再减去相机原点(Kinect已对齐Unity原点):
Vector3 topClothingPosition = spineChestPosition; topClothingPosition.y += 0.2f; topClothingObject.transform.position = topClothingPosition; Vector3 bottomClothingPosition = pelvisPosition; bottomClothingPosition.y -= 0.1f; bottomClothingObject.transform.position = bottomClothingPosition;
4. 重置模型初始旋转
检查衣物FBX模型的Inspector面板,将Rotation重置为(0,0,0),避免模型自身初始偏移影响映射效果。
测试步骤
- 在Scene视图中绘制关节Gizmo,确认转换后的关节位置与用户实际位置一致;
- 暂时移除旋转偏移,直接使用关节原始旋转,观察方向是否正确;
- 逐步添加旋转偏移,微调角度至完全匹配。
内容的提问来源于stack exchange,提问作者Yerim Kang
相关产品推荐
相关产品推荐

