0816学习 agile Posted on Aug 18 2023 面试 unity基础 - [`Unity Transform Rotate`](http://warmcat.org/chai/blog/?p=1660)相关函数有5个,其中两个被废弃了 ```C# //使用欧拉角定义的旋转,以zxy顺规计算 //当Space.Self空间下,eulerRot被当做local空间下的旋转,直接右乘四元数,之后这个旋转将会被首先应用;当在Space.World空间下,eulerRot被当做相对世界坐标的旋转,首先用 (Quaternion.Inverse (rotation) * eulerRot * rotation) 将这个四元数从世界空间变换到本地空间,然后附加到m_LocalRotation。 public void Rotate(Vector3 eulerAngles, [uei.DefaultValue("Space.Self")] Space relativeTo ){ Quaternion eulerRot = Quaternion.Euler(eulers.x, eulers.y, eulers.z); if (relativeTo == Space.Self) localRotation = localRotation * eulerRot; else { rotation = rotation * (Quaternion.Inverse(rotation) * eulerRot * rotation); //是用eulerRot最后旋转,这时候已经到了父节点的最上层即世界坐标了,所以世界空间的旋转能保证是绕世界空间坐标轴的。当希望在世界空间瞄准物体的时候,用Space.World //rotation = eulerRot * rotation; //localRotation = localRotation * (Quaternion.Inverse(rotation) * eulerRot * rotation); } } //使用轴角定义的旋转 public void Rotate(Vector3 axis, float angle, [uei.DefaultValue("Space.Self")] Space relativeTo ){ if (relativeTo == Space.Self) RotateAroundInternal(transform.TransformDirection(axis), angle * Mathf.Deg2Rad); else RotateAroundInternal(axis, angle * Mathf.Deg2Rad); } //[NativeMethod("RotateAround")] //internal extern void RotateAroundInternal(Vector3 axis, float angle); //RotateAroundInternal是一个绕世界空间的轴旋转的函数,函数的实现是 void Transform::RotateAroundInternal (const Vector3f& worldAxis, float rad) { AssertIf (!CompareApproximately (Magnitude (worldAxis), 1.0F)); Vector3f localAxis = InverseTransformDirection(worldAxis); Quaternionf q = AxisAngleToQuaternion (localAxis, rad); m_LocalRotation = Normalize (m_LocalRotation * q); #if UNITY_EDITOR SyncLocalEulerAnglesHint (); #endif SetDirty (); SendTransformChanged (kRotationChanged); } //绕世界空间中某点旋转,同时会影响position和rotation,类似地球绕日公转 public void RotateAround (Vector3 point, Vector3 axis, float angle){ Vector3 worldPos = position; Quaternion q = Quaternion.AngleAxis(angle, axis); Vector3 dif = worldPos - point; dif = q * dif; worldPos = point + dif; position = worldPos; RotateAroundInternal(axis, angle * Mathf.Deg2Rad); } //绕世界空间坐标轴旋转,等同于Rotate(axis, angle, Space.World) [System.Obsolete ("use Transform.Rotate instead.")] public void RotateAround (Vector3 axis, float angle); //绕父物体旋转,并不等同于Rotate(axis, angle, Space.Self) //绕父节点的空间坐标旋转 //能看到RotateAroundLocal实际上会将旋转放在父物体空间下执行,作为此物体在父物体空间下的最后一个旋转,所以命名为RotateAroundParent更合适,因为大多数情况下我们说的local都是物体自己的本地空间,localToWorldMatrix用来将本地空间下的mesh顶点和向量变换到世界空间用来渲染,也叫modelMatrix。RotateAroundLocal在做相对父物体的旋转的时候比较有用,但是unity废弃了这个接口,估计是因为名字有误导性,可以通过右乘localrotation实现 [System.Obsolete ("use Transform.Rotate instead.")] public void RotateAroundLocal (Vector3 axis, float angle){ AssertIf (!CompareApproximately (Magnitude (localAxis), 1.0F)); Quaternionf q = AxisAngleToQuaternion (localAxis, rad); m_LocalRotation = Normalize (q * m_LocalRotation); //注意这里的顺序 #if UNITY_EDITOR SyncLocalEulerAnglesHint (); #endif SetDirty (); SendTransformChanged (kRotationChanged); } // C#接口 public Quaternion rotation { get { Quaternion tmp; INTERNAL_get_rotation(out tmp); return tmp; } set { INTERNAL_set_rotation(ref value); } } // C++实现 Quaternionf Transform::GetRotation ()const { Quaternionf worldRot = m_LocalRotation; Transform* cur = GetParent (); while (cur) { worldRot = cur->m_LocalRotation * worldRot; cur = cur->GetParent (); } return worldRot; } void Transform::SetRotation (const Quaternionf& q) { Transform* father = GetParent (); if (father != NULL) SetLocalRotation (Inverse (father->GetRotation ()) * q); else SetLocalRotation (q); } void Transform::SetLocalRotation (const Quaternionf& q) { ABORT_INVALID_QUATERNION (q, localRotation, transform); m_LocalRotation = q; #if UNITY_EDITOR SyncLocalEulerAnglesHint (); #endif ASSERT_ROTATION SetDirty (); SendTransformChanged (kRotationChanged); } ``` --- 可以归纳出如下结论: - `child.rotation = parent.rotation * child.localRotation` - `child.localRotation = Quaternion.Inverse(parent.rotation) * child.rotation` - `Quaternion q = Quaternion.Inverse(Camera.main.transform.rotation)*object.transform.rotation;`计算quaternion相机相对于Object,object.transform.rotation==Camera.main.transform.rotation * q - `localRotation = localRotation * eulerRot;` - `rotation = rotation * eulerRot`; - `m_Transform.localRotation = rot * m_Transform.localRotation;` 这个是相对于 绕父节点的空间坐标旋转 - `m_Transform.rotation = m_Transform.parent.rotation * rot * m_Transform.localRotation;` 这个是相对于 绕父节点的空间坐标旋转 - `m_Transform.rotation = rot * m_Transform.rotation;` 绕world空间的轴旋转 rot 其实就是世界坐标系*rot - `m_Transform.localRotation=Quaternion.Inverse(m_Transform.parent.rotation)*rot *m_Transform.rotation;`绕world空间的轴旋转 rot 其实就是世界坐标系*rot --- 实践例子 ```C# void Update() { Quaternion rot; if (m_RotateType == RotateType.AroundDefaultAxis_Q) { //1. 绕初始轴旋转 rot = Quaternion.AngleAxis(0.5f, Vector3.up); m_Transform.localRotation = Quaternion.Normalize(m_Transform.localRotation * rot); } else if (m_RotateType == RotateType.AroundDefaultAxis_T) { m_Transform.Rotate(Vector3.up, 0.5f, Space.Self); } else if (m_RotateType == RotateType.AroundParentAxis_Q) { //2. 绕父节点的空间坐标旋转 rot = Quaternion.AngleAxis(0.5f, Vector3.up); // 作为此物体在父物体空间下的最后一个旋转 m_Transform.rotation = m_Transform.parent.rotation * rot * m_Transform.localRotation; } else if (m_RotateType == RotateType.AroundParentAxis_Q2) { //2. 绕父节点的空间坐标旋转 rot = Quaternion.AngleAxis(0.5f, Vector3.up); // parent.rotation * child.localRotation = child.rotation // child.localRotation = Quaternion.Inverse(parent.rotation) * child.rotation // child.localRotation = rot * Quaternion.Inverse(parent.rotation) * child.rotation // child.localRotation = rot * Quaternion.Inverse(parent.rotation) * parent.rotation * child.localRotation // m_Transform.parent.rotation * m_Transform.localRotation = m_Transform.parent.rotation * rot * m_Transform.localRotation; m_Transform.localRotation = rot * m_Transform.localRotation; } else if (m_RotateType == RotateType.AroundParentAxis_T) { // 能看到RotateAroundLocal实际上会将旋转放在父物体空间下执行,作为此物体在父物体空间下的最后一个旋转, // 所以命名为RotateAroundParent更合适,因为大多数情况下我们说的local都是物体自己的本地空间, // localToWorldMatrix用来将本地空间下的mesh顶点和向量变换到世界空间用来渲染,也叫modelMatrix。 // RotateAroundLocal在做相对父物体的旋转的时候比较有用,但是unity废弃了这个接口,估计是因为名字有误导性, // 可以通过右乘localrotation实现。 // void Transform::RotateAroundLocal (const Vector3f& localAxis, float rad) // { // AssertIf (!CompareApproximately (Magnitude (localAxis), 1.0F)); // // Quaternionf q = AxisAngleToQuaternion (localAxis, rad); // m_LocalRotation = Normalize (q * m_LocalRotation); //注意这里的顺序 // #if UNITY_EDITOR // SyncLocalEulerAnglesHint (); // #endif // // SetDirty (); // SendTransformChanged (kRotationChanged); // } m_Transform.RotateAroundLocal(Vector3.up, Mathf.Deg2Rad * 0.5f); } else if (m_RotateType == RotateType.AroundWorldAxis_Q) { //3. 绕world空间的轴旋转 Vector3 localAxis = m_Transform.InverseTransformDirection(Vector3.up); rot = Quaternion.AngleAxis(0.5f, localAxis); m_Transform.localRotation = Quaternion.Normalize(m_Transform.localRotation * rot); } else if (m_RotateType == RotateType.AroundWorldAxis_Q2) { rot = Quaternion.AngleAxis(0.5f, Vector3.up); // m_Transform.rotation == m_Transform.parent.rotation * m_Transform.localRotation == // m_Transform.parent.rotation * Quaternion.Inverse(m_Transform.parent.rotation) * rot * // m_Transform.rotation; //rot 其实就是世界坐标系*rot m_Transform.rotation = rot * m_Transform.rotation; } else if (m_RotateType == RotateType.AroundWorldAxis_Q3) { rot = Quaternion.AngleAxis(0.5f, Vector3.up); m_Transform.localRotation = Quaternion.Inverse(m_Transform.parent.rotation) * rot * m_Transform.rotation; } else if (m_RotateType == RotateType.AroundWorldAxis_Q4) { rot = Quaternion.AngleAxis(0.5f, Vector3.up); m_Transform.localRotation = Quaternion.Inverse(m_Transform.parent.rotation) * m_Transform.rotation * (Quaternion.Inverse(m_Transform.rotation) * rot * m_Transform.rotation); } else if (m_RotateType == RotateType.AroundWorldAxis_T) { m_Transform.Rotate(Vector3.up, 0.5f, Space.World); } } ``` --- - [unity3d 中对场景进行类似谷歌地图的手势操作](https://gist.github.com/bibishou/e5824596414e159ba996ce5288335b35) - [Unity拖动2D和3D物体](https://www.lfzxb.top/unity-2d3d/) - [Unity中 多种相机视角跟随方式 (第一、三人称都有哦,快来看看叭)](https://bbs.huaweicloud.com/blogs/285712) - [一个简单操作解决Unity中拖拽相机视图的跟手问题](https://zhuanlan.zhihu.com/p/138936629) - [完美解决Unity中拖拽相机视图的跟手问题](https://www.cnblogs.com/atong/p/15113821.html) - [Unity SceneView 鼠标转世界坐标](https://www.cnblogs.com/atong/p/16473021.html) - [用Unity实现传送门效果(一)](https://zhuanlan.zhihu.com/p/47437577) - [Unity 关于GUI与UGUI坐标 的一点问题解惑](https://zhuanlan.zhihu.com/p/141731132) - [来说说Unity中的那些Utility和Helper们](https://zhuanlan.zhihu.com/p/141672693) - [Unity中的Matrix4x4](https://zhuanlan.zhihu.com/p/146918827) - [记一次非正规变体优化带来的兼容性导致部分手机卡死的问题](https://blog.csdn.net/linjf520/article/details/130847540) - [斜视锥体裁剪Camera.CalculateObliqueMatrix的推导](https://blog.csdn.net/a1047120490/article/details/106743734/) 0619学习 0804学习