Unity 获取真实旋转数据

阅读: 评论:0

Unity 获取真实旋转数据

Unity 获取真实旋转数据

转载自:.html


今天做工具的时候遇到一个神奇的问题,具体就是在使用transform.eulerAngles拿到的数据是经过计算转换的,简单的说就是你面板上的数据是vector3(-100, 0, 0),而访问transform对象拿到的eulerAngles属性是vector3(260, 0, 0),并且会把大于360的值限制在360内,我做的工具是用animationCurve进行曲线旋转,3个轴分别各自插值,但是拿到的这个eulerAngles属性就没法做反向插值旋转,比如我要从x=10插值到x=-10,结果成了x=10到x=350的插值了,并且没办法做到旋转很多圈。

拿到这个问题,我以为是我的工具在其他地方有设置去限定这个的值,因为我看到transform的检视面板上是明明可以看到负值的。后来才发现监视面板上面是负值,但是调用transform对象拿到的eulerAngles的值就已经是转换后的了。那不用说,肯定是Unity在背后做了工作,于是果断反编译了unity的transformInspactor类查看。

transformInspactor源码:

namespace UnityEditor
{using System;using UnityEngine;[CustomEditor(typeof(Transform)), CanEditMultipleObjects]internal class TransformInspector : Editor{private SerializedProperty m_Position;private TransformRotationGUI m_RotationGUI;private SerializedProperty m_Scale;private static Contents s_Contents;private void Inspector3D(){EditorGUILayout.PropertyField(this.m_Position, s_Contents.positionContent, new GUILayoutOption[0]);this.m_RotationGUI.RotationField();EditorGUILayout.PropertyField(this.m_Scale, s_Contents.scaleContent, new GUILayoutOption[0]);}public void OnEnable(){this.m_Position = base.serializedObject.FindProperty("m_LocalPosition");this.m_Scale = base.serializedObject.FindProperty("m_LocalScale");if (this.m_RotationGUI == null){this.m_RotationGUI = new TransformRotationGUI();}this.m_RotationGUI.OnEnable(base.serializedObject.FindProperty("m_LocalRotation"), new GUIContent(LocalizationDatabase.GetLocalizedString("Rotation")));}public override void OnInspectorGUI(){if (s_Contents == null){s_Contents = new Contents();}if (!EditorGUIUtility.wideMode){EditorGUIUtility.wideMode = true;EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212f;}base.serializedObject.Update();this.Inspector3D();Transform target = base.target as Transform;Vector3 position = target.position;if (((Mathf.Abs(position.x) > 100000f) || (Mathf.Abs(position.y) > 100000f)) || (Mathf.Abs(position.z) > 100000f)){EditorGUILayout.HelpBox(s_Contents.floatingPointWarning, MessageType.Warning);}base.serializedObject.ApplyModifiedProperties();}private class Contents{public string floatingPointWarning = LocalizationDatabase.GetLocalizedString("Due to floating-point precision limitations, it is recommended to bring the world coordinates of the GameObject within a smaller range.");public GUIContent positionContent = new GUIContent(LocalizationDatabase.GetLocalizedString("Position"), LocalizationDatabase.GetLocalizedString("The local position of this Game Object relative to the parent."));public GUIContent scaleContent = new GUIContent(LocalizationDatabase.GetLocalizedString("Scale"), LocalizationDatabase.GetLocalizedString("The local scaling of this Game Object relative to the parent."));}}
}

可以看到里面的旋转属性在检视面板的显示是由TransformRotationGUI这个类处理的;

TransformRotationGUI源码:

namespace UnityEditor
{using System;using UnityEngine;[Serializable]internal class TransformRotationGUI{private Vector3 m_EulerAngles;private Vector3 m_OldEulerAngles = new Vector3(1000000f, 1E+07f, 1000000f);private RotationOrder m_OldRotationOrder = RotationOrder.OrderZXY;private SerializedProperty m_Rotation;private GUIContent rotationContent = new GUIContent("Rotation", "The local rotation of this Game Object relative to the parent.");private static int s_FoldoutHash = "Foldout".GetHashCode();private Object[] targets;public void OnEnable(SerializedProperty m_Rotation, GUIContent label){this.m_Rotation = m_Rotation;this.targets = m_Rotation.serializedObject.targetObjects;this.m_OldRotationOrder = (this.targets[0] as Transform).ationContent = label;}public void RotationField(){this.RotationField(false);}public void RotationField(bool disabled){Transform transform = this.targets[0] as Transform;Vector3 localEulerAngles = transform.ationOrder);if (((this.m_OldEulerAngles.x != localEulerAngles.x) || (this.m_OldEulerAngles.y != localEulerAngles.y)) || ((this.m_OldEulerAngles.z != localEulerAngles.z) || (this.m_OldRotationOrder != ationOrder))){this.m_EulerAngles = transform.ationOrder);this.m_OldRotationOrder = ationOrder;}bool flag = false;bool flag2 = false;for (int i = 1; i < this.targets.Length; i++){Transform transform2 = this.targets[i] as Transform;Vector3 vector2 = transform2.ationOrder);flag |= ((vector2.x != localEulerAngles.x) || (vector2.y != localEulerAngles.y)) || !(vector2.z == localEulerAngles.z);flag2 |= ationOrder != ationOrder;}Rect totalPosition = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * (!EditorGUIUtility.wideMode ? ((float) 2) : ((float) 1)), new GUILayoutOption[0]);GUIContent label = EditorGUI.BeginProperty(totalPosition, ationContent, this.m_Rotation);EditorGUI.showMixedValue = flag;EditorGUI.BeginChangeCheck();int id = GUIUtility.GetControlID(s_FoldoutHash, FocusType.Keyboard, totalPosition);string str = "";if (AnimationMode.InAnimationMode() && (ationOrder != RotationOrder.OrderZXY)){if (flag2){str = "Mixed";}else{str = ationOrder.ToString();str = str.Substring(str.Length - 3);} =  + " (" + str + ")";}totalPosition = EditorGUI.MultiFieldPrefixLabel(totalPosition, id, label, 3);totalPosition.height = EditorGUIUtility.singleLineHeight;using (new EditorGUI.DisabledScope(disabled)){this.m_EulerAngles = EditorGUI.Vector3Field(totalPosition, , this.m_EulerAngles);}if (EditorGUI.EndChangeCheck()){Undo.RecordObjects(this.targets, "Inspector");foreach (Transform transform3 in this.targets){transform3.SetLocalEulerAngles(this.m_EulerAngles, ationOrder);if (transform3.parent != null){transform3.SendTransformChangedScale();}}this.m_Rotation.serializedObject.SetIsDifferentCacheDirty();}EditorGUI.showMixedValue = false;if (flag2){EditorGUILayout.HelpBox("Transforms have different rotation orders, keyframes saved will have the same value but not the same local rotation", MessageType.Warning);}EditorGUI.EndProperty();}}
}

再仔细看里面得到eulerAngles的方法:

// 拿到transform对象
Transform transform = this.targets[0] as Transform;// 调用transform的GetLocalEulerAngles方法获得原生值(此方法是直接调用到unity的native层)
Vector3 localEulerAngles = transform.ationOrder);

再看反编译的Transform类的GetLocalEulerAngles方法和eulerAngles属性:

public Vector3 eulerAngles
{get{ation.eulerAngles;}ation = Quaternion.Euler(value);}
}

eulerAngles是用的缓存的四元素,GetLocalEulerAngles是直接访问去了底层。
于是用反射去调用GetLocalEulerAngles,最终结果果然就是检视面板上面的真实值。

请看结果:

最后上调用该方法的代码:

// 获取原生值
System.Type transformType = transform.GetType();
PropertyInfo m_propertyInfo_rotationOrder = transformType.GetProperty("rotationOrder", BindingFlags.Instance | BindingFlags.NonPublic);
object m_OldRotationOrder = m_propertyInfo_rotationOrder.GetValue(transform, null);
MethodInfo m_methodInfo_GetLocalEulerAngles = transformType.GetMethod("GetLocalEulerAngles", BindingFlags.Instance | BindingFlags.NonPublic);
object value = m_methodInfo_GetLocalEulerAngles.Invoke(transform, new object[] { m_OldRotationOrder });Debug.LogError("反射调用GetLocalEulerAngles方法获得的值:" + value.ToString());
Debug.LogError("transform.localEulerAngles获取的值:" + transform.localEulerAngles.ToString());

本文发布于:2024-02-04 10:14:05,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170704860754667.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:真实   数据   Unity
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23