using UnityEngine; using PlanarReflections5; /// /// NiloToon Environment 셰이더와 PIDI Planar Reflections 5를 연동하는 브리지 스크립트 /// [System.Serializable] public class NiloToonReflectionSettings { [Header("Reflection Control")] [Range(0f, 1f)] public float reflectionIntensity = 1.0f; [ColorUsage(false)] public Color reflectionTintColor = Color.white; [Range(0.1f, 5f)] public float fresnelPower = 1.5f; [Range(0f, 0.1f)] public float distortionStrength = 0.02f; [Range(0f, 10f)] public float depthFade = 1.0f; [Range(0f, 2f)] public float blurRadius = 0.5f; [Header("Advanced")] public bool enableReflection = true; public bool useDepthFade = false; public LayerMask reflectionLayers = -1; } [RequireComponent(typeof(PlanarReflectionRenderer))] public class NiloToonPlanarReflectionBridge : MonoBehaviour { [Header("NiloToon Integration Settings")] public NiloToonReflectionSettings reflectionSettings = new NiloToonReflectionSettings(); [Header("Shader Keywords")] [SerializeField] private bool enableReflectionDepthFade = false; private PlanarReflectionRenderer planarRenderer; private Camera[] monitoredCameras; // 셰이더 프로퍼티 IDs (성능 최적화) private static readonly int EnablePlanarReflectionID = Shader.PropertyToID("_EnablePlanarReflection"); private static readonly int ReflectionIntensityID = Shader.PropertyToID("_ReflectionIntensity"); private static readonly int ReflectionTintColorID = Shader.PropertyToID("_ReflectionTintColor"); private static readonly int ReflectionFresnelID = Shader.PropertyToID("_ReflectionFresnel"); private static readonly int ReflectionDistortionID = Shader.PropertyToID("_ReflectionDistortion"); private static readonly int ReflectionDepthFadeID = Shader.PropertyToID("_ReflectionDepthFade"); private static readonly int ReflectionBlurRadiusID = Shader.PropertyToID("_ReflectionBlurRadius"); private void Awake() { planarRenderer = GetComponent(); if (planarRenderer == null) { Debug.LogError("NiloToonPlanarReflectionBridge requires PlanarReflectionRenderer component!"); enabled = false; return; } } private void Start() { // 초기 설정 적용 UpdateShaderProperties(); UpdateShaderKeywords(); } private void Update() { // 실시간으로 셰이더 프로퍼티 업데이트 UpdateShaderProperties(); // 카메라 변경 감지 및 업데이트 if (monitoredCameras == null || monitoredCameras.Length != Camera.allCamerasCount) { UpdateCameraReferences(); } } private void UpdateShaderProperties() { // Global 셰이더 프로퍼티 업데이트 Shader.SetGlobalFloat(EnablePlanarReflectionID, reflectionSettings.enableReflection ? 1.0f : 0.0f); Shader.SetGlobalFloat(ReflectionIntensityID, reflectionSettings.reflectionIntensity); Shader.SetGlobalVector(ReflectionTintColorID, new Vector4( reflectionSettings.reflectionTintColor.r, reflectionSettings.reflectionTintColor.g, reflectionSettings.reflectionTintColor.b, reflectionSettings.reflectionTintColor.a)); Shader.SetGlobalFloat(ReflectionFresnelID, reflectionSettings.fresnelPower); Shader.SetGlobalFloat(ReflectionDistortionID, reflectionSettings.distortionStrength); Shader.SetGlobalFloat(ReflectionDepthFadeID, reflectionSettings.depthFade); Shader.SetGlobalFloat(ReflectionBlurRadiusID, reflectionSettings.blurRadius); } private void UpdateShaderKeywords() { // 셰이더 키워드 업데이트 if (enableReflectionDepthFade && reflectionSettings.useDepthFade) { Shader.EnableKeyword("_REFLECTION_DEPTH_FADE"); } else { Shader.DisableKeyword("_REFLECTION_DEPTH_FADE"); } } private void UpdateCameraReferences() { monitoredCameras = new Camera[Camera.allCamerasCount]; Camera.GetAllCameras(monitoredCameras); // Planar Reflection 설정을 카메라별로 동기화 if (planarRenderer != null && planarRenderer.Settings != null) { planarRenderer.Settings.reflectLayers = reflectionSettings.reflectionLayers; planarRenderer.Settings.renderDepth = reflectionSettings.useDepthFade; } } /// /// 특정 재질에 반사 설정을 적용합니다. /// /// 적용할 재질 public void ApplyToMaterial(Material material) { if (material == null) return; material.SetFloat(EnablePlanarReflectionID, reflectionSettings.enableReflection ? 1.0f : 0.0f); material.SetFloat(ReflectionIntensityID, reflectionSettings.reflectionIntensity); material.SetVector(ReflectionTintColorID, new Vector4( reflectionSettings.reflectionTintColor.r, reflectionSettings.reflectionTintColor.g, reflectionSettings.reflectionTintColor.b, reflectionSettings.reflectionTintColor.a)); material.SetFloat(ReflectionFresnelID, reflectionSettings.fresnelPower); material.SetFloat(ReflectionDistortionID, reflectionSettings.distortionStrength); material.SetFloat(ReflectionDepthFadeID, reflectionSettings.depthFade); material.SetFloat(ReflectionBlurRadiusID, reflectionSettings.blurRadius); // 키워드 설정 if (enableReflectionDepthFade && reflectionSettings.useDepthFade) { material.EnableKeyword("_REFLECTION_DEPTH_FADE"); } else { material.DisableKeyword("_REFLECTION_DEPTH_FADE"); } } /// /// 씬의 모든 NiloToon Environment 재질에 설정을 적용합니다. /// public void ApplyToAllNiloToonMaterials() { Renderer[] renderers = FindObjectsOfType(); foreach (Renderer renderer in renderers) { foreach (Material mat in renderer.materials) { // NiloToon Environment 셰이더인지 확인 (이름으로 판별) if (mat.shader.name.Contains("NiloToon") && mat.shader.name.Contains("Environment")) { ApplyToMaterial(mat); } } } } private void OnValidate() { // Inspector에서 값이 변경될 때 실시간 업데이트 if (Application.isPlaying) { UpdateShaderProperties(); UpdateShaderKeywords(); } } #if UNITY_EDITOR [UnityEditor.MenuItem("Tools/NiloToon/Create Planar Reflection Bridge")] private static void CreateBridge() { GameObject bridge = new GameObject("NiloToon Planar Reflection Bridge"); bridge.AddComponent(); bridge.AddComponent(); UnityEditor.Selection.activeGameObject = bridge; UnityEditor.EditorGUIUtility.PingObject(bridge); Debug.Log("NiloToon Planar Reflection Bridge가 생성되었습니다!"); } #endif }