unity_踩坑日志_物体的世界坐标 Transform.position 和 PointerEventData.point 对不上

当Canvas设置为ScreenSpace-Camera模式时,点击位置与世界坐标相差较大。原因是该模式下以屏幕中心为坐标原点。解决方法是创建额外的Canvas来承载UI元素,以减小坐标差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

 可以看出点击的位置和小黑点的世界坐标相差很多。

    public void OnTouchDown(BaseEventData baseEventData)
    {
        PointerEventData data = (PointerEventData) baseEventData;
        _touchPos = data.position;
    }

理论上来说点击的位置也是世界坐标,但是会相差很多。

原因:

Canvas 设置成了 ScreenSpace-Camera 模式。是以屏幕中心点为坐标原点。

 

解决方法:

再创建一个 Canvas 把相关 UI 放到另一个 Canvas 上面。

<think>我们正在处理一个Unity相关的问题:用户想要获取物体的包围盒中心坐标(center)而不是轴心点(pivot)坐标。根据提供的引用,我们可以总结如下: - 引用[2]指出:在Unity中,Pivot Point对应物体Transform.position,而Center模式则显示物体包围盒(AABB)的中心点。 - 引用[3]提供了一种方法:如果物体的pivot不在center,可以通过代码获取center位置,然后创建一个新的物体(作为中心轴)并将原物体作为其子物体,通过旋转中心轴来实现绕中心旋转。 - 引用[4]提到:当center轴pivot轴不一致时,旋转操作可能不如预期,需要调整。 因此,用户的需求是直接获取物体的包围盒中心坐标(即Center坐标),而不是Transform.position(即Pivot坐标)。 在Unity中,物体的包围盒(AABB)可以通过渲染器(Renderer)组件来获取。具体来说,我们可以使用`Renderer.bounds`属性,该属性返回一个包围盒(Bounds),然后我们可以通过`Bounds.center`获取包围盒的中心点。 步骤: 1. 获取物体上的Renderer组件(可以是MeshRenderer或SkinnedMeshRenderer等)。 2. 通过Renderer组件的bounds属性得到包围盒。 3. 访问包围盒的center属性即可得到中心坐标。 注意:如果物体没有Renderer组件,那么这种方法将无效。另外,如果物体有多个Renderer,可能需要合并这些包围盒。 代码示例: ```csharp using UnityEngine; public class GetCenter : MonoBehaviour { void Start() { // 获取当前物体上的Renderer组件 Renderer renderer = GetComponent<Renderer>(); if (renderer != null) { // 获取包围盒 Bounds bounds = renderer.bounds; // 中心坐标 Vector3 center = bounds.center; Debug.Log("物体的中心坐标: " + center); } else { Debug.LogWarning("物体上没有Renderer组件。"); } } } ``` 如果物体有多个Renderer(例如,子物体上也有Renderer),我们可以遍历所有Renderer,然后计算一个总的包围盒: ```csharp using UnityEngine; using System.Collections.Generic; public class GetCenter : MonoBehaviour { void Start() { // 获取当前物体及其所有子物体上的Renderer组件 Renderer[] renderers = GetComponentsInChildren<Renderer>(); if (renderers.Length > 0) { // 初始化一个包围盒,将第一个渲染器的包围盒作为初始值 Bounds combinedBounds = renderers[0].bounds; // 从第二个开始合并 for (int i = 1; i < renderers.Length; i++) { combinedBounds.Encapsulate(renderers[i].bounds); } Vector3 center = combinedBounds.center; Debug.Log("合并后的中心坐标: " + center); } else { Debug.LogWarning("物体及其子物体上没有Renderer组件。"); } } } ``` 注意:`Bounds.Encapsulate`方法用于扩展包围盒以包含另一个包围盒。 另外,如果物体没有渲染器,但可能有碰撞器(Collider),我们可以使用碰撞器的包围盒: ```csharp Collider collider = GetComponent<Collider>(); if (collider != null) { Bounds bounds = collider.bounds; Vector3 center = bounds.center; // ... } ``` 同样,也可以合并多个碰撞器的包围盒。 但是,请注意,用户的需求是获取物体的包围盒中心,而不是碰撞器。通常,渲染器的包围盒碰撞器的包围盒可能有所不同(例如,碰撞器可能是一个简化的形状)。所以,根据需求选择。 总结:获取物体包围盒中心坐标(center)的方法是通过渲染器或碰撞器的包围盒的center属性。 相关问题: 1.Unity中,如何动态改变物体的轴心点(pivot)? 2. 如何让物体围绕其包围盒中心(center)旋转? 3.Unity编辑器中,如何将物体的轴心点(pivot)设置到包围盒中心(center)?</think>### Unity 中获取物体包围盒中心坐标(Center)的方法 在 Unity 中获取物体的包围盒中心坐标(Center)而非轴心点(Pivot)坐标,可通过以下步骤实现: #### 核心方法:使用 `Renderer.bounds.center` ```csharp using UnityEngine; public class GetCenterPosition : MonoBehaviour { void Start() { // 获取物体上的渲染器组件(MeshRenderer/SkinnedMeshRenderer) Renderer renderer = GetComponent<Renderer>(); if (renderer != null) { // 直接获取包围盒中心坐标 Vector3 centerPosition = renderer.bounds.center; Debug.Log("包围盒中心坐标: " + centerPosition); } else { Debug.LogWarning("物体缺少渲染器组件"); } } } ``` #### 关键说明: 1. **`Renderer.bounds`** - 自动计算物体**当前**的轴对齐包围盒(AABB) - `.center` 属性直接返回包围盒中心的世界坐标 - 适用于所有带渲染器的物体(MeshRenderer、SkinnedMeshRenderer等) 2. **与 Transform.position 的区别** - `Transform.position` 返回轴心点(Pivot)坐标(由建模软件决定)[^2] - `Renderer.bounds.center` 返回动态计算的包围盒中心坐标(Center)[^2] 3. **多子物体对象的处理** 若对象包含多个子物体,需合并所有渲染器的包围盒: ```csharp Bounds totalBounds = new Bounds(); Renderer[] allRenderers = GetComponentsInChildren<Renderer>(); foreach (Renderer r in allRenderers) { if (totalBounds.size == Vector3.zero) totalBounds = r.bounds; else totalBounds.Encapsulate(r.bounds); } Vector3 center = totalBounds.center; ``` #### 应用场景示例(绕中心旋转)[^3]: ```csharp // 创建临时空物体作为旋转中心 GameObject rotationCenter = new GameObject("RotationCenter"); rotationCenter.transform.position = GetComponent<Renderer>().bounds.center; // 将目标物体设为旋转中心的子物体 transform.SetParent(rotationCenter.transform); // 绕中心旋转 rotationCenter.transform.Rotate(0, 30 * Time.deltaTime, 0); ``` #### 注意事项: 1. **实时更新** 包围盒会在物体移动/缩放时自动更新,但脚本中需在 `Update` 或 `LateUpdate` 中持续获取 2. **无渲染器对象** 若对象无渲染器(如空物体): - 添加碰撞器并使用 `collider.bounds.center` - 或手动计算子物体中心点 3. **性能优化** 避免每帧计算,可在需要时缓存结果: ```csharp private Vector3 cachedCenter; void Update() { if (transform.hasChanged) { cachedCenter = GetComponent<Renderer>().bounds.center; transform.hasChanged = false; } } ``` --- ### 常见问题解答 **Q:为什么直接使用 Transform.position 无法获取中心坐标?** A:`Transform.position` 始终返回轴心点(Pivot),这是由模型文件(如.fbx)定义的原始锚点,与包围盒无关[^2][^4]。 **Q:编辑器中如何可视化中心点?** A:在 Scene 视图左上角将坐标模式从 **Pivot** 切换为 **Center**,即可看到包围盒中心坐标(蓝/红/绿三轴交点)[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值