ProjectDDD/Assets/External/StylizedWater2/Editor/Inspectors/PlanarReflectionRendererInspector.cs
2025-07-08 19:46:31 +09:00

351 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;
namespace StylizedWater2
{
[CustomEditor(typeof(PlanarReflectionRenderer))]
public class PlanarReflectionRendererInspector : Editor
{
private PlanarReflectionRenderer renderer;
//Rendering
private SerializedProperty rotatable;
private SerializedProperty cullingMask;
private SerializedProperty rendererIndex;
private SerializedProperty offset;
private SerializedProperty includeSkybox;
private SerializedProperty enableFog;
//Quality
private SerializedProperty renderShadows;
private SerializedProperty renderRange;
private SerializedProperty renderScale;
private SerializedProperty maximumLODLevel;
private SerializedProperty waterObjects;
private SerializedProperty moveWithTransform;
private Bounds curBounds;
private bool waterLayerError;
private bool previewReflection
{
get => EditorPrefs.GetBool("SWS2_PREVIEW_REFLECTION_ENABLED", true);
set => EditorPrefs.SetBool("SWS2_PREVIEW_REFLECTION_ENABLED", value);
}
private RenderTexture previewTexture;
#if URP
private void OnEnable()
{
PipelineUtilities.RefreshRendererList();
renderer = (PlanarReflectionRenderer)target;
rotatable = serializedObject.FindProperty("rotatable");
cullingMask = serializedObject.FindProperty("cullingMask");
rendererIndex = serializedObject.FindProperty("rendererIndex");
offset = serializedObject.FindProperty("offset");
includeSkybox = serializedObject.FindProperty("includeSkybox");
enableFog = serializedObject.FindProperty("enableFog");
renderShadows = serializedObject.FindProperty("renderShadows");
renderRange = serializedObject.FindProperty("renderRange");
renderScale = serializedObject.FindProperty("renderScale");
maximumLODLevel = serializedObject.FindProperty("maximumLODLevel");
waterObjects = serializedObject.FindProperty("waterObjects");
moveWithTransform = serializedObject.FindProperty("moveWithTransform");
if (renderer.waterObjects.Count == 0 && WaterObject.Instances.Count == 1)
{
renderer.waterObjects.Add(WaterObject.Instances[0]);
renderer.RecalculateBounds();
renderer.EnableMaterialReflectionSampling();
EditorUtility.SetDirty(target);
serializedObject.ApplyModifiedPropertiesWithoutUndo();
}
ValidateWaterObjectLayer();
curBounds = renderer.CalculateBounds();
RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
}
private Camera currentCamera;
private string currentCameraName;
private bool waterObjectsVisible;
private void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (!previewReflection) return;
if (PlanarReflectionRenderer.InvalidContext(camera)) return;
currentCamera = camera;
waterObjectsVisible = renderer.WaterObjectsVisible(currentCamera);
previewTexture = renderer.TryGetReflectionTexture(currentCamera);
currentCameraName = currentCamera.name;
}
private void OnDisable()
{
RenderPipelineManager.endCameraRendering -= OnEndCameraRendering;
}
#endif
public override void OnInspectorGUI()
{
#if !URP
UI.DrawNotification("The Universal Render Pipeline package v" + AssetInfo.MIN_URP_VERSION + " or newer is not installed", MessageType.Error);
#else
UI.DrawHeader();
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Space(EditorGUIUtility.labelWidth);
previewReflection =
GUILayout.Toggle(previewReflection, new GUIContent(" Preview reflection", EditorGUIUtility.IconContent(
(previewReflection ? "animationvisibilitytoggleon" : "animationvisibilitytoggleoff")).image), "Button");
}
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Space(EditorGUIUtility.labelWidth);
EditorGUILayout.LabelField("Status: " + (waterObjectsVisible && currentCamera ? $"Rendering (camera: {currentCamera.name})" : "Not rendering (water not in view for any camera)"), EditorStyles.miniLabel);
}
UI.DrawNotification(PipelineUtilities.VREnabled(), "Not supported with VR rendering", MessageType.Error);
UI.DrawNotification(PlanarReflectionRenderer.AllowReflections == false, "Reflections have been globally disabled by an external script", MessageType.Warning);
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.LabelField("Rendering", EditorStyles.boldLabel);
EditorGUI.BeginChangeCheck();
UI.DrawRendererProperty(rendererIndex);
if (EditorGUI.EndChangeCheck())
{
renderer.SetRendererIndex(rendererIndex.intValue);
}
//Default renderer
if (rendererIndex.intValue == 0)
{
UI.DrawNotification("\n" +
"Using the default renderer for reflections is strongly discouraged." +
"\n\nMost (if not all) render features, such as third-party post processing effects, will also render for the reflection." +
"\n\nThis can lead to rendering artefacts and negatively impacts overall performance." +
"\n", MessageType.Warning);
//If there are no other renderers to assign, suggest to auto-create one
UI.DrawNotification(PipelineUtilities.rendererIndexList.Length <= 2, "It is highly recommend to create a separate empty renderer", "Create and assign", CreateRenderer, MessageType.None);
EditorGUILayout.Space();
}
EditorGUILayout.PropertyField(cullingMask);
EditorGUILayout.PropertyField(includeSkybox);
EditorGUILayout.PropertyField(enableFog);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(rotatable);
EditorGUILayout.PropertyField(offset);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Quality", EditorStyles.boldLabel);
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(renderShadows);
if (EditorGUI.EndChangeCheck())
{
renderer.ToggleShadows(renderShadows.boolValue);
}
EditorGUILayout.PropertyField(renderRange);
EditorGUILayout.PropertyField(renderScale);
EditorGUILayout.PropertyField(maximumLODLevel);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Target water objects", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(moveWithTransform, new GUIContent("Move bounds with transform", moveWithTransform.tooltip));
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(waterObjects);
if (EditorGUI.EndChangeCheck())
{
curBounds = renderer.CalculateBounds();
}
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if(GUILayout.Button(new GUIContent("Auto-find", "Assigns all active water objects currently in the scene"), EditorStyles.miniButton))
{
renderer.waterObjects = new List<WaterObject>(WaterObject.Instances);
renderer.RecalculateBounds();
curBounds = renderer.bounds;
renderer.EnableMaterialReflectionSampling();
ValidateWaterObjectLayer();
EditorUtility.SetDirty(target);
}
if(GUILayout.Button("Clear", EditorStyles.miniButton))
{
renderer.ToggleMaterialReflectionSampling(false);
renderer.waterObjects.Clear();
renderer.RecalculateBounds();
EditorUtility.SetDirty(target);
}
}
if (renderer.waterObjects != null)
{
UI.DrawNotification(renderer.waterObjects.Count == 0, "Assign at least one Water Object", MessageType.Info);
if (renderer.waterObjects.Count > 0)
{
UI.DrawNotification(curBounds.size != renderer.bounds.size || (moveWithTransform.boolValue == false && curBounds.center != renderer.bounds.center), "Water objects have changed or moved, bounds needs to be recalculated", "Recalculate",() => RecalculateBounds(), MessageType.Error);
}
UI.DrawNotification(waterLayerError, "One or more Water Objects aren't on the \"Water\" layer.\n\nThis causes recursive reflections", "Fix", () => SetObjectsOnWaterLayer(), MessageType.Error);
}
#endif
UI.DrawFooter();
}
#if URP
private void CreateRenderer()
{
int index = -1;
string path = "";
PipelineUtilities.CreateAndAssignNewRenderer(out index, out path);
if (index >= 0)
{
rendererIndex.intValue = index;
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
renderer.SetRendererIndex(rendererIndex.intValue);
if (path != string.Empty)
{
Debug.Log("New renderer created at path <i>" + path + "</i>");
}
}
}
public override bool HasPreviewGUI()
{
return previewReflection && previewTexture;
}
public override bool RequiresConstantRepaint()
{
return HasPreviewGUI();
}
public override GUIContent GetPreviewTitle()
{
return currentCamera ? new GUIContent(currentCameraName + " reflection") : new GUIContent("Reflection");
}
public override void OnPreviewSettings()
{
if (HasPreviewGUI() == false) return;
GUILayout.Label($"Resolution ({previewTexture.width}x{previewTexture.height})");
}
private bool drawAlpha;
public override void OnPreviewGUI(Rect r, GUIStyle background)
{
if (drawAlpha)
{
EditorGUI.DrawTextureAlpha(r, previewTexture, ScaleMode.ScaleToFit);
}
else
{
GUI.DrawTexture(r, previewTexture, ScaleMode.ScaleToFit, false);
}
Rect btnRect = r;
btnRect.x += 10f;
btnRect.y += 10f;
btnRect.width = 150f;
btnRect.height = 20f;
drawAlpha = GUI.Toggle(btnRect, drawAlpha, new GUIContent(" Alpha channel"));
}
private void ValidateWaterObjectLayer()
{
if (renderer.waterObjects == null) return;
waterLayerError = false;
int layerID = LayerMask.NameToLayer("Water");
foreach (WaterObject obj in renderer.waterObjects)
{
//Is not on "Water" layer?
if (obj.gameObject.layer != layerID)
{
waterLayerError = true;
return;
}
}
}
private void SetObjectsOnWaterLayer()
{
int layerID = LayerMask.NameToLayer("Water");
foreach (WaterObject obj in renderer.waterObjects)
{
//Is not on "Water" layer?
if (obj.gameObject.layer != layerID)
{
obj.gameObject.layer = layerID;
EditorUtility.SetDirty(obj);
}
}
waterLayerError = false;
}
#endif
private void RecalculateBounds()
{
#if URP
renderer.RecalculateBounds();
curBounds = renderer.bounds;
EditorUtility.SetDirty(target);
#endif
}
}
}