2026-06-09 룸 프로토타입 디자인 (진행중)
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
// 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.
|
||||
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
#define DEBUG_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if URP
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.RenderGraphModule;
|
||||
using UnityEngine.Rendering.RenderGraphModule.Util;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace StylizedWater3
|
||||
{
|
||||
[DisallowMultipleRendererFeature("Stylized Water 3")]
|
||||
public partial class StylizedWaterRenderFeature : ScriptableRendererFeature
|
||||
{
|
||||
[Tooltip("Render all transparent materials NOT on the \"Water\" layer into a screen-space texture, and use that for refraction rendering in the water." +
|
||||
"\n\n" +
|
||||
"If enabled, transparent materials can be submerged and refracted correctly")]
|
||||
public bool transparencyRefraction;
|
||||
|
||||
public static StylizedWaterRenderFeature GetDefault()
|
||||
{
|
||||
return (StylizedWaterRenderFeature)PipelineUtilities.GetRenderFeature<StylizedWaterRenderFeature>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ScreenSpaceReflectionSettings
|
||||
{
|
||||
[FormerlySerializedAs("enable")]
|
||||
[Tooltip("Allow SSR to be rendered in water materials that have it enabled." +
|
||||
"\n\nDisable as a global performance scaling measure")]
|
||||
public bool allow = true;
|
||||
|
||||
[FormerlySerializedAs("reflectSkybox")]
|
||||
[Tooltip("Only enable when Reflection Probes cannot be used in a realtime lighting setup. If enabled, SSR will also reflects the skybox color and geometry in front of the water." +
|
||||
"\n\nIdeally disabled, so that Reflection Probes can be relied on for a 1:1 accurate skybox reflection.")]
|
||||
public bool reflectEverything = false;
|
||||
}
|
||||
public ScreenSpaceReflectionSettings screenSpaceReflectionSettings = new ScreenSpaceReflectionSettings();
|
||||
|
||||
[FormerlySerializedAs("directionalCaustics")]
|
||||
[Tooltip("Pass on the main directional light's projection onto the water shader. Allows caustics to project along its direction (rather than top-down)." +
|
||||
"\n\nThis shading operation is relative expensive, as it involves analyzing the depth texture at 4 different points")]
|
||||
public bool allowDirectionalCaustics;
|
||||
|
||||
public HeightPrePass.Settings heightPrePassSettings = new HeightPrePass.Settings();
|
||||
#if SWS_DEV
|
||||
public TerrainHeightPrePass.Settings terrainHeightPrePassSettings = new TerrainHeightPrePass.Settings();
|
||||
#endif
|
||||
|
||||
private SetupConstants constantsSetup;
|
||||
private HeightPrePass heightPrePass;
|
||||
private HeightQuerySystem.RenderPass heightQueryPass;
|
||||
#if SWS_DEV
|
||||
private TerrainHeightPrePass terrainHeightPrePass;
|
||||
private DistanceFieldPass distanceFieldPass;
|
||||
private RenderTransparentTexture transparentTexturePass;
|
||||
#endif
|
||||
|
||||
#if DEBUG_AVAILABLE
|
||||
private DebugInspectorPass debugInspectorPass;
|
||||
#endif
|
||||
|
||||
[SerializeField]
|
||||
public ComputeShader heightReadbackCS;
|
||||
[SerializeField]
|
||||
public Shader heightProcessingShader;
|
||||
|
||||
/// <summary>
|
||||
/// Set this to true from a render pass if it requires the displacement pre-pass, despite it being disabled in the render feature settings.
|
||||
/// </summary>
|
||||
public static bool RequireHeightPrePass;
|
||||
|
||||
protected bool WillExecuteHeightPrePass => RequireHeightPrePass || heightPrePassSettings.enable || HeightQuerySystem.RequiresHeightPrepass;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
VerifyReferences();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
VerifyReferences();
|
||||
}
|
||||
|
||||
public void VerifyReferences()
|
||||
{
|
||||
if (!heightReadbackCS)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
//HeightSampler.cs
|
||||
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath("768e0c28dfdbc6b429fd59518fa03f2d");
|
||||
|
||||
ComputeShader cs = UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(assetPath);
|
||||
|
||||
if (cs)
|
||||
{
|
||||
heightReadbackCS = cs;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(!heightProcessingShader) heightProcessingShader = Shader.Find(ShaderParams.ShaderNames.HeightProcessor);
|
||||
|
||||
#if SWS_DEV
|
||||
if(!terrainHeightPrePassSettings.terrainHeightVisualizationShader) terrainHeightPrePassSettings.terrainHeightVisualizationShader = Shader.Find(ShaderParams.ShaderNames.TerrainHeight);
|
||||
#endif
|
||||
|
||||
VerifyUnderwaterRendering();
|
||||
}
|
||||
|
||||
public class DebugData : ContextItem
|
||||
{
|
||||
public TextureHandle currentHandle;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
currentHandle = TextureHandle.nullHandle;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Create()
|
||||
{
|
||||
GraphicsDeviceType currentGraphicsAPI = SystemInfo.graphicsDeviceType;
|
||||
//https://issuetracker.unity3d.com/issues/crash-on-gfxdeviced3d12base-drawbufferscommon-when-adding-specific-custom-render-pass-feature-to-renderer
|
||||
//Now fixed in Unity 6000.0.60f1
|
||||
#if !UNITY_6000_1_OR_NEWER
|
||||
if (currentGraphicsAPI == GraphicsDeviceType.Direct3D12 || currentGraphicsAPI == GraphicsDeviceType.XboxOneD3D12)
|
||||
{
|
||||
//Using the "BeforeRendering" point causes a fatal crash when using DX12 when allocating a RT
|
||||
//defaultInjectionPoint = RenderPassEvent.BeforeRenderingShadows;
|
||||
}
|
||||
#endif
|
||||
|
||||
constantsSetup = new SetupConstants
|
||||
{
|
||||
renderPassEvent = defaultInjectionPoint
|
||||
};
|
||||
|
||||
heightPrePass = new HeightPrePass
|
||||
{
|
||||
renderPassEvent = defaultInjectionPoint
|
||||
};
|
||||
|
||||
heightQueryPass = new HeightQuerySystem.RenderPass()
|
||||
{
|
||||
renderPassEvent = defaultInjectionPoint
|
||||
};
|
||||
|
||||
#if SWS_DEV
|
||||
terrainHeightPrePass = new TerrainHeightPrePass()
|
||||
{
|
||||
renderPassEvent = defaultInjectionPoint
|
||||
};
|
||||
|
||||
if (transparencyRefraction)
|
||||
{
|
||||
transparentTexturePass = new RenderTransparentTexture();
|
||||
transparentTexturePass.renderPassEvent = RenderPassEvent.BeforeRenderingTransparents;
|
||||
}
|
||||
#endif
|
||||
|
||||
CreateFlowMapPass();
|
||||
CreateDynamicEffectsPasses();
|
||||
CreateUnderwaterRenderingPasses();
|
||||
|
||||
#if DEBUG_AVAILABLE
|
||||
debugInspectorPass = new DebugInspectorPass();
|
||||
debugInspectorPass.renderPassEvent = RenderPassEvent.AfterRendering;
|
||||
#endif
|
||||
}
|
||||
|
||||
//Note: Actually prefer to render before transparents, but this creates a recursive RenderSingleCamera call
|
||||
//Restoring the view/projection to that of the camera also breaks VR. Required functions are internal URP code
|
||||
|
||||
//In some cases, if no pre-passes render (depth, shadows, etc) then the projection does not get reset when rendering the opaque objects pass. Hence, things must render as early as possible.
|
||||
private static RenderPassEvent defaultInjectionPoint = RenderPassEvent.BeforeRendering;
|
||||
|
||||
//Dynamic Effects
|
||||
partial void CreateDynamicEffectsPasses();
|
||||
partial void AddDynamicEffectsPasses(ScriptableRenderer renderer, ref RenderingData renderingData);
|
||||
partial void DisposeDynamicEffectsPasses();
|
||||
|
||||
partial void VerifyUnderwaterRendering();
|
||||
partial void CreateUnderwaterRenderingPasses();
|
||||
partial void AddUnderwaterRenderingPasses(ScriptableRenderer renderer, ref RenderingData renderingData);
|
||||
partial void DisposeUnderwaterRenderingPasses();
|
||||
|
||||
partial void CreateFlowMapPass();
|
||||
partial void AddFlowMapPass(ScriptableRenderer renderer, ref RenderingData renderingData);
|
||||
partial void DisposeFlowMapPass();
|
||||
|
||||
private bool IsInvalidContext(CameraType cameraType, CameraRenderType cameraRenderType)
|
||||
{
|
||||
//Skip for any special use camera's (except scene view camera)
|
||||
if (cameraType != CameraType.SceneView && (cameraType == CameraType.Preview || hideFlags != HideFlags.None))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//Skip overlay cameras
|
||||
if (cameraRenderType == CameraRenderType.Overlay)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool isMainCamera(Camera camera)
|
||||
{
|
||||
//Skip for any special use camera's (except scene view camera)
|
||||
return (camera.cameraType == CameraType.SceneView || camera.CompareTag("MainCamera"));
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||||
{
|
||||
var currentCam = renderingData.cameraData.camera;
|
||||
|
||||
if(IsInvalidContext(currentCam.cameraType, renderingData.cameraData.renderType)) return;
|
||||
|
||||
constantsSetup.Setup(this);
|
||||
renderer.EnqueuePass(constantsSetup);
|
||||
|
||||
#if SWS_DEV
|
||||
if (terrainHeightPrePassSettings.enable)
|
||||
{
|
||||
terrainHeightPrePass.Setup(terrainHeightPrePassSettings);
|
||||
renderer.EnqueuePass(terrainHeightPrePass);
|
||||
}
|
||||
|
||||
if (transparencyRefraction)
|
||||
{
|
||||
renderer.EnqueuePass(transparentTexturePass);
|
||||
}
|
||||
#endif
|
||||
|
||||
//Do not execute for reflection probe captures
|
||||
if (currentCam.cameraType != CameraType.Reflection)
|
||||
{
|
||||
AddFlowMapPass(renderer, ref renderingData);
|
||||
AddDynamicEffectsPasses(renderer, ref renderingData);
|
||||
|
||||
//Do not execute for the scene-view camera in play-mode. Even if the tab is not active, it would render around it instead of the main camera
|
||||
var skipHeightPrePass = Application.isPlaying && heightPrePassSettings.disableInSceneView && currentCam.cameraType == CameraType.SceneView;
|
||||
|
||||
//In play-mode, strictly execute for the main camera
|
||||
skipHeightPrePass |= Application.isPlaying && !currentCam.CompareTag("MainCamera");
|
||||
|
||||
if (WillExecuteHeightPrePass && skipHeightPrePass == false)
|
||||
{
|
||||
//Debug.Log($"Executing height pre-pass for {currentCam.name}");
|
||||
|
||||
heightPrePass.Setup(heightPrePassSettings);
|
||||
renderer.EnqueuePass(heightPrePass);
|
||||
|
||||
if (HeightQuerySystem.QueryCount > 0)
|
||||
{
|
||||
heightQueryPass.Setup(this, heightReadbackCS);
|
||||
renderer.EnqueuePass(heightQueryPass);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Shader.SetGlobalInt(HeightPrePass._WaterHeightPrePassAvailable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
AddUnderwaterRenderingPasses(renderer, ref renderingData);
|
||||
|
||||
#if DEBUG_AVAILABLE
|
||||
if (RenderTargetDebugger.InspectedProperty > 0)
|
||||
{
|
||||
renderer.EnqueuePass(debugInspectorPass);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
constantsSetup.Dispose();
|
||||
heightPrePass.Dispose();
|
||||
heightQueryPass.Dispose();
|
||||
#if SWS_DEV
|
||||
terrainHeightPrePass.Dispose();
|
||||
#endif
|
||||
|
||||
DisposeFlowMapPass();
|
||||
DisposeDynamicEffectsPasses();
|
||||
DisposeUnderwaterRenderingPasses();
|
||||
}
|
||||
|
||||
#if DEBUG_AVAILABLE
|
||||
private class DebugInspectorPass : ScriptableRenderPass
|
||||
{
|
||||
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
||||
{
|
||||
DebugData debugData = frameData.Get<DebugData>();
|
||||
|
||||
//Whichever pass's render target PropertyID matches the selected one in the inspector window get assigned as the 'currentHandle'
|
||||
if (debugData.currentHandle.IsValid())
|
||||
{
|
||||
var destinationDesc = renderGraph.GetTextureDesc(debugData.currentHandle);
|
||||
destinationDesc.clearBuffer = false;
|
||||
|
||||
RenderTextureDescriptor rtDsc = new RenderTextureDescriptor
|
||||
{
|
||||
width = destinationDesc.width,
|
||||
height = destinationDesc.height,
|
||||
//If you're seeing an error here you are not using a compatible Unity version!
|
||||
graphicsFormat = destinationDesc.colorFormat,
|
||||
#if UNITY_6000_1_OR_NEWER
|
||||
colorFormat = RenderTextureFormat.Default,
|
||||
#endif
|
||||
volumeDepth = 1,
|
||||
dimension = destinationDesc.dimension,
|
||||
useMipMap = destinationDesc.useMipMap,
|
||||
msaaSamples = 1
|
||||
};
|
||||
|
||||
TextureDesc textureDesc = debugData.currentHandle.GetDescriptor(renderGraph);
|
||||
var allocate = RenderTargetDebugger.CurrentRT == null || RenderTargetDebugger.CurrentRT.rt == null;
|
||||
|
||||
if (allocate == false)
|
||||
{
|
||||
allocate |= RenderTargetDebugger.CurrentRT.rt.name != textureDesc.name;
|
||||
//RTMF :') Update to a supported Unity 6.0 version if this throws an error
|
||||
allocate |= RenderTargetDebugger.CurrentRT.rt.graphicsFormat != textureDesc.format;
|
||||
allocate |= RenderTargetDebugger.CurrentRT.rt.width != textureDesc.width;
|
||||
allocate |= RenderTargetDebugger.CurrentRT.rt.height != textureDesc.height;
|
||||
}
|
||||
|
||||
if (allocate)
|
||||
{
|
||||
textureDesc.name += " (Debug)";
|
||||
//Debug.Log($"Reallocating debug RT ({textureDesc.name})");
|
||||
|
||||
RenderTargetDebugger.CurrentRT?.Release();
|
||||
RenderTargetDebugger.CurrentRT = RTHandles.Alloc(rtDsc, name: textureDesc.name);
|
||||
}
|
||||
|
||||
//Idiotic function keeps causing memory leaks since Unity 2021
|
||||
//RenderingUtils.ReAllocateHandleIfNeeded(ref RenderTargetDebugger.CurrentRT, rtDsc, textureDesc.filterMode, textureDesc.wrapMode, textureDesc.anisoLevel, textureDesc.mipMapBias, textureDesc.name);
|
||||
|
||||
TextureHandle destination = renderGraph.ImportTexture(RenderTargetDebugger.CurrentRT);
|
||||
|
||||
if (destination.IsValid() == false)
|
||||
{
|
||||
throw new Exception("Failed to generate debugger texture");
|
||||
}
|
||||
else
|
||||
{
|
||||
var cameraData = frameData.Get<UniversalCameraData>();
|
||||
RenderTargetDebugger.CurrentCameraName = cameraData.camera.name;
|
||||
|
||||
//Copy TextureHandle into persistent RT
|
||||
renderGraph.AddCopyPass(debugData.currentHandle, destination, passName: "Water Debug");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTargetDebugger.CurrentRT = null;
|
||||
RenderTargetDebugger.CurrentCameraName = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#if !UNITY_6000_4_OR_NEWER
|
||||
#pragma warning disable CS0672
|
||||
#pragma warning disable CS0618
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { }
|
||||
#pragma warning restore CS0672
|
||||
#pragma warning restore CS0618
|
||||
#endif
|
||||
}
|
||||
#endif //DEBUG_AVAILABLE
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user