@@ -35,6 +35,119 @@ static void Draw3rdPersonGizmos(Cinemachine3rdPersonFollow target, GizmoType sel
35
35
Gizmos . color = originalGizmoColour ;
36
36
}
37
37
}
38
+
39
+ #if UNITY_2021_2_OR_NEWER
40
+ protected virtual void OnEnable ( )
41
+ {
42
+ CinemachineSceneToolUtility . RegisterTool ( typeof ( FollowOffsetTool ) ) ;
43
+ }
44
+
45
+ protected virtual void OnDisable ( )
46
+ {
47
+ CinemachineSceneToolUtility . UnregisterTool ( typeof ( FollowOffsetTool ) ) ;
48
+ }
49
+
50
+ void OnSceneGUI ( )
51
+ {
52
+ DrawSceneTools ( ) ;
53
+ }
54
+
55
+ void DrawSceneTools ( )
56
+ {
57
+ var thirdPerson = Target ;
58
+ if ( thirdPerson == null || ! thirdPerson . IsValid )
59
+ {
60
+ return ;
61
+ }
62
+
63
+ if ( CinemachineSceneToolUtility . IsToolActive ( typeof ( FollowOffsetTool ) ) )
64
+ {
65
+ var originalColor = Handles . color ;
66
+
67
+ thirdPerson . GetRigPositions ( out var followTargetPosition , out var shoulderPosition ,
68
+ out var armPosition ) ;
69
+ var followTargetRotation = thirdPerson . FollowTargetRotation ;
70
+ var targetForward = followTargetRotation * Vector3 . forward ;
71
+ var heading = Cinemachine3rdPersonFollow . GetHeading (
72
+ followTargetRotation , thirdPerson . VirtualCamera . State . ReferenceUp ) ;
73
+
74
+ EditorGUI . BeginChangeCheck ( ) ;
75
+ // shoulder handle
76
+ var sHandleMinId = GUIUtility . GetControlID ( FocusType . Passive ) ; // TODO: KGB workaround until id is exposed
77
+ var newShoulderPosition = Handles . PositionHandle ( shoulderPosition , heading ) ;
78
+ var sHandleMaxId = GUIUtility . GetControlID ( FocusType . Passive ) ; // TODO: KGB workaround until id is exposed
79
+
80
+ Handles . color = Handles . preselectionColor ;
81
+ // arm handle
82
+ var followUp = followTargetRotation * Vector3 . up ;
83
+ var aHandleId = GUIUtility . GetControlID ( FocusType . Passive ) ;
84
+ var newArmPosition = Handles . Slider ( aHandleId , armPosition , followUp ,
85
+ CinemachineSceneToolHelpers . CubeHandleCapSize ( armPosition ) , Handles . CubeHandleCap , 0.5f ) ;
86
+
87
+ // cam distance handle
88
+ var camDistance = thirdPerson . CameraDistance ;
89
+ var camPos = armPosition - targetForward * camDistance ;
90
+ var cdHandleId = GUIUtility . GetControlID ( FocusType . Passive ) ;
91
+ var newCamPos = Handles . Slider ( cdHandleId , camPos , targetForward ,
92
+ CinemachineSceneToolHelpers . CubeHandleCapSize ( camPos ) , Handles . CubeHandleCap , 0.5f ) ;
93
+ if ( EditorGUI . EndChangeCheck ( ) )
94
+ {
95
+ // Modify via SerializedProperty for OnValidate to get called automatically, and scene repainting too
96
+ var so = new SerializedObject ( thirdPerson ) ;
97
+
98
+ var shoulderOffset = so . FindProperty ( ( ) => thirdPerson . ShoulderOffset ) ;
99
+ shoulderOffset . vector3Value +=
100
+ CinemachineSceneToolHelpers . PositionHandleDelta ( heading , newShoulderPosition , shoulderPosition ) ;
101
+ var verticalArmLength = so . FindProperty ( ( ) => thirdPerson . VerticalArmLength ) ;
102
+ verticalArmLength . floatValue +=
103
+ CinemachineSceneToolHelpers . SliderHandleDelta ( newArmPosition , armPosition , followUp ) ;
104
+ var cameraDistance = so . FindProperty ( ( ) => thirdPerson . CameraDistance ) ;
105
+ cameraDistance . floatValue -=
106
+ CinemachineSceneToolHelpers . SliderHandleDelta ( newCamPos , camPos , targetForward ) ;
107
+
108
+ so . ApplyModifiedProperties ( ) ;
109
+ }
110
+
111
+ var isDragged = IsHandleDragged ( sHandleMinId , sHandleMaxId , shoulderPosition , "Shoulder Offset "
112
+ + thirdPerson . ShoulderOffset . ToString ( "F1" ) , followTargetPosition , shoulderPosition ) ;
113
+ isDragged |= IsHandleDragged ( aHandleId , aHandleId , armPosition , "Vertical Arm Length ("
114
+ + thirdPerson . VerticalArmLength . ToString ( "F1" ) + ")" , shoulderPosition , armPosition ) ;
115
+ isDragged |= IsHandleDragged ( cdHandleId , cdHandleId , camPos , "Camera Distance ("
116
+ + camDistance . ToString ( "F1" ) + ")" , armPosition , camPos ) ;
117
+
118
+ CinemachineSceneToolHelpers . SoloOnDrag ( isDragged , thirdPerson . VirtualCamera , sHandleMaxId ) ;
119
+
120
+ Handles . color = originalColor ;
121
+ }
122
+
123
+ // local function that draws label and guide lines, and returns true if a handle has been dragged
124
+ static bool IsHandleDragged
125
+ ( int handleMinId , int handleMaxId , Vector3 labelPos , string text , Vector3 lineStart , Vector3 lineEnd )
126
+ {
127
+ bool handleIsDragged ;
128
+ bool handleIsDraggedOrHovered ;
129
+ if ( handleMinId == handleMaxId ) {
130
+ handleIsDragged = GUIUtility . hotControl == handleMinId ;
131
+ handleIsDraggedOrHovered = handleIsDragged || HandleUtility . nearestControl == handleMinId ;
132
+ }
133
+ else
134
+ {
135
+ handleIsDragged = handleMinId < GUIUtility . hotControl && GUIUtility . hotControl < handleMaxId ;
136
+ handleIsDraggedOrHovered = handleIsDragged ||
137
+ ( handleMinId < HandleUtility . nearestControl && HandleUtility . nearestControl < handleMaxId ) ;
138
+ }
139
+
140
+ if ( handleIsDraggedOrHovered )
141
+ CinemachineSceneToolHelpers . DrawLabel ( labelPos , text ) ;
142
+
143
+ Handles . color = handleIsDraggedOrHovered ?
144
+ Handles . selectedColor : CinemachineSceneToolHelpers . HelperLineDefaultColor ;
145
+ Handles . DrawLine ( lineStart , lineEnd , CinemachineSceneToolHelpers . LineThickness ) ;
146
+
147
+ return handleIsDragged ;
148
+ }
149
+ }
150
+ #endif
38
151
}
39
152
}
40
153
0 commit comments