You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity、Vuforia与HoloLens中球体相对图像目标定位异常问题

问题描述

我正在使用Unity、Vuforia和HoloLens开发AR应用,目标是在Vuforia图像目标的相对指定位置(如相对于图像目标原点的(1, 2, 3)处)创建球体。

已尝试操作

  • 手动操作:在Unity Inspector中将球体作为Vuforia图像目标的子物体,设置位置为(1, 2, 3),球体显示位置正确。
  • 脚本创建:通过脚本创建球体时,位置不符合预期。

代码尝试

我原本用以下方式定位球体:

sphere.transform.position = targetTransform.position + localPosition;

其中targetTransform是Vuforia目标ObserverBehaviour的Transform组件,但脚本创建的球体与手动放置的位置不一致。

完整脚本

SphereManager类

public class SphereManager
{
    private GameObject sphere;
    private Vector3 localPosition;

    public SphereManager(Vector3 position)
    {
        localPosition = position;
    }

    public void CreateSphere(Transform targetTransform)
    {
        if (sphere == null)
        {
            sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphere.transform.SetParent(targetTransform, false);
            sphere.transform.position = targetTransform.position + localPosition;
            sphere.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
        }
    }

    public void DestroySphere()
    {
        if (sphere != null)
        {
            GameObject.Destroy(sphere);
            sphere = null;
        }
    }

    public bool IsSphereActive() => sphere != null;
}

SphereCreator类

public class SphereCreator : MonoBehaviour
{
    public Vector3 pose = Vector3.zero;
    private SphereManager sphereManager;
    private ObserverBehaviour observerBehaviour;

    void Start()
    {
        sphereManager = new SphereManager(pose);
        observerBehaviour = GetComponent<ObserverBehaviour>() ?? GetComponentInChildren<ObserverBehaviour>() ?? GetComponentInParent<ObserverBehaviour>();

        if (observerBehaviour)
        {
            observerBehaviour.OnTargetStatusChanged += OnTargetStatusChanged;
        }
        else
        {
            Debug.LogWarning("ObserverBehaviour component not found.");
        }
    }

    private void OnTargetStatusChanged(ObserverBehaviour behaviour, TargetStatus targetStatus)
    {
        if (targetStatus.Status == Status.TRACKED || targetStatus.Status == Status.EXTENDED_TRACKED)
        {
            sphereManager.CreateSphere(behaviour.transform);
        }
        else
        {
            sphereManager.DestroySphere();
        }
    }

    private void OnDestroy()
    {
        if (observerBehaviour != null)
        {
            observerBehaviour.OnTargetStatusChanged -= OnTargetStatusChanged;
        }
    }
}

核心问题:脚本创建的球体与Inspector手动放置的球体无法对齐,如何在脚本中设置位置确保两者一致?


解决方案

问题出在你设置球体位置的逻辑上。当球体作为图像目标的子物体时,应该使用局部坐标定位,这和你手动在Inspector中操作的逻辑完全一致。

修改步骤

在SphereManager的CreateSphere方法中,替换设置position的代码,改为直接设置localPosition:

public void CreateSphere(Transform targetTransform)
{
    if (sphere == null)
    {
        sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.SetParent(targetTransform, false);
        // 关键修改:使用局部坐标匹配手动操作逻辑
        sphere.transform.localPosition = localPosition;
        sphere.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
    }
}

原因解释

  • 手动操作时,你在Inspector中设置的是球体相对于父物体(图像目标)的局部位置。
  • 原代码中targetTransform.position + localPosition计算的是世界坐标,会忽略图像目标的旋转、缩放等变换信息,导致位置偏移。
  • 使用localPosition可以直接将球体放置在相对于图像目标原点的指定位置,完全对齐手动放置的效果。

额外优化

如果图像目标存在缩放,可根据需求调整局部位置以适配缩放后的空间:

// 若父物体有缩放,按比例调整局部位置(可选)
sphere.transform.localPosition = Vector3.Scale(localPosition, targetTransform.localScale);

内容的提问来源于stack exchange,提问作者Morteza Namvar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:19:59