static Vector3 DoPlanarHandle( int id, int planePrimaryAxis, Vector3 position, Vector3 offset, Quaternion rotation, float handleSize, float cameraLerp, Vector3 viewVectorDrawSpace, PositionHandleParam.Orientation orientation) { var positionOffset = offset; var axis1index = planePrimaryAxis; var axis2index = (axis1index + 1) % 3; var axisNormalIndex = (axis1index + 2) % 3; Color prevColor = Handles.color; bool isDisabled = !GUI.enabled; color = isDisabled ? staticColor : GetColorByAxis(axisNormalIndex); color = Color.Lerp(color, Color.clear, cameraLerp); var updateOpacityFillColor = false; if (GUIUtility.hotControl == id) { color = selectedColor; } else if (HandleUtility.nearestControl == id && !Event.current.alt) { color = preselectionColor; } else { updateOpacityFillColor = true; } color = ToActiveColorSpace(color); // NOTE: The planar transform handles always face toward the camera so they won't // obscure each other (unlike the X, Y, and Z axis handles which always face in the // positive axis directions). Whenever the octant that the camera is in (relative to // to the transform tool) changes, we need to move the planar transform handle // positions to the correct octant. // Comments below assume axis1 is X and axis2 is Z to make it easier to visualize things. // Shift the planar transform handle in the positive direction by half its // handleSize so that it doesn't overlap in the center of the transform gizmo, // and also move the handle origin into the octant that the camera is in. // Don't update the actant while dragging to avoid too much distraction. if (!currentlyDragging) { switch (orientation) { case PositionHandleParam.Orientation.Camera: // Offset the X position of the handle in negative direction if camera is in the -X octants; otherwise positive. // Test against -0.01 instead of 0 to give a little bias to the positive quadrants. This looks better in axis views. s_PlanarHandlesOctant[axis1index] = (viewVectorDrawSpace[axis1index] > 0.01f ? -1 : 1); // Likewise with the other axis. s_PlanarHandlesOctant[axis2index] = (viewVectorDrawSpace[axis2index] > 0.01f ? -1 : 1); break; case PositionHandleParam.Orientation.Signed: s_PlanarHandlesOctant[axis1index] = 1; s_PlanarHandlesOctant[axis2index] = 1; break; } } Vector3 handleOffset = s_PlanarHandlesOctant; // Zero out the offset along the normal axis. handleOffset[axisNormalIndex] = 0; positionOffset = rotation * Vector3.Scale(positionOffset, handleOffset); // Rotate and scale the offset handleOffset = rotation * (handleOffset * handleSize * 0.5f); // Calculate 3 axes Vector3 axis1 = Vector3.zero; Vector3 axis2 = Vector3.zero; Vector3 axisNormal = Vector3.zero; axis1[axis1index] = 1; axis2[axis2index] = 1; axisNormal[axisNormalIndex] = 1; axis1 = rotation * axis1; axis2 = rotation * axis2; axisNormal = rotation * axisNormal; // Draw the "filler" color for the handle verts[0] = position + positionOffset + handleOffset + (axis1 + axis2) * handleSize * 0.5f; verts[1] = position + positionOffset + handleOffset + (-axis1 + axis2) * handleSize * 0.5f; verts[2] = position + positionOffset + handleOffset + (-axis1 - axis2) * handleSize * 0.5f; verts[3] = position + positionOffset + handleOffset + (axis1 - axis2) * handleSize * 0.5f; Color faceColor = updateOpacityFillColor ? new Color(color.r, color.g, color.b, 0.1f) : color; faceColor = ToActiveColorSpace(faceColor); Handles.DrawSolidRectangleWithOutline(verts, faceColor, Color.clear); // And then render the handle itself (this is the colored outline) position = Slider2D(id, position, handleOffset + positionOffset, axisNormal, axis1, axis2, handleSize * 0.5f, RectangleHandleCap, GridSnapping.active ? Vector2.zero : new Vector2(EditorSnapSettings.move[axis1index], EditorSnapSettings.move[axis2index]), false); Handles.color = prevColor; return(position); }
/// <summary> /// Calls the methods in its invocation list when show the Inspector /// </summary> public override void OnInspectorGUI() { var camera = Camera.main; if (camera == null) { Debug.LogError("Light Anchor: At least one camera must be tagged as MainCamera"); return; } if (IsCacheInvalid(manipulator)) { manipulator.SynchronizeOnTransform(camera); UpdateCache(); } // anchor is cached for it cannot be changed from the inspector, // we have a dedicated editor tool to move the anchor var anchor = manipulator.anchorPosition; bool yawChanged = false; bool pitchChanged = false; bool rollChanged = false; bool distanceChanged = false; bool frameChanged = false; bool upChanged = false; using (var change = new EditorGUI.ChangeCheckScope()) { EditorGUILayout.Space(); float widgetHeight = EditorGUIUtility.singleLineHeight * 5f; float oldValue; using (new EditorGUILayout.HorizontalScope()) { Color usedColor; { var localRect = EditorGUILayout.GetControlRect(false, widgetHeight); oldValue = m_Yaw; usedColor = Color.green; usedColor.a = 0.2f; m_Yaw = AngleField(localRect, "Yaw", m_Yaw, 90, usedColor, true); } yawChanged = oldValue != m_Yaw; { var localRect = EditorGUILayout.GetControlRect(false, widgetHeight); oldValue = m_Pitch; usedColor = Color.blue; usedColor.a = 0.2f; m_Pitch = AngleField(localRect, "Pitch", m_Pitch, 180, usedColor, true); } pitchChanged = oldValue != m_Pitch; { var localRect = EditorGUILayout.GetControlRect(false, widgetHeight); oldValue = m_Roll; usedColor = Color.grey; usedColor.a = 0.2f; bool enabledKnob = true; m_Roll = AngleField(localRect, "Roll", m_Roll, -90, usedColor, enabledKnob); } rollChanged = oldValue != m_Roll; } EditorGUILayout.Space(); Rect angleRect = EditorGUILayout.GetControlRect(true, EditorGUI.GetPropertyHeight(SerializedPropertyType.Vector3, EditorGUIUtility.TrTextContent(""))); float[] angles = new float[3] { m_Yaw, m_Pitch, m_Roll }; EditorGUI.BeginChangeCheck(); EditorGUI.MultiFloatField(angleRect, LightAnchorStyles.angleSubContent, angles); const float eps = 1e-4f; if (EditorGUI.EndChangeCheck()) { if (Mathf.Abs(angles[0] - m_Yaw) > eps) { m_Yaw = angles[0]; yawChanged = true; } if (Mathf.Abs(angles[1] - m_Pitch) > eps) { m_Pitch = angles[1]; pitchChanged = true; } if (Mathf.Abs(angles[2] - m_Roll) > eps) { m_Roll = angles[2]; rollChanged = true; } } EditorGUILayout.Space(); oldValue = manipulator.distance; m_Distance = EditorGUILayout.FloatField(LightAnchorStyles.distanceProperty, manipulator.distance); distanceChanged = oldValue != m_Distance; var dropRect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight); LightAnchor.UpDirection newSpace = (LightAnchor.UpDirection)EditorGUI.EnumPopup(dropRect, LightAnchorStyles.upDirectionProperty, manipulator.frameSpace); upChanged = manipulator.frameSpace != newSpace; manipulator.frameSpace = newSpace; if (upChanged) { manipulator.SynchronizeOnTransform(camera); UpdateCache(); } frameChanged = yawChanged || pitchChanged || rollChanged || distanceChanged; if (m_FoldoutPreset = EditorGUILayout.Foldout(m_FoldoutPreset, "Common")) { Color cachedColor = GUI.backgroundColor; GUI.backgroundColor = LightAnchorStyles.BackgroundIconColor(); var inspectorWidth = EditorGUIUtility.currentViewWidth - LightAnchorStyles.inspectorWidthPadding; var presetButtonWidth = GUILayout.Width(inspectorWidth / LightAnchorStyles.presetButtonCount); var presetButtonHeight = GUILayout.Height(inspectorWidth / LightAnchorStyles.presetButtonCount); using (new EditorGUILayout.HorizontalScope()) { bool rectFound = false; Rect rect = new Rect(); if (GUILayout.Button(LightAnchorStyles.presetTextureRimLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 135; m_Pitch = 0; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw - 135.0f) < eps && Mathf.Abs(m_Pitch - 0.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureKickLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 100; m_Pitch = 10; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw - 100.0f) < eps && Mathf.Abs(m_Pitch - 10.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureBounceLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 30; m_Pitch = -30; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw - 30.0f) < eps && Mathf.Abs(m_Pitch + 30.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureFillLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 35; m_Pitch = 35; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw - 35.0f) < eps && Mathf.Abs(m_Pitch - 35.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureHair, presetButtonWidth, presetButtonHeight)) { m_Yaw = 0; m_Pitch = 110; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw - 0.0f) < eps && Mathf.Abs(m_Pitch - 110.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureFillRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -35; m_Pitch = 35; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw + 35.0f) < eps && Mathf.Abs(m_Pitch - 35.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureBounceRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -30; m_Pitch = -30; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw + 30.0f) < eps && Mathf.Abs(m_Pitch + 30.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureKickRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -100; m_Pitch = 10; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw + 100.0f) < eps && Mathf.Abs(m_Pitch - 10.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureRimRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -135; m_Pitch = 0; yawChanged = true; pitchChanged = true; frameChanged = true; } if (Mathf.Abs(m_Yaw + 135.0f) < eps && Mathf.Abs(m_Pitch - 0.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (rectFound) { Handles.DrawSolidRectangleWithOutline(rect, LightAnchorStyles.totalTransparentColor, LightAnchorStyles.hoverColor); } GUILayout.FlexibleSpace(); } GUI.backgroundColor = cachedColor; } if (frameChanged) { LightAnchor manipulator = target as LightAnchor; if (upChanged) { manipulator.SynchronizeOnTransform(camera); } Undo.RecordObjects(new UnityEngine.Object[] { manipulator.transform }, "Reset Light Anchor Transform"); if (yawChanged) { manipulator.yaw = m_Yaw; } if (pitchChanged) { manipulator.pitch = m_Pitch; } if (rollChanged) { manipulator.roll = m_Roll; } if (distanceChanged) { manipulator.distance = m_Distance; } manipulator.UpdateTransform(camera, anchor); IsCacheInvalid(manipulator); } } }
/// <summary> /// Calls the methods in its invocation list when show the Inspector /// </summary> public override void OnInspectorGUI() { var camera = Camera.main; if (camera == null) { EditorGUILayout.HelpBox("Light Anchor: At least one camera must be tagged as MainCamera", MessageType.Error); return; } if (IsCacheInvalid(manipulator)) { manipulator.SynchronizeOnTransform(camera); UpdateCache(); } // anchor is cached for it cannot be changed from the inspector, // we have a dedicated editor tool to move the anchor var anchor = manipulator.anchorPosition; bool yawChanged = false; bool pitchChanged = false; bool rollChanged = false; bool distanceChanged = false; bool positionOverrideChanged = false; bool upChanged = false; using (var change = new EditorGUI.ChangeCheckScope()) { EditorGUILayout.Space(); float widgetHeight = EditorGUIUtility.singleLineHeight * 5f; using (new EditorGUILayout.HorizontalScope()) { Color usedColor; EditorGUI.BeginChangeCheck(); { var localRect = EditorGUILayout.GetControlRect(false, widgetHeight); usedColor = Color.green; usedColor.a = 0.2f; m_Yaw = AngleField(localRect, "Yaw", m_Yaw, 90, usedColor, true); } yawChanged = EditorGUI.EndChangeCheck(); EditorGUI.BeginChangeCheck(); { var localRect = EditorGUILayout.GetControlRect(false, widgetHeight); usedColor = Color.blue; usedColor.a = 0.2f; m_Pitch = AngleField(localRect, "Pitch", m_Pitch, 180, usedColor, true); } pitchChanged = EditorGUI.EndChangeCheck(); EditorGUI.BeginChangeCheck(); { var localRect = EditorGUILayout.GetControlRect(false, widgetHeight); usedColor = Color.grey; usedColor.a = 0.2f; bool enabledKnob = true; m_Roll = AngleField(localRect, "Roll", m_Roll, -90, usedColor, enabledKnob); } rollChanged = EditorGUI.EndChangeCheck(); } EditorGUILayout.Space(); Rect angleRect = EditorGUILayout.GetControlRect(true, EditorGUI.GetPropertyHeight(SerializedPropertyType.Vector3, EditorGUIUtility.TrTextContent(""))); float[] angles = new float[3] { m_Yaw, m_Pitch, m_Roll }; EditorGUI.BeginChangeCheck(); EditorGUI.MultiFloatField(angleRect, LightAnchorStyles.angleSubContent, angles); const float eps = 1e-4f; if (EditorGUI.EndChangeCheck()) { if (Mathf.Abs(angles[0] - m_Yaw) > eps) { m_Yaw = angles[0]; yawChanged = true; } if (Mathf.Abs(angles[1] - m_Pitch) > eps) { m_Pitch = angles[1]; pitchChanged = true; } if (Mathf.Abs(angles[2] - m_Roll) > eps) { m_Roll = angles[2]; rollChanged = true; } } EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_DistanceProperty, LightAnchorStyles.distanceProperty); if (distanceChanged = EditorGUI.EndChangeCheck()) { m_DistanceProperty.floatValue = Mathf.Min(m_DistanceProperty.floatValue, LightAnchor.k_MaxDistance); } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_FrameSpaceProperty, LightAnchorStyles.upDirectionProperty); upChanged = EditorGUI.EndChangeCheck(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_AnchorPositionOverrideProperty, LightAnchorStyles.anchorPositionOverrideProperty); positionOverrideChanged = EditorGUI.EndChangeCheck(); if (m_AnchorPositionOverrideProperty.objectReferenceValue != null) { EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_AnchorPositionOffsetProperty, LightAnchorStyles.anchorPositionOffsetProperty); positionOverrideChanged |= EditorGUI.EndChangeCheck(); EditorGUI.indentLevel--; } if (m_FoldoutPreset = EditorGUILayout.Foldout(m_FoldoutPreset, "Common")) { Color cachedColor = GUI.backgroundColor; GUI.backgroundColor = LightAnchorStyles.BackgroundIconColor(); var inspectorWidth = EditorGUIUtility.currentViewWidth - LightAnchorStyles.inspectorWidthPadding; var presetButtonWidth = GUILayout.Width(inspectorWidth / LightAnchorStyles.presetButtonCount); var presetButtonHeight = GUILayout.Height(inspectorWidth / LightAnchorStyles.presetButtonCount); using (new EditorGUILayout.HorizontalScope()) { bool rectFound = false; Rect rect = new Rect(); if (GUILayout.Button(LightAnchorStyles.presetTextureRimLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 135; m_Pitch = 0; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw - 135.0f) < eps && Mathf.Abs(m_Pitch - 0.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureKickLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 100; m_Pitch = 10; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw - 100.0f) < eps && Mathf.Abs(m_Pitch - 10.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureBounceLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 30; m_Pitch = -30; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw - 30.0f) < eps && Mathf.Abs(m_Pitch + 30.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureFillLeft, presetButtonWidth, presetButtonHeight)) { m_Yaw = 35; m_Pitch = 35; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw - 35.0f) < eps && Mathf.Abs(m_Pitch - 35.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureHair, presetButtonWidth, presetButtonHeight)) { m_Yaw = 0; m_Pitch = 110; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw - 0.0f) < eps && Mathf.Abs(m_Pitch - 110.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureFillRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -35; m_Pitch = 35; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw + 35.0f) < eps && Mathf.Abs(m_Pitch - 35.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureBounceRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -30; m_Pitch = -30; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw + 30.0f) < eps && Mathf.Abs(m_Pitch + 30.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureKickRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -100; m_Pitch = 10; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw + 100.0f) < eps && Mathf.Abs(m_Pitch - 10.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (GUILayout.Button(LightAnchorStyles.presetTextureRimRight, presetButtonWidth, presetButtonHeight)) { m_Yaw = -135; m_Pitch = 0; yawChanged = true; pitchChanged = true; } if (Mathf.Abs(m_Yaw + 135.0f) < eps && Mathf.Abs(m_Pitch - 0.0f) < eps) { rect = GUILayoutUtility.GetLastRect(); rectFound = true; } if (rectFound) { Handles.DrawSolidRectangleWithOutline(rect, LightAnchorStyles.totalTransparentColor, LightAnchorStyles.hoverColor); } GUILayout.FlexibleSpace(); } GUI.backgroundColor = cachedColor; } if (upChanged) { Undo.RecordObjects(new UnityEngine.Object[] { target, manipulator.transform }, "Light Anchor Change"); manipulator.frameSpace = (LightAnchor.UpDirection)m_FrameSpaceProperty.intValue; manipulator.SynchronizeOnTransform(camera); UpdateCache(); } if (yawChanged || pitchChanged || rollChanged || distanceChanged || positionOverrideChanged) { Undo.RecordObjects(new UnityEngine.Object[] { target, manipulator.transform }, "Light Anchor Change"); if (yawChanged) { manipulator.yaw = m_Yaw; } if (pitchChanged) { manipulator.pitch = m_Pitch; } if (rollChanged) { manipulator.roll = m_Roll; } if (distanceChanged) { manipulator.distance = m_DistanceProperty.floatValue; } if (positionOverrideChanged) { var newTransform = m_AnchorPositionOverrideProperty.objectReferenceValue as Transform; if (newTransform != null) { // Check that the assigned transform is not child of the light anchor, otherwise it would cause problems when moving the light position if (newTransform.IsChildOf(manipulator.transform)) { Debug.LogError($"Can't assign '{newTransform.name}' because it's a child of the Light Anchor component"); } else { manipulator.anchorPositionOverride = newTransform; manipulator.anchorPositionOffset = m_AnchorPositionOffsetProperty.vector3Value; float newDistance = Vector3.Distance(manipulator.transform.position, manipulator.anchorPosition); // Orient the object to face the new override position manipulator.SynchronizeOnTransform(camera); // And adjust it's distance to avoid modifying it's position. manipulator.distance = newDistance; } } else { manipulator.anchorPositionOverride = newTransform; } } if (manipulator.anchorPositionOverride != null) { anchor = manipulator.anchorPosition; } manipulator.UpdateTransform(camera, anchor); IsCacheInvalid(manipulator); } } }