Modify: 카메라 컨트롤러 관련 스크립트 업데이트
This commit is contained in:
parent
7a4e05d575
commit
2cfe3d7f5f
@ -439,6 +439,9 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
case "get_drone_state":
|
||||
HandleGetDroneState(service);
|
||||
break;
|
||||
case "toggle_default_blend":
|
||||
HandleToggleDefaultBlend();
|
||||
break;
|
||||
|
||||
// 아이템
|
||||
case "toggle_item":
|
||||
@ -642,6 +645,13 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
HandleGetDroneState(service);
|
||||
}
|
||||
|
||||
private void HandleToggleDefaultBlend()
|
||||
{
|
||||
if (cameraManager == null) return;
|
||||
cameraManager.ToggleDefaultBlend();
|
||||
// ToggleDefaultBlend 내부에서 NotifyCameraChanged를 호출하여 모든 클라이언트에 브로드캐스트됩니다.
|
||||
}
|
||||
|
||||
private void HandleGetDroneState(StreamDeckService service)
|
||||
{
|
||||
if (cameraManager == null) return;
|
||||
|
||||
@ -365,6 +365,61 @@ public class CameraManager : MonoBehaviour, IController
|
||||
streamDeckManager.NotifyCameraChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main Camera에 달린 CinemachineBrain의 Default Blend 스타일을 Cut ↔ EaseInOut 로 토글합니다.
|
||||
/// </summary>
|
||||
public void ToggleDefaultBlend()
|
||||
{
|
||||
var brain = GetCinemachineBrain();
|
||||
if (brain == null)
|
||||
{
|
||||
Debug.LogWarning("[CameraManager] CinemachineBrain을 찾을 수 없습니다. Main Camera에 추가되어 있어야 합니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
var blend = brain.DefaultBlend;
|
||||
blend.Style = (blend.Style == CinemachineBlendDefinition.Styles.Cut)
|
||||
? CinemachineBlendDefinition.Styles.EaseInOut
|
||||
: CinemachineBlendDefinition.Styles.Cut;
|
||||
brain.DefaultBlend = blend;
|
||||
|
||||
NotifyStreamDeckCameraStateChanged();
|
||||
}
|
||||
|
||||
public bool IsDefaultBlendCut
|
||||
{
|
||||
get
|
||||
{
|
||||
var brain = GetCinemachineBrain();
|
||||
return brain != null && brain.DefaultBlend.Style == CinemachineBlendDefinition.Styles.Cut;
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultBlendStyleName
|
||||
{
|
||||
get
|
||||
{
|
||||
var brain = GetCinemachineBrain();
|
||||
return brain != null ? brain.DefaultBlend.Style.ToString() : "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private CinemachineBrain cachedBrain;
|
||||
|
||||
public CinemachineBrain GetCinemachineBrain()
|
||||
{
|
||||
if (cachedBrain != null) return cachedBrain;
|
||||
|
||||
var mainCam = Camera.main;
|
||||
if (mainCam != null)
|
||||
{
|
||||
cachedBrain = mainCam.GetComponent<CinemachineBrain>();
|
||||
if (cachedBrain != null) return cachedBrain;
|
||||
}
|
||||
cachedBrain = FindFirstObjectByType<CinemachineBrain>();
|
||||
return cachedBrain;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Initialization
|
||||
@ -1175,7 +1230,9 @@ public class CameraManager : MonoBehaviour, IController
|
||||
camera_name = currentPreset.virtualCamera?.gameObject.name ?? "Unknown",
|
||||
preset_name = currentPreset.presetName,
|
||||
total_cameras = cameraPresets.Count,
|
||||
is_drone_mode = IsDroneModeActive
|
||||
is_drone_mode = IsDroneModeActive,
|
||||
default_blend_style = DefaultBlendStyleName,
|
||||
is_default_blend_cut = IsDefaultBlendCut
|
||||
};
|
||||
}
|
||||
|
||||
@ -1203,6 +1260,8 @@ public class CameraManager : MonoBehaviour, IController
|
||||
public string preset_name;
|
||||
public int total_cameras;
|
||||
public bool is_drone_mode;
|
||||
public string default_blend_style;
|
||||
public bool is_default_blend_cut;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -1253,6 +1312,10 @@ public class CameraManager : MonoBehaviour, IController
|
||||
// 드론 상태는 GetCurrentCameraState()의 is_drone_mode로 반환됨
|
||||
break;
|
||||
|
||||
case "toggle_default_blend":
|
||||
ToggleDefaultBlend();
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.LogWarning($"[CameraManager] 알 수 없는 액션: {actionId}");
|
||||
break;
|
||||
|
||||
@ -213,6 +213,23 @@ public class RuntimeControlPanelManager
|
||||
return;
|
||||
}
|
||||
|
||||
// Default Blend 토글 (Cinemachine Brain)
|
||||
var blendRow = new VisualElement();
|
||||
blendRow.AddToClassList("action-row");
|
||||
|
||||
bool isCut = cam.IsDefaultBlendCut;
|
||||
string styleName = cam.DefaultBlendStyleName;
|
||||
var blendBtn = MakeButton(
|
||||
$"Blend: {styleName} ▶ {(isCut ? "EaseInOut" : "Cut")}로 전환",
|
||||
isCut ? "action-btn--secondary" : "action-btn--success");
|
||||
blendBtn.clicked += () =>
|
||||
{
|
||||
cam.ToggleDefaultBlend();
|
||||
SwitchCategory("camera");
|
||||
};
|
||||
blendRow.Add(blendBtn);
|
||||
actionList.Add(blendRow);
|
||||
|
||||
var data = cam.GetCameraListData();
|
||||
if (data?.presets == null) return;
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UIElements;
|
||||
@ -11,8 +12,13 @@ public class CameraManagerEditor : Editor
|
||||
private const string UssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/CameraManagerEditor.uss";
|
||||
private const string CommonUssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/StreamingleCommon.uss";
|
||||
|
||||
private VisualElement presetsSection;
|
||||
private VisualElement presetsContainer;
|
||||
private VisualElement dropZone;
|
||||
private Label presetsTitleLabel;
|
||||
private Button defaultBlendButton;
|
||||
private Label defaultBlendStatusLabel;
|
||||
private HelpBox brainNotFoundWarning;
|
||||
private CameraManager manager;
|
||||
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
@ -36,6 +42,9 @@ public class CameraManagerEditor : Editor
|
||||
SetupRotationTargetLogic(root);
|
||||
SetupBlendTransitionLogic(root);
|
||||
|
||||
// Cinemachine Brain default blend toggle
|
||||
SetupDefaultBlendSection(root);
|
||||
|
||||
// Preset list (dynamic)
|
||||
BuildPresetsSection(root);
|
||||
|
||||
@ -162,12 +171,104 @@ public class CameraManagerEditor : Editor
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cinemachine Brain
|
||||
|
||||
private void SetupDefaultBlendSection(VisualElement root)
|
||||
{
|
||||
var group = root.Q("defaultBlendGroup");
|
||||
brainNotFoundWarning = root.Q<HelpBox>("brainNotFoundWarning");
|
||||
if (group == null) return;
|
||||
|
||||
var row = new VisualElement();
|
||||
row.AddToClassList("blend-toggle-row");
|
||||
|
||||
defaultBlendStatusLabel = new Label("현재 Default Blend:");
|
||||
defaultBlendStatusLabel.AddToClassList("blend-toggle-label");
|
||||
row.Add(defaultBlendStatusLabel);
|
||||
|
||||
defaultBlendButton = new Button(ToggleEditorDefaultBlend) { text = "-" };
|
||||
defaultBlendButton.AddToClassList("blend-toggle-btn");
|
||||
row.Add(defaultBlendButton);
|
||||
|
||||
group.Add(row);
|
||||
|
||||
// 인스펙터가 포커스를 가질 때 주기적으로 UI 동기화 (씬에서 직접 편집한 경우 반영)
|
||||
root.schedule.Execute(UpdateDefaultBlendUI).Every(500);
|
||||
UpdateDefaultBlendUI();
|
||||
}
|
||||
|
||||
private CinemachineBrain FindBrain()
|
||||
{
|
||||
var mainCam = Camera.main;
|
||||
if (mainCam != null)
|
||||
{
|
||||
var brain = mainCam.GetComponent<CinemachineBrain>();
|
||||
if (brain != null) return brain;
|
||||
}
|
||||
return FindFirstObjectByType<CinemachineBrain>();
|
||||
}
|
||||
|
||||
private void UpdateDefaultBlendUI()
|
||||
{
|
||||
if (defaultBlendButton == null) return;
|
||||
|
||||
var brain = FindBrain();
|
||||
if (brain == null)
|
||||
{
|
||||
defaultBlendButton.text = "Brain 없음";
|
||||
defaultBlendButton.SetEnabled(false);
|
||||
defaultBlendButton.RemoveFromClassList("blend-toggle-btn--cut");
|
||||
defaultBlendButton.RemoveFromClassList("blend-toggle-btn--ease");
|
||||
|
||||
if (defaultBlendStatusLabel != null)
|
||||
defaultBlendStatusLabel.text = "CinemachineBrain을 찾을 수 없음";
|
||||
|
||||
if (brainNotFoundWarning != null)
|
||||
brainNotFoundWarning.style.display = DisplayStyle.Flex;
|
||||
return;
|
||||
}
|
||||
|
||||
if (brainNotFoundWarning != null)
|
||||
brainNotFoundWarning.style.display = DisplayStyle.None;
|
||||
|
||||
var style = brain.DefaultBlend.Style;
|
||||
bool isCut = style == CinemachineBlendDefinition.Styles.Cut;
|
||||
bool isEase = style == CinemachineBlendDefinition.Styles.EaseInOut;
|
||||
|
||||
if (defaultBlendStatusLabel != null)
|
||||
defaultBlendStatusLabel.text = $"현재 Default Blend: {style}";
|
||||
|
||||
defaultBlendButton.SetEnabled(true);
|
||||
defaultBlendButton.text = isCut ? "▶ EaseInOut 으로 전환" : "▶ Cut 으로 전환";
|
||||
|
||||
defaultBlendButton.EnableInClassList("blend-toggle-btn--cut", isCut);
|
||||
defaultBlendButton.EnableInClassList("blend-toggle-btn--ease", isEase);
|
||||
}
|
||||
|
||||
private void ToggleEditorDefaultBlend()
|
||||
{
|
||||
var brain = FindBrain();
|
||||
if (brain == null) return;
|
||||
|
||||
Undo.RecordObject(brain, "Toggle CinemachineBrain Default Blend");
|
||||
var blend = brain.DefaultBlend;
|
||||
blend.Style = (blend.Style == CinemachineBlendDefinition.Styles.Cut)
|
||||
? CinemachineBlendDefinition.Styles.EaseInOut
|
||||
: CinemachineBlendDefinition.Styles.Cut;
|
||||
brain.DefaultBlend = blend;
|
||||
EditorUtility.SetDirty(brain);
|
||||
|
||||
UpdateDefaultBlendUI();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Preset List
|
||||
|
||||
private void BuildPresetsSection(VisualElement root)
|
||||
{
|
||||
var section = root.Q("presetsSection");
|
||||
if (section == null) return;
|
||||
presetsSection = root.Q("presetsSection");
|
||||
if (presetsSection == null) return;
|
||||
|
||||
// Header
|
||||
var header = new VisualElement();
|
||||
@ -177,19 +278,88 @@ public class CameraManagerEditor : Editor
|
||||
presetsTitleLabel.AddToClassList("presets-title");
|
||||
header.Add(presetsTitleLabel);
|
||||
|
||||
var addBtn = new Button(AddPreset) { text = "+ 프리셋 추가" };
|
||||
var addBtn = new Button(AddPreset)
|
||||
{
|
||||
text = "+ 프리셋 추가",
|
||||
tooltip = "씬의 첫 CinemachineCamera를 추가합니다. 아래 영역으로 드래그해서 추가할 수도 있습니다."
|
||||
};
|
||||
addBtn.AddToClassList("preset-add-btn");
|
||||
header.Add(addBtn);
|
||||
|
||||
section.Add(header);
|
||||
presetsSection.Add(header);
|
||||
|
||||
// Container
|
||||
presetsContainer = new VisualElement();
|
||||
section.Add(presetsContainer);
|
||||
presetsSection.Add(presetsContainer);
|
||||
|
||||
// Drop zone
|
||||
dropZone = new Label("CinemachineCamera를 여기로 드래그하여 추가");
|
||||
dropZone.AddToClassList("preset-drop-zone");
|
||||
presetsSection.Add(dropZone);
|
||||
|
||||
SetupDragAndDrop(presetsSection);
|
||||
|
||||
RebuildPresetList();
|
||||
}
|
||||
|
||||
private void SetupDragAndDrop(VisualElement target)
|
||||
{
|
||||
target.RegisterCallback<DragUpdatedEvent>(evt =>
|
||||
{
|
||||
if (GetDraggedCameras().Count > 0)
|
||||
{
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
||||
dropZone?.AddToClassList("preset-drop-zone--active");
|
||||
evt.StopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
target.RegisterCallback<DragLeaveEvent>(_ =>
|
||||
{
|
||||
dropZone?.RemoveFromClassList("preset-drop-zone--active");
|
||||
});
|
||||
|
||||
target.RegisterCallback<DragExitedEvent>(_ =>
|
||||
{
|
||||
dropZone?.RemoveFromClassList("preset-drop-zone--active");
|
||||
});
|
||||
|
||||
target.RegisterCallback<DragPerformEvent>(evt =>
|
||||
{
|
||||
var cams = GetDraggedCameras();
|
||||
dropZone?.RemoveFromClassList("preset-drop-zone--active");
|
||||
if (cams.Count == 0) return;
|
||||
|
||||
DragAndDrop.AcceptDrag();
|
||||
Undo.RecordObject(this.target, "Add Camera Preset (Drop)");
|
||||
foreach (var cam in cams)
|
||||
{
|
||||
manager.cameraPresets.Add(new CameraManager.CameraPreset(cam));
|
||||
}
|
||||
EditorUtility.SetDirty(this.target);
|
||||
RebuildPresetList();
|
||||
evt.StopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
private List<CinemachineCamera> GetDraggedCameras()
|
||||
{
|
||||
var list = new List<CinemachineCamera>();
|
||||
foreach (var obj in DragAndDrop.objectReferences)
|
||||
{
|
||||
if (obj is CinemachineCamera cc)
|
||||
{
|
||||
if (!list.Contains(cc)) list.Add(cc);
|
||||
}
|
||||
else if (obj is GameObject go)
|
||||
{
|
||||
var cam = go.GetComponent<CinemachineCamera>();
|
||||
if (cam != null && !list.Contains(cam)) list.Add(cam);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void RebuildPresetList()
|
||||
{
|
||||
if (presetsContainer == null || manager == null) return;
|
||||
@ -226,14 +396,32 @@ public class CameraManagerEditor : Editor
|
||||
var headerRow = new VisualElement();
|
||||
headerRow.AddToClassList("preset-item-header");
|
||||
|
||||
var indexLabel = new Label($"{index + 1}");
|
||||
indexLabel.AddToClassList("preset-index");
|
||||
headerRow.Add(indexLabel);
|
||||
int idx = index;
|
||||
|
||||
var indexField = new IntegerField
|
||||
{
|
||||
value = index + 1,
|
||||
isDelayed = true,
|
||||
tooltip = "카메라 순서 번호. 숫자를 입력 후 Enter를 누르면 해당 위치로 이동합니다."
|
||||
};
|
||||
indexField.AddToClassList("preset-index-field");
|
||||
indexField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
int newIndex = Mathf.Clamp(evt.newValue - 1, 0, manager.cameraPresets.Count - 1);
|
||||
if (newIndex != idx)
|
||||
{
|
||||
MovePreset(idx, newIndex);
|
||||
}
|
||||
else if (evt.newValue != idx + 1)
|
||||
{
|
||||
indexField.SetValueWithoutNotify(idx + 1);
|
||||
}
|
||||
});
|
||||
headerRow.Add(indexField);
|
||||
|
||||
var nameField = new TextField();
|
||||
nameField.value = preset.presetName;
|
||||
nameField.AddToClassList("preset-name-field");
|
||||
int idx = index;
|
||||
nameField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
Undo.RecordObject(target, "Rename Camera Preset");
|
||||
@ -250,19 +438,24 @@ public class CameraManagerEditor : Editor
|
||||
}
|
||||
|
||||
// Up button
|
||||
var upBtn = new Button(() => SwapPresets(index, index - 1)) { text = "\u25B2" };
|
||||
var upBtn = new Button(() => SwapPresets(index, index - 1)) { text = "\u25B2", tooltip = "위로 이동" };
|
||||
upBtn.AddToClassList("preset-reorder-btn");
|
||||
upBtn.SetEnabled(index > 0);
|
||||
headerRow.Add(upBtn);
|
||||
|
||||
// Down button
|
||||
var downBtn = new Button(() => SwapPresets(index, index + 1)) { text = "\u25BC" };
|
||||
var downBtn = new Button(() => SwapPresets(index, index + 1)) { text = "\u25BC", tooltip = "아래로 이동" };
|
||||
downBtn.AddToClassList("preset-reorder-btn");
|
||||
downBtn.SetEnabled(index < manager.cameraPresets.Count - 1);
|
||||
headerRow.Add(downBtn);
|
||||
|
||||
// Duplicate button
|
||||
var duplicateBtn = new Button(() => DuplicatePreset(index)) { text = "\u29C9", tooltip = "프리셋 복제" };
|
||||
duplicateBtn.AddToClassList("preset-duplicate-btn");
|
||||
headerRow.Add(duplicateBtn);
|
||||
|
||||
// Delete button
|
||||
var deleteBtn = new Button(() => DeletePreset(index)) { text = "X" };
|
||||
var deleteBtn = new Button(() => DeletePreset(index)) { text = "X", tooltip = "프리셋 삭제" };
|
||||
deleteBtn.AddToClassList("preset-delete-btn");
|
||||
headerRow.Add(deleteBtn);
|
||||
|
||||
@ -278,11 +471,10 @@ public class CameraManagerEditor : Editor
|
||||
allowSceneObjects = true,
|
||||
value = preset.virtualCamera
|
||||
};
|
||||
int ci = index;
|
||||
cameraField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
Undo.RecordObject(target, "Change Camera Preset Camera");
|
||||
manager.cameraPresets[ci].virtualCamera = evt.newValue as CinemachineCamera;
|
||||
manager.cameraPresets[idx].virtualCamera = evt.newValue as CinemachineCamera;
|
||||
EditorUtility.SetDirty(target);
|
||||
});
|
||||
fields.Add(cameraField);
|
||||
@ -292,11 +484,10 @@ public class CameraManagerEditor : Editor
|
||||
tooltip = "이 카메라에서 마우스 조작(회전, 팬, 줌)을 허용할지 여부",
|
||||
value = preset.allowMouseControl
|
||||
};
|
||||
int mi = index;
|
||||
mouseToggle.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
Undo.RecordObject(target, "Toggle Mouse Control");
|
||||
manager.cameraPresets[mi].allowMouseControl = evt.newValue;
|
||||
manager.cameraPresets[idx].allowMouseControl = evt.newValue;
|
||||
EditorUtility.SetDirty(target);
|
||||
});
|
||||
fields.Add(mouseToggle);
|
||||
@ -337,6 +528,36 @@ public class CameraManagerEditor : Editor
|
||||
RebuildPresetList();
|
||||
}
|
||||
|
||||
private void MovePreset(int from, int to)
|
||||
{
|
||||
if (from == to) return;
|
||||
if (from < 0 || from >= manager.cameraPresets.Count) return;
|
||||
if (to < 0 || to >= manager.cameraPresets.Count) return;
|
||||
|
||||
Undo.RecordObject(target, "Move Camera Preset");
|
||||
var preset = manager.cameraPresets[from];
|
||||
manager.cameraPresets.RemoveAt(from);
|
||||
manager.cameraPresets.Insert(to, preset);
|
||||
EditorUtility.SetDirty(target);
|
||||
RebuildPresetList();
|
||||
}
|
||||
|
||||
private void DuplicatePreset(int index)
|
||||
{
|
||||
if (index < 0 || index >= manager.cameraPresets.Count) return;
|
||||
|
||||
Undo.RecordObject(target, "Duplicate Camera Preset");
|
||||
var source = manager.cameraPresets[index];
|
||||
var copy = new CameraManager.CameraPreset(source.virtualCamera)
|
||||
{
|
||||
presetName = $"{source.presetName} (복사)",
|
||||
allowMouseControl = source.allowMouseControl
|
||||
};
|
||||
manager.cameraPresets.Insert(index + 1, copy);
|
||||
EditorUtility.SetDirty(target);
|
||||
RebuildPresetList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Play Mode State
|
||||
|
||||
@ -1,5 +1,54 @@
|
||||
/* Camera Manager Editor styles */
|
||||
|
||||
.blend-toggle-row {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 4px 2px;
|
||||
}
|
||||
|
||||
.blend-toggle-label {
|
||||
flex-grow: 1;
|
||||
font-size: 11px;
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
.blend-toggle-btn {
|
||||
min-width: 160px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
border-width: 0;
|
||||
font-size: 11px;
|
||||
-unity-font-style: bold;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #e5e7eb;
|
||||
}
|
||||
|
||||
.blend-toggle-btn:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.blend-toggle-btn:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.blend-toggle-btn--cut {
|
||||
background-color: rgba(234, 179, 8, 0.25);
|
||||
color: #fde68a;
|
||||
}
|
||||
|
||||
.blend-toggle-btn--cut:hover {
|
||||
background-color: rgba(234, 179, 8, 0.4);
|
||||
}
|
||||
|
||||
.blend-toggle-btn--ease {
|
||||
background-color: rgba(34, 197, 94, 0.25);
|
||||
color: #bbf7d0;
|
||||
}
|
||||
|
||||
.blend-toggle-btn--ease:hover {
|
||||
background-color: rgba(34, 197, 94, 0.4);
|
||||
}
|
||||
|
||||
.presets-section {
|
||||
margin-top: 12px;
|
||||
}
|
||||
@ -63,6 +112,18 @@
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.preset-index-field {
|
||||
width: 42px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.preset-index-field > .unity-integer-field__input {
|
||||
-unity-text-align: middle-center;
|
||||
-unity-font-style: bold;
|
||||
font-size: 11px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.preset-name-field {
|
||||
flex-grow: 1;
|
||||
margin-left: 4px;
|
||||
@ -97,6 +158,24 @@
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.preset-duplicate-btn {
|
||||
width: 24px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
margin: 0 1px;
|
||||
border-radius: 3px;
|
||||
border-width: 0;
|
||||
background-color: rgba(99, 102, 241, 0.15);
|
||||
color: #a5b4fc;
|
||||
font-size: 12px;
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
|
||||
.preset-duplicate-btn:hover {
|
||||
background-color: rgba(99, 102, 241, 0.35);
|
||||
color: #c7d2fe;
|
||||
}
|
||||
|
||||
.preset-delete-btn {
|
||||
width: 24px;
|
||||
height: 20px;
|
||||
@ -126,3 +205,22 @@
|
||||
font-size: 11px;
|
||||
-unity-font-style: italic;
|
||||
}
|
||||
|
||||
.preset-drop-zone {
|
||||
margin-top: 8px;
|
||||
padding: 12px;
|
||||
border-width: 1px;
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 6px;
|
||||
background-color: rgba(255, 255, 255, 0.03);
|
||||
-unity-text-align: middle-center;
|
||||
color: #94a3b8;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.preset-drop-zone--active {
|
||||
border-color: #6366f1;
|
||||
background-color: rgba(99, 102, 241, 0.15);
|
||||
color: #c7d2fe;
|
||||
-unity-font-style: bold;
|
||||
}
|
||||
|
||||
@ -60,6 +60,14 @@
|
||||
</ui:Foldout>
|
||||
</ui:VisualElement>
|
||||
|
||||
<!-- Cinemachine Brain Default Blend -->
|
||||
<ui:VisualElement class="section">
|
||||
<ui:Foldout text="Cinemachine Brain" value="true" class="section-foldout">
|
||||
<ui:VisualElement name="defaultBlendGroup"/>
|
||||
<ui:HelpBox name="brainNotFoundWarning" message-type="Warning" text="Main Camera에 CinemachineBrain이 없습니다. Main Camera를 설정하거나 Camera에 CinemachineBrain 컴포넌트를 추가하세요."/>
|
||||
</ui:Foldout>
|
||||
</ui:VisualElement>
|
||||
|
||||
<!-- 카메라 프리셋 (C#에서 동적 생성) -->
|
||||
<ui:VisualElement name="presetsSection" class="section presets-section"/>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user