常用旋转知识 - 旋转父对象子对象不受到位置影响

本文介绍了一个Unity中的相机脚本CCamera,该脚本允许父对象旋转时,保持相机及其目标位置固定不变,仅使角色自身旋转。通过初始化相机及其目标的相对位置,并在每次更新时重新计算这些位置来实现。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//旋转父对象,子对象不跟着移动
public class CCamera : MonoBehaviour {

    public Transform cameraLook;    //相机看向目标
    public Transform cameraAt;      //相机所在位置
    // Use this for initialization

    Vector3 initPos;
    Vector3 initTarget;
    void Start()
    {
        //cameraAt目标初始化相对位置
        initPos = cameraAt.parent.transform.rotation * cameraAt.localPosition;
        Debug.Log("init "+(initPos).ToString("F2"));

        //cameraLook目标初始化相对位置
        initTarget = cameraLook.parent.transform.rotation * cameraLook.localPosition;
    }

    // Update is called once per frame
    void Update () {


        //当前旋转UserControl后,计算cameraLook的位置
        Vector3 lookv3 = cameraLook.parent.transform.rotation * cameraLook.localPosition;
        cameraLook.position = cameraLook.position + (initTarget - lookv3);

        //当前旋转UserControl后,计算cameraAt的位置
        Vector3 newv3 = cameraAt.parent.transform.rotation * cameraAt.localPosition;
        transform.position = cameraAt.position + (initPos - newv3);

        //相机所在位置看向目标方位
        Vector3 dir = (cameraLook.position - transform.position).normalized;
        Quaternion q = Quaternion.LookRotation(dir);
        transform.rotation = q;

        Debug.Log((newv3).ToString("F2")+","+(newv3- initPos).ToString("F2"));
    }


}

图:
这里写图片描述

可以看到胶囊旋转后,相机位置和目标位置是不变的,只有角色在旋转。

重点要理解 四元数 × 位置 = 旋转后所在位置

旋转向量也是同样道理。

<think>我们面对的核心问题是:如何在Unity中设置子物体的旋转,使其不受父物体旋转影响。根据引用内容[1][2][3],我们可以总结出几个关键点:1.在Unity中,子物体的变换(包括旋转)默认会受到父物体变换的影响(引用[1][2])2.直接修改子物体的旋转可能会因为父子关系而出现意外结果(引用[1])3.使用旋转(rotation)翻转物体会影响其坐标系和子物体(引用[3])4.在AnimatorController控制下,能直接修改骨骼物体的Transform(引用[2])解决方案思路:1.**分离父子关系法**:临时解除父子关系,设置旋转后再重新建立关系(简单但可能适用于所有场景)2.**反向旋转补偿法**:计算父物体旋转的逆,然后应用到子物体上(引用[2]提供了一种思路)3.**使用额外容器物体**:在父子之间插入一个空物体,通过控制这个空物体来抵消父物体的旋转(推荐)4.**直接设置世界空间旋转**:通过设置子物体的worldRotation来覆盖局部旋转(但需注意万向锁问题,引用[4]提到四元数的优势)具体实现:###方法1:临时解除父子关系(适用于静态场景)```csharp//保存当前父物体Transformparent=transform.parent;//解除父子关系transform.SetParent(null);//设置子物体的世界旋转不受父物体影响)transform.rotation=Quaternion.Euler(0,30,0);//示例旋转//重新建立父子关系transform.SetParent(parent);```###方法2:反向旋转补偿(适用于动态场景)```csharp//获取父物体的逆旋转QuaternioninverseParentRot=Quaternion.Inverse(transform.parent.rotation);//计算子物体期望的世界旋转QuaterniondesiredWorldRot=Quaternion.Euler(0,30,0);//设置子物体的局部旋转=父物体逆旋转*期望世界旋转transform.localRotation=inverseParentRot*desiredWorldRot;```###方法3:使用中间容器物体(最佳实践)1.在父物体和子物体之间创建一个空物体(例如命名为"Pivot")2.将子物体作为这个空物体的子物体3.需要独立控制子物体旋转时,直接修改空物体的旋转```csharp//创建中间物体GameObjectcontainer=newGameObject("RotationContainer");container.transform.SetParent(transform.parent);//设置容器位置与原子物体一致container.transform.position=transform.position;//将原物体转移到容器下transform.SetParent(container.transform);//现在可以通过修改容器旋转来控制子物体的"独立旋转"container.transform.rotation=Quaternion.Euler(0,90,0);```###方法4:直接设置世界旋转(需注意约束)```csharp//直接设置子物体的世界旋转(会覆盖局部旋转)transform.rotation=Quaternion.Euler(0,45,0);//注意:如果父物体后续旋转,子物体仍会跟随旋转```>⚠️**重要注意事项**:>1.在动画系统控制的对象上,直接修改Transform可能导致冲突(引用[2]),应优先使用额外容器法>2.涉及物理模拟时,推荐使用方法3的中间容器,避免破坏物理连续性>3.引用[4]强调使用四元数操作旋转比欧拉角更可靠###性能与适用场景对比|方法|性能影响|适用场景||------|----------|----------||临时解除父子关系|中等(层级改变触发矩阵重算)|单次操作,静态物体||反向旋转补偿|较低(每帧计算)|持续更新,动态父子关系||中间容器|低(额外Transform开销)|长期独立控制,复杂系统||直接设置世界旋转|最低|简单需求,需要后续父物体影响|###扩展问题:如何保持子物体的位置不受父物体影响?解决方案类似,但需同时处理位置旋转:```csharp//创建中间容器GameObjectcontainer=newGameObject("IndependentContainer");container.transform.SetParent(transform.parent);//保持世界空间位置旋转变container.transform.position=transform.position;container.transform.rotation=transform.rotation;//转移子物体transform.SetParent(container.transform,true);//第二个参数保持世界坐标变```###引用[5]的启示:避免直接依赖欧拉角当需要精确获取旋转值时,应使用四元数或编写规范化函数(如引用[5]的方法),但更推荐:```csharp//直接使用四元数运算代替欧拉角QuaternioncurrentRot=transform.rotation;```---§§相关问题§§1.Unity中如何同时保持子物体的位置旋转独立于父物体?2.在动画系统中如何实现骨骼部件的独立旋转?3.使用中间容器物体会影响渲染批处理吗?4.如何优化大量独立旋转子物体的性能?</think>### Unity 子物体旋转不受父物体影响的解决方案 在 Unity 中,子物体的 `rotation` 默认会继承父物体的旋转。以下是 **4 种实现子物体独立旋转**的核心方案,结合引用内容和实际工程实践: --- ### 方案 1:使用中间容器物体(推荐) **原理**:在父物体和子物体之间添加空物体层,隔离旋转影响(引用[2]思路) **步骤**: 1. 创建空物体 `RotationContainer` 作为父物体的直接子物体 2. 将原子物体作为 `RotationContainer` 的子物体 3. 通过控制 `RotationContainer` 实现独立旋转 ```csharp // 创建中间容器 GameObject container = new GameObject("RotationContainer"); container.transform.SetParent(parentTransform); container.transform.localPosition = Vector3.zero; container.transform.localRotation = Quaternion.identity; // 将子物体挂载到容器 childTransform.SetParent(container.transform); childTransform.localPosition = originalLocalPos; // 保持原位置 // 独立旋转子物体(不受父物体影响) childTransform.localRotation = Quaternion.Euler(30, 0, 45); // 示例旋转 ``` **优势**: - 完全隔离父子旋转链(引用[1]问题根源) - 兼容动画系统(引用[2]骨骼限制场景) - 物理引擎友好 --- ### 方案 2:反向旋转补偿法 **原理**:通过计算父物体旋转的逆矩阵抵消影响(引用[2]数学方案) ```csharp // 获取父物体世界旋转的逆 Quaternion inverseParentRot = Quaternion.Inverse(parentTransform.rotation); // 计算子物体期望的独立世界旋转 Quaternion desiredWorldRot = Quaternion.Euler(0, 90, 0); // 设置子物体局部旋转 = 父逆旋转 * 期望世界旋转 childTransform.localRotation = inverseParentRot * desiredWorldRot; ``` **适用场景**: - 动态旋转的父物体 - 无法添加中间物体的约束环境 --- ### 方案 3:世界空间旋转锁定 **原理**:直接设置世界空间旋转,覆盖局部旋转值(引用[4]四元数实践) ```csharp // 保持子物体世界旋转恒定 void Update() { childTransform.rotation = Quaternion.Euler(0, 90, 0); // 锁定Y轴90度 } ``` **注意**: - 需每帧更新(父物体旋转时) - 可能与其他动画系统冲突 --- ### 方案 4:Shader 级旋转分离(高级) **原理**:通过Shader矩阵运算分离渲染旋转(引用[3]视觉翻转思路) ```glsl // Shader 代码片段 v2f vert (appdata v) { v2f o; // 只应用子物体模型矩阵,忽略父矩阵 o.pos = mul(UNITY_MATRIX_VP, mul(_ChildObjectMatrix, v.vertex)); return o; } ``` **优势**: - 完全改变Transform层级 - 适用于VR/AR等敏感场景(引用[1]手柄交互) --- ### 关键决策因素 | 方案 | 适用场景 | 性能影响 | 实现复杂度 | |------|----------|----------|------------| | 中间容器 | 通用场景 | ⭐⭐ | ⭐ | | 反向补偿 | 动态父物体 | ⭐⭐⭐ | ⭐⭐ | | 世界锁定 | 简单需求 | ⭐ | ⭐ | | Shader方案 | 高级渲染 | ⭐⭐ | ⭐⭐⭐ | --- ### 工程实践建议 1. **优先选择中间容器方案**(90%场景适用) 2. 避免直接操作欧拉角(引用[4][5]的教训) 3. 复杂骨骼系统用 `Transform.SetParent(null, true)` 临时解除父子关系再操作(引用[2]) 4. 使用四元数代替欧拉角(引用[4]成功案例): ```csharp // 安全的旋转操作 Quaternion targetRot = Quaternion.AngleAxis(90, Vector3.up); childTransform.rotation = targetRot; ``` > 📌 **重要提示**:若子物体需要同时独立于父物体的**位置旋转**,需在中间容器中同时处理位置偏移(引用[1]摄像机跟随问题)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thinbug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值