2026-06-09 룸 프로토타입 디자인 (진행중)
This commit is contained in:
@@ -0,0 +1,366 @@
|
||||
// Stylized Water 3 by Staggart Creations (http://staggart.xyz)
|
||||
// COPYRIGHT PROTECTED UNDER THE UNITY ASSET STORE EULA (https://unity.com/legal/as-terms)
|
||||
// • Copying or referencing source code for the production of new asset store, or public, content is strictly prohibited!
|
||||
// • Uploading this file to a public repository will subject it to an automated DMCA takedown request.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace StylizedWater3
|
||||
{
|
||||
[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;
|
||||
private SerializedProperty enableInSceneView;
|
||||
|
||||
//Quality
|
||||
private SerializedProperty renderShadows;
|
||||
private SerializedProperty renderScale;
|
||||
private SerializedProperty maximumLODLevel;
|
||||
|
||||
private SerializedProperty waterObjects;
|
||||
private SerializedProperty moveWithTransform;
|
||||
|
||||
private Bounds curBounds;
|
||||
private bool waterLayerError;
|
||||
private bool gpuOcclusionCulling;
|
||||
|
||||
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");
|
||||
enableInSceneView = serializedObject.FindProperty("enableInSceneView");
|
||||
renderShadows = serializedObject.FindProperty("renderShadows");
|
||||
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();
|
||||
gpuOcclusionCulling = UniversalRenderPipeline.asset.gpuResidentDrawerEnableOcclusionCullingInCameras;
|
||||
|
||||
RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
|
||||
}
|
||||
|
||||
private Camera currentCamera;
|
||||
private string currentCameraName;
|
||||
private bool waterObjectsVisible;
|
||||
|
||||
private void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
if (!previewReflection) return;
|
||||
|
||||
if (renderer.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();
|
||||
|
||||
if (ShaderUtil.anythingCompiling)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Rendering is temporarily paused, while the editor finishes compiling shaders", MessageType.Info);
|
||||
}
|
||||
|
||||
UI.DrawNotification(gpuOcclusionCulling, "GPU Occlusion Culling is enabled, this can cause some objects to disappear in the reflection.", MessageType.Warning);
|
||||
|
||||
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);
|
||||
if(enableFog.boolValue) EditorGUILayout.HelpBox("Unity's built-in fog does not support oblique projections. Expect incorrect fog shading on tall objects or large triangles", MessageType.Warning);
|
||||
EditorGUILayout.PropertyField(enableInSceneView);
|
||||
|
||||
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(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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user