/// <summary> /// Allows us to render joint info into the scene. This GUI is /// used for displaying and manipulating the joint itself. /// </summary> /// <returns>Reports if the object's value was changed</returns> public override bool OnSceneManipulatorGUI(IKBoneModifier rModifier) { #if UNITY_EDITOR //Quaternion lSwing = mBone.Swing; //Quaternion lTwist = mBone.Twist; bool lIsSwingDirty = HandlesHelper.JointSwingHandle(mBone, rModifier); if (lIsSwingDirty) { //rModifier.Swing = lSwing; rModifier.IsDirty = true; } if (_AllowTwist) { bool lIsTwistDirty = HandlesHelper.JointTwistHandle(mBone, rModifier); if (lIsTwistDirty) { //rModifier.Twist = lTwist; rModifier.IsDirty = true; } } if (rModifier.IsDirty) { ApplyLimits(ref rModifier.Swing, ref rModifier.Twist); } #endif return(rModifier.IsDirty); }
/// <summary> /// Allows us to render joint info into the scene. This GUI is /// used for displaying and manipulating the joint itself. /// </summary> /// <returns>Reports if the object's value was changed</returns> public override bool OnSceneManipulatorGUI(IKBoneModifier rModifier) { #if UNITY_EDITOR bool lIsSwingDirty = HandlesHelper.JointSwingAxisHandle(mBone, _SwingAxis, rModifier); if (lIsSwingDirty) { rModifier.IsDirty = true; } if (_AllowTwist) { bool lIsTwistDirty = HandlesHelper.JointTwistHandle(mBone, rModifier); if (lIsTwistDirty) { rModifier.IsDirty = true; } } if (rModifier.IsDirty) { ApplyLimits(ref rModifier.Swing, ref rModifier.Twist); } #endif return(rModifier.IsDirty); }
/// <summary> /// Allows us to render joint info into the scene. This GUI is /// used for displaying and manipulating the joint itself. /// </summary> /// <returns></returns> public override bool OnSceneConstraintGUI(bool rIsSelected) { bool lIsDirty = false; #if UNITY_EDITOR //Color lLineColor = new Color(0f, 1f, 1f, 0.25f); //Color lFillColor = new Color(0f, 1f, 1f, 0.05f); Color lHandleColor = Handles.color; // Render out the twist limit if (_AllowTwist && _LimitTwist) { bool lIsLimitsDirty = HandlesHelper.JointTwistLimitsHandle(mBone, ref _MinTwistAngle, ref _MaxTwistAngle); if (lIsLimitsDirty) { lIsDirty = true; } } // Reset Handles.color = lHandleColor; #endif return(lIsDirty); }
/// <summary> /// Allow for rendering in the editor /// </summary> /// <returns></returns> public override bool OnSceneConstraintGUI(bool rIsSelected) { bool lIsDirty = false; #if UNITY_EDITOR IKBoneModifier lModifier = IKBoneModifier.Allocate(); lModifier.Swing = _Swing; lModifier.Twist = _Twist; bool lIsSwingDirty = HandlesHelper.JointSwingHandle(mBone, lModifier); if (lIsSwingDirty) { lIsDirty = true; } bool lIsTwistDirty = HandlesHelper.JointTwistHandle(mBone, lModifier); if (lIsTwistDirty) { lIsDirty = true; } if (lIsDirty) { _Swing = lModifier.Swing; _Twist = lModifier.Twist; mBone.SetLocalRotation(_Swing, _Twist, 1f); } IKBoneModifier.Release(lModifier); #endif return(lIsDirty); }
protected override void OnSceneGUI() { for (int i = 0; i < _pathMgr.points.Count; ++i) { Vector3 pos = _pathMgr.transform.TransformPoint(_pathMgr.points[i]); bool selected = (_curPathPointSelected == i); if (selected) { HandlesHelper.DrawXYZAxis(ref pos); } if (HandlesHelper.DrawDot(pos, Color.white)) { _curPathPointSelected = i; } _pathMgr.points[i] = _pathMgr.transform.InverseTransformPoint(pos); } MathTools.GetCatmullRomSplineFullPathPoints(_pathMgr.points, _pathMgr.loop, ref _fullPathPoints); Handles.color = Color.yellow; for (int i = 0; i < _fullPathPoints.Count - 1; i++) { Vector3 from = _pathMgr.transform.TransformPoint(_fullPathPoints[i]); Vector3 to = _pathMgr.transform.TransformPoint(_fullPathPoints[i + 1]); Handles.DrawLine(from, to); } }
void OnSceneGUI() { var targ = this.target as SphericalVisualSensor; if (targ == null) { return; } if (!targ.enabled) { return; } Handles.color = targ.SensorColor; Handles.matrix = Matrix4x4.TRS(targ.transform.position, targ.transform.rotation, Vector3.one); switch (targ.Mode) { case SphericalVisualSensor.Modes.Conical: { HandlesHelper.DrawWireSphere(Vector3.zero, Quaternion.identity, targ.Radius, targ.HorizontalAngle); if (targ.InnerRadius > 0f) { HandlesHelper.DrawWireSphere(Vector3.zero, Quaternion.identity, targ.InnerRadius, targ.HorizontalAngle); } if (targ.HorizontalAngle < 360f) { float dx = Mathf.Cos(targ.HorizontalAngle * Mathf.Deg2Rad / 2f); float dy = Mathf.Sqrt(1f - dx * dx); var v = new Vector3(0f, dy, dx); Handles.DrawLine(v * targ.InnerRadius, v * targ.Radius); v = new Vector3(0f, -dy, dx); Handles.DrawLine(v * targ.InnerRadius, v * targ.Radius); v = new Vector3(dy, 0f, dx); Handles.DrawLine(v * targ.InnerRadius, v * targ.Radius); v = new Vector3(-dy, 0f, dx); Handles.DrawLine(v * targ.InnerRadius, v * targ.Radius); } } break; case SphericalVisualSensor.Modes.Frustum: if (targ.HorizontalAngle >= 360f && targ.VerticalAngle >= 180f) { HandlesHelper.DrawWireSphere(Vector3.zero, Quaternion.identity, targ.Radius); if (targ.InnerRadius > 0f) { HandlesHelper.DrawWireSphere(Vector3.zero, Quaternion.identity, targ.InnerRadius); } } else { HandlesHelper.DrawWireSphereFrustum(targ.InnerRadius, targ.Radius, targ.HorizontalAngle, targ.VerticalAngle); } break; } }
static void DrawArrowCap(Vector3 localOffset, Quaternion localRotation, Transform bone) { HandlesHelper.Scope(() => { Vector3 worldPos = bone.TransformPoint(localOffset); Handles.matrix = Matrix4x4.TRS( worldPos, bone.rotation * localRotation, bone.localScale ); float size = 0.1f; //HandleUtility.GetHandleSize(worldPos); Handles.color = Color.blue.WithAlpha(0.5f); Handles.ArrowHandleCap( controlID: 0, position: Vector3.zero, rotation: Quaternion.LookRotation(Vector3.forward), size: size, eventType: EventType.Repaint ); Handles.color = Color.red.WithAlpha(0.5f); Handles.ArrowHandleCap( controlID: 0, position: Vector3.zero, rotation: Quaternion.LookRotation(Vector3.right), size: size, eventType: EventType.Repaint ); Handles.color = Color.green.WithAlpha(0.5f); Handles.ArrowHandleCap( controlID: 0, position: Vector3.zero, rotation: Quaternion.LookRotation(Vector3.up), size: size, eventType: EventType.Repaint ); }); }
/// <summary> /// Allows us to render joint info into the scene. This GUI is /// used for displaying and manipulating the joint itself. /// </summary> /// <returns>Reports if the object's value was changed</returns> public override bool OnSceneManipulatorGUI(IKBoneModifier rModifier) { #if UNITY_EDITOR //Quaternion lSwing = mBone.Swing; //Quaternion lTwist = mBone.Twist; bool lIsSwingDirty = HandlesHelper.JointSwingHandle(mBone, rModifier); if (lIsSwingDirty) { //rModifier.Swing = lSwing; rModifier.IsDirty = true; } bool lIsTwistDirty = HandlesHelper.JointTwistHandle(mBone, rModifier); if (lIsTwistDirty) { //rModifier.Twist = lTwist; rModifier.IsDirty = true; } if (rModifier.IsDirty) { // Before we go to far, see if we are within the joint limits. If not, // we need to go back to a good position. bool lIsInLimits = ApplyLimits(ref rModifier.Swing, ref rModifier.Twist); if (lIsInLimits || QuaternionExt.IsEqual(rModifier.Swing, Quaternion.identity)) { mLastSwing = rModifier.Swing; mLastTwist = rModifier.Twist; } else { rModifier.Swing = mLastSwing; rModifier.Twist = mLastTwist; } } #endif return(rModifier.IsDirty); }
/// <summary> /// Allows us to render joint info into the scene. This GUI is /// used for displaying and manipulating the joint itself. /// </summary> /// <returns></returns> public override bool OnSceneConstraintGUI(bool rIsSelected) { bool lIsDirty = false; #if UNITY_EDITOR //Vector3 lBoneForward = mBone.BoneForward; //Color lLineColor = new Color(0f, 1f, 1f, 0.25f); //Color lFillColor = new Color(0f, 1f, 1f, 0.05f); Color lHandleColor = Handles.color; //Quaternion lWorldBind = mBone.WorldBindRotation; // Render out the swing limits if (_LimitSwing) { bool lIsLimitsDirty = HandlesHelper.JointSwingAxisLimitsHandle(mBone, _SwingAxis, _MinSwingAngle, _MaxSwingAngle); if (lIsLimitsDirty) { lIsDirty = true; } } // Render out the twist limit if (_AllowTwist && _LimitTwist) { bool lIsLimitsDirty = HandlesHelper.JointTwistLimitsHandle(mBone, ref _MinTwistAngle, ref _MaxTwistAngle); if (lIsLimitsDirty) { lIsDirty = true; } } // Reset Handles.color = lHandleColor; #endif return(lIsDirty); }
private void DrawnNodeWithLinks(PatrolGraphNode PatrolGraphNode) { if (!this.ProcessedPatrolGraphNodeBuffer.Contains(PatrolGraphNode)) { Handles.DrawWireDisc(PatrolGraphNode.WorldPosition, Vector3.up, 1); Handles.Label(PatrolGraphNode.WorldPosition + new Vector3(0, 1, 0), PatrolGraphNode.name, MyEditorStyles.LabelWhite); if (PatrolGraphNode.WorldRotationEnabled) { HandlesHelper.DrawArrow(PatrolGraphNode.WorldPosition, PatrolGraphNode.WorldPosition + (Quaternion.Euler(PatrolGraphNode.WorldRotation) * Vector3.forward), Color.yellow); } foreach (var patrolGraphNodeLink in PatrolGraphNode.Links) { Color linkColor = Color.black; if (patrolGraphNodeLink.AIMovementSpeed == AIMovementSpeedAttenuationFactor.WALK) { linkColor = Color.green; } else if (patrolGraphNodeLink.AIMovementSpeed == AIMovementSpeedAttenuationFactor.RUN) { linkColor = Color.red; } HandlesHelper.DrawArrow(PatrolGraphNode.WorldPosition, patrolGraphNodeLink.PatrolGraphNode.WorldPosition, linkColor); } this.ProcessedPatrolGraphNodeBuffer.Add(PatrolGraphNode); foreach (var patrolGraphNodeLink in PatrolGraphNode.Links) { DrawnNodeWithLinks(patrolGraphNodeLink.PatrolGraphNode); } } }
/// <summary> /// Allow for rendering in the editor /// </summary> /// <returns></returns> public override bool OnSceneConstraintGUI(bool rIsSelected) { bool lIsDirty = false; #if UNITY_EDITOR float lPositionScale = 0.08f; if (Bone.Skeleton.EditorAutoScaleHandles) { lPositionScale = HandleUtility.GetHandleSize(Bone.Transform.position) * HandlesHelper.HandleScale * 0.9f; } Color lLineColor = new Color(0.94118f, 0.39608f, 0.13333f, 1f); Color lFillColor = new Color(0.94118f, 0.39608f, 0.13333f, 0.2f); Color lHandleColor = Handles.color; Quaternion lWorldBind = Bone.WorldBindRotation; // Render out the swing limits if (_LimitSwing) { Handles.color = Color.white; // If we have an invalid reach cone, report it for (int i = 0; i < mReachCones.Length; i++) { if (!mReachCones[i].IsVisiblePointValid) { lFillColor = new Color(1f, 0f, 0f, 1.0f); lLineColor = new Color(1f, 0f, 0f, 1.0f); } } for (int i = 0; i < mReachPoints.Length; i++) { int iPlus1 = (i + 1) % mReachPoints.Length; Vector3[] lVertices = new Vector3[4]; lVertices[0] = Bone.Transform.position; lVertices[1] = Bone.Transform.position; lVertices[2] = Bone.Transform.position + (lWorldBind * mReachPoints[i] * lPositionScale); lVertices[3] = Bone.Transform.position + (lWorldBind * mReachPoints[iPlus1] * lPositionScale); Handles.DrawSolidRectangleWithOutline(lVertices, lFillColor, lLineColor); //Log.ConsoleWrite("Color: " + lFillColor.ToString()); } } // Render out the twist limit if (_LimitTwist) { bool lIsLimitsDirty = HandlesHelper.JointTwistLimitsHandle(mBone, ref _MinTwistAngle, ref _MaxTwistAngle); if (lIsLimitsDirty) { lIsDirty = true; } } // Only show the boundary points if we're in editor mode if (mIsEditing) { float lHandleScale = HandleUtility.GetHandleSize(Bone.Transform.position) * HandlesHelper.HandleScale * 0.1f; // Render out the code that is limiting the swing for (int i = 0; i < BoundaryPoints.Count; i++) { GUI.color = new Color(0.72549f, 0.30588f, 0.10588f, 1f); Handles.Label(Bone.Transform.position + (lWorldBind * (BoundaryPoints[i] * (lPositionScale + 0.01f))), (i + 1).ToString()); Vector3 lWorldPosition = Bone.Transform.position + (lWorldBind * (BoundaryPoints[i] * lPositionScale)); Handles.color = (i == mSelectedPoint ? Color.yellow : new Color(0.94118f, 0.39608f, 0.13333f, 1f)); #if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 || UNITY_5_4 || UNITY_5_5 if (Handles.Button(lWorldPosition, Quaternion.identity, lHandleScale, lHandleScale, Handles.SphereCap)) #else if (Handles.Button(lWorldPosition, Quaternion.identity, lHandleScale, lHandleScale, Handles.SphereHandleCap)) #endif { lIsDirty = true; mSelectedPoint = i; } if (i == mSelectedPoint) { Vector3 lNewPosition = Handles.PositionHandle(lWorldPosition, Quaternion.identity); if (lNewPosition != lWorldPosition) { lIsDirty = true; lNewPosition = (lWorldBind.Conjugate() * (lNewPosition - Bone.Transform.position)) / lPositionScale; BoundaryPoints[i] = lNewPosition.normalized; BuildReachCones(); } } } } // Reset Handles.color = lHandleColor; #endif return(lIsDirty); }
public static void Draw(object drawableObject, Transform objectTransform, CommonGameConfigurations CommonGameConfigurations) { if (drawableObject.GetType().GetCustomAttribute <SceneHandleDrawAttribute>(true) != null) { var fields = ReflectionHelper.GetAllFields(drawableObject.GetType()); foreach (var field in fields) { var DrawConfigurationAttribute = field.GetCustomAttribute <DrawConfigurationAttribute>() as DrawConfigurationAttribute; if (DrawConfigurationAttribute != null) { var configurationAsset = CommonGameConfigurations.GetConfiguration(DrawConfigurationAttribute.ConfigurationType); if (configurationAsset != null) { configurationAsset.GetEntryTry((Enum)field.GetValue(drawableObject), out var configurationDataObject); if (configurationDataObject != null) { Draw(configurationDataObject, objectTransform, CommonGameConfigurations); } } } var DrawNestedAttribute = field.GetCustomAttribute <DrawNestedAttribute>() as DrawNestedAttribute; if (DrawNestedAttribute != null) { Draw(field.GetValue(drawableObject), objectTransform, CommonGameConfigurations); } var AbstractSceneHandleAttributes = field.GetCustomAttributes <AbstractSceneHandleAttribute>(true); if (AbstractSceneHandleAttributes != null) { foreach (var AbstractSceneHandleAttribute in AbstractSceneHandleAttributes) { if (AbstractSceneHandleAttribute.GetType() == typeof(WireArcAttribute)) { var WireArcAttribute = (WireArcAttribute)AbstractSceneHandleAttribute; var semiAngle = GetFieldValue <float>(drawableObject, field); SetupColors(WireArcAttribute.GetColor()); DrawLabel(field.Name, WireArcAttribute.Radius, objectTransform); Handles.DrawWireArc(objectTransform.position, Vector3.up, objectTransform.forward, semiAngle, WireArcAttribute.Radius); Handles.DrawWireArc(objectTransform.position, Vector3.up, objectTransform.forward, -semiAngle, WireArcAttribute.Radius); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireCircleAttribute)) { var WireCircleAttribute = (WireCircleAttribute)AbstractSceneHandleAttribute; var radius = GetFieldValue <float>(drawableObject, field); SetupColors(WireCircleAttribute.GetColor()); DrawLabel(field.Name, radius, objectTransform); DrawLabel(field.Name, radius, objectTransform); Handles.DrawWireDisc(objectTransform.position, objectTransform.up, radius); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireCircleWorldAttribute)) { var WireCircleWorldAttribute = (WireCircleWorldAttribute)AbstractSceneHandleAttribute; Vector3 worldPositionCenter = Vector3.zero; float radius; if (WireCircleWorldAttribute.UseTransform) { worldPositionCenter = objectTransform.position; } else { worldPositionCenter = GetPositionFromObject(drawableObject.GetType().GetField(WireCircleWorldAttribute.PositionFieldName).GetValue(drawableObject)); } if (!string.IsNullOrEmpty(WireCircleWorldAttribute.RadiusFieldName)) { radius = (float)drawableObject.GetType().GetField(WireCircleWorldAttribute.RadiusFieldName).GetValue(drawableObject); } else { radius = WireCircleWorldAttribute.Radius; } SetupColors(WireCircleWorldAttribute.GetColor()); DrawLabel(field.Name, radius, worldPositionCenter); DrawLabel(field.Name, radius, worldPositionCenter); Handles.DrawWireDisc(worldPositionCenter, Vector3.up, radius); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireBoxAttribute)) { var WireBoxAttribute = (WireBoxAttribute)AbstractSceneHandleAttribute; var center = (Vector3)drawableObject.GetType().GetField(WireBoxAttribute.CenterFieldName).GetValue(drawableObject); var size = (Vector3)drawableObject.GetType().GetField(WireBoxAttribute.SizeFieldName).GetValue(drawableObject); SetupColors(WireBoxAttribute.GetColor()); HandlesHelper.DrawBox(center, size, objectTransform, WireBoxAttribute.GetColor(), drawableObject.GetType().Name, MyEditorStyles.SceneDrawDynamicLabelStyle); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireFrustumAttribute)) { var WireFrustumAttribute = (WireFrustumAttribute)AbstractSceneHandleAttribute; var frustum = (FrustumV2)field.GetValue(drawableObject); SetupColors(WireFrustumAttribute.GetColor()); DrawFrustum(frustum, objectTransform, false); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireRoundedFrustumAttribute)) { var WireRoundedFrustumAttribute = (WireRoundedFrustumAttribute)AbstractSceneHandleAttribute; var frustum = (FrustumV2)field.GetValue(drawableObject); SetupColors(WireRoundedFrustumAttribute.GetColor()); DrawFrustum(frustum, objectTransform, true); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireDirectionalLineAttribute)) { var WireLineAttribute = (WireDirectionalLineAttribute)AbstractSceneHandleAttribute; var lineLength = (float)field.GetValue(drawableObject); SetupColors(WireLineAttribute.GetColor()); Handles.DrawLine(objectTransform.transform.position, objectTransform.transform.position + new Vector3(WireLineAttribute.dX, WireLineAttribute.dY, WireLineAttribute.dZ) * lineLength); } else if (AbstractSceneHandleAttribute.GetType() == typeof(WireArrowAttribute)) { var WireArrowAttribute = (WireArrowAttribute)AbstractSceneHandleAttribute; Vector3 Source = WireArrowAttribute.Source; Vector3 Target = WireArrowAttribute.Target; if (!string.IsNullOrEmpty(WireArrowAttribute.SourceFieldName)) { Source = GetPositionFromObject(drawableObject.GetType().GetField(WireArrowAttribute.SourceFieldName).GetValue(drawableObject)); } if (!string.IsNullOrEmpty(WireArrowAttribute.TargetFieldName)) { Target = GetPositionFromObject(drawableObject.GetType().GetField(WireArrowAttribute.TargetFieldName).GetValue(drawableObject)); } SetupColors(WireArrowAttribute.GetColor()); HandlesHelper.DrawArrow(Source, Target, WireArrowAttribute.GetColor(), WireArrowAttribute.ArrowSemiAngle, WireArrowAttribute.ArrowLength); } } } } } }
/// <summary> /// Allows us to render objects in the scene itself. This /// is only called when the scene window has focus /// </summary> private void OnSceneGUI() { bool lIsDirty = false; int lControlID = GUIUtility.GetControlID(FocusType.Passive); Event lEvent = Event.current; EventType lEventType = Event.current.GetTypeForControl(lControlID); // Track the mouse down position so we can test it when the // mouse is released if (lEventType == EventType.MouseDown && lEvent.button == 0) { mMouseDownPosition = lEvent.mousePosition; } // Test if a valid mouse up event has occurred else if (lEventType == EventType.MouseUp && lEvent.button == 0) { // Only process if the mouse didn't move if (mMouseDownPosition == lEvent.mousePosition) { if (GUIUtility.hotControl == lControlID) { GUIUtility.hotControl = 0; lEvent.Use(); } // Test if we hit a bone int lHitIndex = RaycastForBone(lEvent.mousePosition, true); if (lHitIndex >= 0) { BoneControllerBone lBone = mSkeleton.Bones[lHitIndex]; SelectBone(lBone); // The only way to really get the SceneView to repaint is to // force the dirty flag on the skeleton. It sucks, but... BoneController.EditorForceRepaint = true; } } } // Render out the skeleton as handles if (lEventType == EventType.Repaint && mSkeleton.EditorShowBones) { HandlesHelper.DrawSkeleton(mSkeleton, BoneControllerEditor.SkeletonColor, BoneControllerEditor.SkeletonColliderColor); } // Allow the joints to render to the scene if ((mSkeleton.EditorShowBoneLimits || mShowBones) && mSelectedBones.Count > 0) { for (int i = 0; i < mSelectedBones.Count; i++) { bool lIsBoneDirty = mSelectedBones[i].OnSceneGUI(true); if (lIsBoneDirty) { lIsDirty = true; } } } // Allow the motors to render to the scene or edit scene objects if (mShowMotors && mSelectedMotorIndex >= 0 && mSelectedMotorIndex < mSkeleton.Motors.Count) { bool lIsMotorDirty = mSkeleton.Motors[mSelectedMotorIndex].OnSceneGUI(mSelectedBones); if (lIsMotorDirty) { lIsDirty = true; } } // Render out the selected bones for (int i = 0; i < mSelectedBones.Count; i++) { HandlesHelper.DrawTransform(mSelectedBones[i].Transform.position, mSelectedBones[i].Transform.rotation * mSelectedBones[i].ToBoneForward, 1f, true, 0.8f); HandlesHelper.DrawTransform(mSelectedBones[i].Transform.position, mSelectedBones[i].Transform.rotation, 0.25f, true, 1.2f); HandlesHelper.DrawBone(mSelectedBones[i], BoneControllerEditor.SkeletonSelectedColor); } // If we had a major change, repaint the inspector and then // force the SceneView to redraw. Unfortunatley, the only way to consistantly // do this is to set the dirty flag of the main object. if (lIsDirty) { mIsDirty = true; } }
public static void Draw(SerializedProperty fieldProperty, GUIContent label, Transform self) { if (fieldProperty.hasMultipleDifferentValues) { return; } if (editingProperty != null && !IsEditingProperty(fieldProperty)) { return; } var kindProp = fieldProperty.FindPropertyRelative("kind"); var parentProp = fieldProperty.FindPropertyRelative("parent"); var childNameProp = fieldProperty.FindPropertyRelative("childName"); var findInactiveProp = fieldProperty.FindPropertyRelative("findInactive"); var findInChildrenProp = fieldProperty.FindPropertyRelative("findInChildren"); var directCompProp = fieldProperty.FindPropertyRelative("directComponent"); var localOffsetProp = fieldProperty.FindPropertyRelative("_localOffset"); var localRotProp = fieldProperty.FindPropertyRelative("_localRotation"); bool anyNull = kindProp == null || parentProp == null || childNameProp == null || findInactiveProp == null || findInChildrenProp == null || directCompProp == null || localOffsetProp == null || localRotProp == null; if (anyNull) { Dbg.LogWarnOnceRelease( Dbg.Context(fieldProperty.propertyPath), "Property with path {0} lacked a field. Are you sure it's a LocalOffsetField?", fieldProperty.propertyPath ); return; } Transform bone = FindCompField <Transform> .Get( kindProp.EnumValue <FindCompKind>(), (Transform)parentProp.objectReferenceValue, self, childNameProp.stringValue, findInChildrenProp.boolValue, findInactiveProp.boolValue, (Transform)directCompProp.objectReferenceValue ); if (bone == null) { return; } var localOffset = localOffsetProp.vector3Value; var localRotation = Quaternion.Euler(localRotProp.vector3Value); EditorHelper.RegisterUndo("Transformed Effect", fieldProperty.serializedObject.targetObject, undoHelper ); Vector3 worldPos = bone.TransformPoint(localOffset); bool clicked = false; HandlesHelper.Scope(() => { if (IsEditingProperty(fieldProperty)) { Handles.color = Color.green; } if (editingProperty == null) { clicked = Handles.Button( worldPos, Quaternion.identity, size: 0.05f, pickSize: 0.05f, capFunction: Handles.SphereHandleCap ); } else { Handles.SphereHandleCap( controlID: 0, position: worldPos, rotation: Quaternion.identity, size: 0.05f, eventType: EventType.Repaint ); } }); if (clicked) { undoHelper.worldSpaceRot = Quaternion.identity; editingProperty = fieldProperty; if (Tools.current != Tool.Move && Tools.current != Tool.Rotate) { Tools.current = Tool.Move; } } GUIStyle style = EditorStyles.toolbarTextField; style.CalcSize(label); Handles.Label(worldPos, label, style); if (!IsEditingProperty(fieldProperty)) { return; } fieldProperty.serializedObject.Update(); HandlesHelper.Scope(() => { if (Tools.current == Tool.Rotate) { if (Tools.pivotRotation == PivotRotation.Local) { Handles.matrix = bone.localToWorldMatrix; } else { Handles.matrix = Matrix4x4.TRS( bone.TransformPoint(localOffset), Quaternion.identity, bone.localScale ); } DrawArrowCap(localOffset, localRotation, bone); Quaternion newLocalRot = localRotation; if (Tools.pivotRotation == PivotRotation.Global) { var newWorldSpaceRot = Handles.RotationHandle(undoHelper.worldSpaceRot, Vector3.zero); // Difference between the the new and the old world space rotation var diff = Quaternion.Inverse(undoHelper.worldSpaceRot) * newWorldSpaceRot; if (diff != Quaternion.identity) { // Convert local rot to world Quaternion rotInWorld = bone.rotation * localRotation; // Apply world difference rotInWorld = diff * rotInWorld; // Convert back to local space newLocalRot = Quaternion.Inverse(bone.rotation) * rotInWorld; undoHelper.worldSpaceRot = newWorldSpaceRot; } } else { newLocalRot = Handles.RotationHandle(localRotation, localOffset); } if (localRotation != newLocalRot) { localRotProp.vector3Value = newLocalRot.eulerAngles; } } else if (Tools.current == Tool.Move) { Handles.matrix = bone.localToWorldMatrix; var rot = localRotation; if (Tools.pivotRotation == PivotRotation.Global) { rot = Quaternion.LookRotation( bone.InverseTransformDirection(Vector3.forward), bone.InverseTransformDirection(Vector3.up) ); } var pos = Handles.PositionHandle(localOffset, rot); if (localOffset != pos) { localOffsetProp.vector3Value = pos; } } }); fieldProperty.serializedObject.ApplyModifiedProperties(); DrawEditingWarning(); Event e = Event.current; if (e.type == EventType.keyUp) { if (e.keyCode == KeyCode.Escape) { StopEditing(); } } }