'push'
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityHDRP
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
sealed class MaskRendererHDRP : MaskRenderer
|
||||
{
|
||||
const string k_Name = "Water Mask";
|
||||
MaskCustomPass _MaskCustomPass;
|
||||
GameObject _GameObject;
|
||||
|
||||
public MaskRendererHDRP(WaterRenderer water) : base(water) { }
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
base.Enable();
|
||||
|
||||
_GameObject = CustomPassHelpers.CreateOrUpdate
|
||||
(
|
||||
parent: _Water.Container.transform,
|
||||
k_Name,
|
||||
hide: !_Water._Debug._ShowHiddenObjects
|
||||
);
|
||||
|
||||
CustomPassHelpers.CreateOrUpdate
|
||||
(
|
||||
_GameObject,
|
||||
ref _MaskCustomPass,
|
||||
UnderwaterRenderer.k_DrawMask,
|
||||
CustomPassInjectionPoint.BeforeRendering
|
||||
);
|
||||
|
||||
_MaskCustomPass._MaskPass = this;
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
base.Disable();
|
||||
|
||||
if (_GameObject != null)
|
||||
{
|
||||
// Will also trigger Cleanup below.
|
||||
_GameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnBeginCameraRendering(Camera camera)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
sealed class MaskCustomPass : CustomPass
|
||||
{
|
||||
internal MaskRenderer _MaskPass;
|
||||
|
||||
// Called when the custom pass object is enabled making it somewhat useless.
|
||||
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
|
||||
{
|
||||
_MaskPass.Allocate();
|
||||
}
|
||||
|
||||
protected override void Cleanup()
|
||||
{
|
||||
_MaskPass.Release();
|
||||
}
|
||||
|
||||
protected override void Execute(CustomPassContext context)
|
||||
{
|
||||
var camera = context.hdCamera.camera;
|
||||
|
||||
if (!_MaskPass.ShouldExecute(camera))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// HDRP does not need ReAllocate. But it is easier to also call Allocate here.
|
||||
// Allocating RTHandles outside the render loop raises an error. Seriously, do not
|
||||
// attempt to optmize this away.
|
||||
_MaskPass.Allocate();
|
||||
_MaskPass.Execute(camera, context.cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // d_UnityHDRP
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c293f6238a2e7418f9348c7c99b8aacf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,63 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
sealed class MaskRendererBIRP : MaskRenderer
|
||||
{
|
||||
CommandBuffer _Commands;
|
||||
|
||||
public MaskRendererBIRP(WaterRenderer water) : base(water) { }
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
base.Enable();
|
||||
Allocate();
|
||||
}
|
||||
|
||||
|
||||
public override void OnBeginCameraRendering(Camera camera)
|
||||
{
|
||||
if (!ShouldExecute(camera))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_Commands ??= new()
|
||||
{
|
||||
name = UnderwaterRenderer.k_DrawMask,
|
||||
};
|
||||
|
||||
_Water.UpdateMatrices(camera);
|
||||
|
||||
var descriptor = Rendering.BIRP.GetCameraTargetDescriptor(camera);
|
||||
descriptor.useDynamicScale = camera.allowDynamicResolution;
|
||||
|
||||
Allocate();
|
||||
|
||||
ReAllocate(descriptor);
|
||||
Execute(camera, _Commands);
|
||||
|
||||
// Handles both forward and deferred.
|
||||
camera.AddCommandBuffer(CameraEvent.BeforeGBuffer, _Commands);
|
||||
camera.AddCommandBuffer(CameraEvent.BeforeDepthTexture, _Commands);
|
||||
}
|
||||
|
||||
public override void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
if (_Commands == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
camera.RemoveCommandBuffer(CameraEvent.BeforeGBuffer, _Commands);
|
||||
camera.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, _Commands);
|
||||
|
||||
_Commands.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8abc65ea1dd9433c972aa074694f5b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,103 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityURP
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
sealed class MaskRendererURP : MaskRenderer
|
||||
{
|
||||
readonly MaskRenderPass _MaskRenderPass = new();
|
||||
|
||||
public MaskRendererURP(WaterRenderer water) : base(water) { }
|
||||
|
||||
public override void OnBeginCameraRendering(Camera camera)
|
||||
{
|
||||
if (!ShouldExecute(camera))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_MaskRenderPass._Renderer = this;
|
||||
_MaskRenderPass.EnqueuePass(camera);
|
||||
}
|
||||
|
||||
public override void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
sealed partial class MaskRenderPass : ScriptableRenderPass
|
||||
{
|
||||
const string k_Name = "Crest.DrawMask";
|
||||
|
||||
internal MaskRenderer _Renderer;
|
||||
|
||||
public MaskRenderPass()
|
||||
{
|
||||
// Will always execute and matrices will be ready.
|
||||
renderPassEvent = RenderPassEvent.BeforeRenderingPrePasses;
|
||||
}
|
||||
|
||||
internal void EnqueuePass(Camera camera)
|
||||
{
|
||||
// TODO: check if we need to even enqueue a pass
|
||||
var renderer = camera.GetUniversalAdditionalCameraData().scriptableRenderer;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (renderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
_Renderer.Allocate();
|
||||
|
||||
// Enqueue the pass. This happens every frame.
|
||||
renderer.EnqueuePass(this);
|
||||
}
|
||||
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
class PassData
|
||||
{
|
||||
public UniversalCameraData _CameraData;
|
||||
public MaskRenderer _Renderer;
|
||||
}
|
||||
|
||||
public override void RecordRenderGraph(UnityEngine.Rendering.RenderGraphModule.RenderGraph graph, ContextContainer frame)
|
||||
{
|
||||
using (var builder = graph.AddUnsafePass<PassData>(k_Name, out var data))
|
||||
{
|
||||
builder.AllowPassCulling(false);
|
||||
|
||||
data._CameraData = frame.Get<UniversalCameraData>();
|
||||
data._Renderer = _Renderer;
|
||||
|
||||
builder.SetRenderFunc<PassData>((data, context) =>
|
||||
{
|
||||
var buffer = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
|
||||
data._Renderer.ReAllocate(data._CameraData.cameraTargetDescriptor);
|
||||
data._Renderer.Execute(data._CameraData.camera, buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[System.Obsolete]
|
||||
#endif
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData data)
|
||||
{
|
||||
var buffer = CommandBufferPool.Get(k_Name);
|
||||
_Renderer.ReAllocate(data.cameraData.cameraTargetDescriptor);
|
||||
_Renderer.Execute(data.cameraData.camera, buffer);
|
||||
context.ExecuteCommandBuffer(buffer);
|
||||
CommandBufferPool.Release(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // d_UnityURP
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b884ed0c0033342c78bdc398e0060299
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,314 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
abstract partial class MaskRenderer
|
||||
{
|
||||
protected const string k_MaskColor = "_Crest_MaskColor";
|
||||
protected const string k_MaskDepth = "_Crest_MaskDepth";
|
||||
|
||||
public static class ShaderIDs
|
||||
{
|
||||
public static readonly int s_WaterMaskTexture = Shader.PropertyToID("_Crest_WaterMaskTexture");
|
||||
public static readonly int s_WaterMaskDepthTexture = Shader.PropertyToID("_Crest_WaterMaskDepthTexture");
|
||||
}
|
||||
|
||||
public static MaskRenderer Instantiate(WaterRenderer water)
|
||||
{
|
||||
#if d_UnityHDRP
|
||||
if (RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
return new MaskRendererHDRP(water);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
#if d_UnityURP
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
return new MaskRendererURP(water);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
{
|
||||
return new MaskRendererBIRP(water);
|
||||
}
|
||||
}
|
||||
|
||||
// For PortalRenderer.
|
||||
public static System.Action s_OnAllocate;
|
||||
public static System.Action s_OnRelease;
|
||||
public static System.Action<RenderTextureDescriptor> s_OnReAllocate;
|
||||
|
||||
public MaskRenderer(WaterRenderer water)
|
||||
{
|
||||
_Water = water;
|
||||
}
|
||||
|
||||
public bool Enabled => true; //_Water.Underwater.Enabled;
|
||||
|
||||
internal RenderTargetIdentifier _ColorRTI;
|
||||
internal RenderTargetIdentifier _DepthRTI;
|
||||
|
||||
public RenderTextureDescriptor ColorDescriptor => ColorRT.descriptor;
|
||||
public RenderTextureDescriptor DepthDescriptor => DepthRT.descriptor;
|
||||
|
||||
public abstract void OnBeginCameraRendering(Camera camera);
|
||||
public abstract void OnEndCameraRendering(Camera camera);
|
||||
|
||||
|
||||
public virtual void Enable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Disable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
protected void UpdateColor(Texture color)
|
||||
{
|
||||
_ColorRTI = new(color, mipLevel: 0, CubemapFace.Unknown, depthSlice: -1);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_WaterMaskTexture, color);
|
||||
}
|
||||
|
||||
protected void UpdateDepth(Texture depth)
|
||||
{
|
||||
_DepthRTI = new(depth, mipLevel: 0, CubemapFace.Unknown, depthSlice: -1);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_WaterMaskDepthTexture, depth);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Pub/Sub
|
||||
//
|
||||
|
||||
[System.Flags]
|
||||
public enum MaskInput
|
||||
{
|
||||
None,
|
||||
Zero = 1 << 0,
|
||||
Color = 1 << 1,
|
||||
Depth = 1 << 2,
|
||||
Both = Color | Depth,
|
||||
}
|
||||
|
||||
protected MaskInput _Inputs;
|
||||
|
||||
protected readonly WaterRenderer _Water;
|
||||
|
||||
internal readonly Utility.SortedList<int, IMaskProvider> _Providers = new(Helpers.DuplicateComparison);
|
||||
internal readonly List<IMaskReceiver> _Receivers = new();
|
||||
|
||||
public interface IMaskProvider
|
||||
{
|
||||
MaskInput Allocate();
|
||||
MaskInput Write(Camera camera);
|
||||
void OnMaskPass(CommandBuffer commands, Camera camera, MaskRenderer mask);
|
||||
}
|
||||
|
||||
public interface IMaskReceiver
|
||||
{
|
||||
MaskInput Allocate();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_Inputs = MaskInput.None;
|
||||
|
||||
foreach (var receiver in _Receivers)
|
||||
{
|
||||
_Inputs |= receiver.Allocate();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Add(IMaskReceiver receiver)
|
||||
{
|
||||
if (_Receivers.Contains(receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Receivers.Add(receiver);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal void Remove(IMaskReceiver receiver)
|
||||
{
|
||||
if (!_Receivers.Remove(receiver))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal void Add(int queue, IMaskProvider provider)
|
||||
{
|
||||
if (_Providers.Contains(provider))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Providers.Add(queue, provider);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
internal void Remove(IMaskProvider provider)
|
||||
{
|
||||
if (!_Providers.Remove(provider))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void Execute(Camera camera, CommandBuffer commands)
|
||||
{
|
||||
foreach (var provider in _Providers)
|
||||
{
|
||||
if (provider.Value.Write(camera) == MaskInput.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
provider.Value.OnMaskPass(commands, camera, this);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ShouldExecute(Camera camera)
|
||||
{
|
||||
var input = MaskInput.None;
|
||||
|
||||
foreach (var providers in _Providers)
|
||||
{
|
||||
input |= providers.Value.Write(camera);
|
||||
}
|
||||
|
||||
return input != MaskInput.None;
|
||||
}
|
||||
}
|
||||
|
||||
// Holds common stuff for SRPs
|
||||
abstract partial class MaskRenderer
|
||||
{
|
||||
internal RTHandle _ColorRTH;
|
||||
internal RTHandle _DepthRTH;
|
||||
|
||||
|
||||
// Null check due to U6 not being able to cast if null (Unity bug?).
|
||||
public Texture ColorT => _ColorRTH?.rt;
|
||||
public Texture DepthT => _DepthRTH?.rt;
|
||||
public RTHandle ColorRTH => _ColorRTH;
|
||||
public RTHandle DepthRTH => _DepthRTH;
|
||||
public RenderTexture ColorRT => _ColorRTH;
|
||||
public RenderTexture DepthRT => _DepthRTH;
|
||||
|
||||
public void ResetRenderTarget(CommandBuffer commands)
|
||||
{
|
||||
CoreUtils.SetRenderTarget(commands, ColorRTH, DepthRTH);
|
||||
}
|
||||
|
||||
public void Allocate()
|
||||
{
|
||||
if (_Inputs.HasFlag(MaskInput.Color) && _ColorRTH == null)
|
||||
{
|
||||
_ColorRTH = RTHandles.Alloc
|
||||
(
|
||||
scaleFactor: Vector2.one,
|
||||
slices: TextureXR.slices,
|
||||
dimension: TextureXR.dimension,
|
||||
depthBufferBits: DepthBits.None,
|
||||
colorFormat: GraphicsFormat.R16_SFloat,
|
||||
enableRandomWrite: true,
|
||||
useDynamicScale: true,
|
||||
name: k_MaskColor
|
||||
);
|
||||
|
||||
UpdateColor(_ColorRTH);
|
||||
}
|
||||
|
||||
if (_Inputs.HasFlag(MaskInput.Depth) && _DepthRTH == null)
|
||||
{
|
||||
_DepthRTH = RTHandles.Alloc
|
||||
(
|
||||
scaleFactor: Vector2.one,
|
||||
slices: TextureXR.slices,
|
||||
dimension: TextureXR.dimension,
|
||||
depthBufferBits: Helpers.k_DepthBits,
|
||||
colorFormat: GraphicsFormat.None,
|
||||
enableRandomWrite: false,
|
||||
useDynamicScale: true,
|
||||
name: k_MaskDepth
|
||||
);
|
||||
|
||||
UpdateDepth(_DepthRTH);
|
||||
}
|
||||
|
||||
s_OnAllocate?.Invoke();
|
||||
}
|
||||
|
||||
public void ReAllocate(RenderTextureDescriptor descriptor)
|
||||
{
|
||||
// Shared settings. Enabling MSAA might be a good idea except cannot enable random
|
||||
// writes. Having a raster shader to remove artifacts is a workaround.
|
||||
// This looks safe to do as Unity's CopyDepthPass does the same.
|
||||
descriptor.bindMS = false;
|
||||
descriptor.msaaSamples = 1;
|
||||
|
||||
s_OnReAllocate?.Invoke(descriptor);
|
||||
|
||||
if (_Inputs.HasFlag(MaskInput.Depth))
|
||||
{
|
||||
descriptor.graphicsFormat = GraphicsFormat.None;
|
||||
descriptor.depthBufferBits = Helpers.k_DepthBufferBits;
|
||||
|
||||
if (RenderPipelineCompatibilityHelper.ReAllocateIfNeeded(ref _DepthRTH, descriptor, name: k_MaskDepth))
|
||||
{
|
||||
UpdateDepth(_DepthRTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (_Inputs.HasFlag(MaskInput.Color))
|
||||
{
|
||||
// NOTE: Intel iGPU for Metal and DirectX both had issues with R16 (2021.11.18).
|
||||
descriptor.graphicsFormat = GraphicsFormat.R16_SFloat;
|
||||
descriptor.depthBufferBits = 0;
|
||||
descriptor.enableRandomWrite = true;
|
||||
|
||||
if (RenderPipelineCompatibilityHelper.ReAllocateIfNeeded(ref _ColorRTH, descriptor, name: k_MaskColor))
|
||||
{
|
||||
UpdateColor(_ColorRTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
_ColorRTH?.Release();
|
||||
_DepthRTH?.Release();
|
||||
|
||||
// Set to null possibly due to Initialize/Destroy overlap.
|
||||
_ColorRTH = null;
|
||||
_DepthRTH = null;
|
||||
|
||||
s_OnRelease?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 797f30610ca4c477fbbaaf38f758dc95
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user