user 7a5d1dbe8f Refactor: 배경 씬 로더 시스템 개선 및 폴더 구조 정리
배경 씬 로더 기능 개선:
- BackgroundSceneDatabase 에셋 추가
- 플레이 모드 언로드 시 MarkSceneDirty 오류 수정
- Directional Light 및 NiloToonOverrider 백업/복원 기능
- 빌드 세팅 자동 추가 기능

배경 폴더 구조 정리:
- [초금비]방 → [공용]방 이름 변경
- [공용]루프탑 카페 씬 구조 정리 (Day/Night 씬 통합)
- 미사용 배경 삭제: [공용]교실, [공용]농구장

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 00:00:35 +09:00

275 lines
9.8 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
namespace Streamingle.Background.Editor
{
/// <summary>
/// 배경 씬에서 라이팅 세팅을 복사해오는 유틸리티
/// </summary>
public static class BackgroundLightingCopier
{
/// <summary>
/// 소스 씬에서 타겟 씬으로 라이팅 세팅 복사
/// </summary>
public static void CopyLightingSettings(Scene sourceScene, Scene targetScene)
{
if (!sourceScene.isLoaded || !targetScene.isLoaded)
{
UnityEngine.Debug.LogWarning("소스 씬 또는 타겟 씬이 로드되지 않았습니다.");
return;
}
// 1. Environment 설정 복사 (Skybox, Ambient, Fog 등)
CopyEnvironmentSettings();
// 2. 소스 씬의 라이트들을 타겟 씬으로 복사
CopyLights(sourceScene, targetScene);
// 3. Reflection Probe 복사
CopyReflectionProbes(sourceScene, targetScene);
// 4. Light Probe Group 복사
CopyLightProbeGroups(sourceScene, targetScene);
// 5. Volume (Post Processing) 복사
CopyVolumes(sourceScene, targetScene);
UnityEngine.Debug.Log($"라이팅 세팅 복사 완료: {sourceScene.name} → {targetScene.name}");
}
/// <summary>
/// 현재 활성 씬에 배경 씬의 라이팅 적용
/// </summary>
public static void ApplyLightingFromBackgroundScene(Scene backgroundScene)
{
if (!backgroundScene.isLoaded)
{
UnityEngine.Debug.LogWarning("배경 씬이 로드되지 않았습니다.");
return;
}
// Environment 설정 복사
CopyEnvironmentSettingsFromScene(backgroundScene);
UnityEngine.Debug.Log($"라이팅 세팅 적용됨: {backgroundScene.name}");
}
private static void CopyEnvironmentSettings()
{
// RenderSettings는 현재 활성 씬에 적용됨
// Lighting Window에서 설정하는 것들
}
private static void CopyEnvironmentSettingsFromScene(Scene sourceScene)
{
// 소스 씬을 활성 씬으로 설정하여 RenderSettings 가져오기
var previousActiveScene = SceneManager.GetActiveScene();
// 소스 씬에서 Environment 관련 오브젝트 찾기
var rootObjects = sourceScene.GetRootGameObjects();
foreach (var obj in rootObjects)
{
// Directional Light (Sun) 찾기
var lights = obj.GetComponentsInChildren<Light>(true);
foreach (var light in lights)
{
if (light.type == LightType.Directional)
{
// Sun Source로 설정
RenderSettings.sun = light;
break;
}
}
// Volume 찾기 (Global Volume의 경우 환경 설정 포함)
var volumes = obj.GetComponentsInChildren<Volume>(true);
foreach (var volume in volumes)
{
if (volume.isGlobal && volume.sharedProfile != null)
{
// Global Volume의 프로파일에서 환경 설정 복사 가능
}
}
}
}
private static void CopyLights(Scene sourceScene, Scene targetScene)
{
var sourceRoots = sourceScene.GetRootGameObjects();
var lightsContainer = GetOrCreateLightingContainer(targetScene, "Background Lights");
foreach (var root in sourceRoots)
{
var lights = root.GetComponentsInChildren<Light>(true);
foreach (var light in lights)
{
// 라이트 복제
var newLightObj = Object.Instantiate(light.gameObject, lightsContainer.transform);
newLightObj.name = $"[BG] {light.gameObject.name}";
// 씬 이동
SceneManager.MoveGameObjectToScene(newLightObj, targetScene);
}
}
}
private static void CopyReflectionProbes(Scene sourceScene, Scene targetScene)
{
var sourceRoots = sourceScene.GetRootGameObjects();
var container = GetOrCreateLightingContainer(targetScene, "Background ReflectionProbes");
foreach (var root in sourceRoots)
{
var probes = root.GetComponentsInChildren<ReflectionProbe>(true);
foreach (var probe in probes)
{
var newProbeObj = Object.Instantiate(probe.gameObject, container.transform);
newProbeObj.name = $"[BG] {probe.gameObject.name}";
SceneManager.MoveGameObjectToScene(newProbeObj, targetScene);
}
}
}
private static void CopyLightProbeGroups(Scene sourceScene, Scene targetScene)
{
var sourceRoots = sourceScene.GetRootGameObjects();
var container = GetOrCreateLightingContainer(targetScene, "Background LightProbes");
foreach (var root in sourceRoots)
{
var groups = root.GetComponentsInChildren<LightProbeGroup>(true);
foreach (var group in groups)
{
var newGroupObj = Object.Instantiate(group.gameObject, container.transform);
newGroupObj.name = $"[BG] {group.gameObject.name}";
SceneManager.MoveGameObjectToScene(newGroupObj, targetScene);
}
}
}
private static void CopyVolumes(Scene sourceScene, Scene targetScene)
{
var sourceRoots = sourceScene.GetRootGameObjects();
var container = GetOrCreateLightingContainer(targetScene, "Background Volumes");
foreach (var root in sourceRoots)
{
var volumes = root.GetComponentsInChildren<Volume>(true);
foreach (var volume in volumes)
{
var newVolumeObj = Object.Instantiate(volume.gameObject, container.transform);
newVolumeObj.name = $"[BG] {volume.gameObject.name}";
SceneManager.MoveGameObjectToScene(newVolumeObj, targetScene);
}
}
}
private static GameObject GetOrCreateLightingContainer(Scene scene, string name)
{
var roots = scene.GetRootGameObjects();
// 기존 컨테이너 찾기
foreach (var root in roots)
{
if (root.name == name)
{
// 기존 자식들 제거
while (root.transform.childCount > 0)
{
Object.DestroyImmediate(root.transform.GetChild(0).gameObject);
}
return root;
}
}
// 새 컨테이너 생성
var container = new GameObject(name);
SceneManager.MoveGameObjectToScene(container, scene);
return container;
}
/// <summary>
/// 타겟 씬에서 복사된 라이팅 오브젝트들 제거
/// </summary>
public static void RemoveCopiedLighting(Scene targetScene)
{
var roots = targetScene.GetRootGameObjects();
var toRemove = new List<GameObject>();
foreach (var root in roots)
{
if (root.name.StartsWith("Background ") ||
root.name.StartsWith("[BG]"))
{
toRemove.Add(root);
}
}
foreach (var obj in toRemove)
{
Object.DestroyImmediate(obj);
}
UnityEngine.Debug.Log($"복사된 라이팅 오브젝트 제거됨: {toRemove.Count}개");
}
/// <summary>
/// 배경 씬의 Skybox Material 가져오기
/// </summary>
public static Material GetSkyboxFromScene(Scene scene)
{
var roots = scene.GetRootGameObjects();
foreach (var root in roots)
{
// Skybox 컴포넌트가 있는 카메라 찾기
var cameras = root.GetComponentsInChildren<Camera>(true);
foreach (var cam in cameras)
{
var skybox = cam.GetComponent<Skybox>();
if (skybox != null && skybox.material != null)
{
return skybox.material;
}
}
}
return null;
}
/// <summary>
/// RenderSettings 전체 복사 (Skybox, Ambient, Fog 등)
/// </summary>
public static void ApplyRenderSettings(
Material skybox = null,
AmbientMode? ambientMode = null,
Color? ambientLight = null,
bool? fog = null,
Color? fogColor = null,
float? fogDensity = null)
{
if (skybox != null)
RenderSettings.skybox = skybox;
if (ambientMode.HasValue)
RenderSettings.ambientMode = ambientMode.Value;
if (ambientLight.HasValue)
RenderSettings.ambientLight = ambientLight.Value;
if (fog.HasValue)
RenderSettings.fog = fog.Value;
if (fogColor.HasValue)
RenderSettings.fogColor = fogColor.Value;
if (fogDensity.HasValue)
RenderSettings.fogDensity = fogDensity.Value;
}
}
}