This commit is contained in:
zhangjiajia
2026-05-06 16:56:59 +08:00
parent 575626d3e1
commit 81ffaaeca6
1373 changed files with 145920 additions and 0 deletions

View File

@@ -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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c293f6238a2e7418f9348c7c99b8aacf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c8abc65ea1dd9433c972aa074694f5b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b884ed0c0033342c78bdc398e0060299
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 797f30610ca4c477fbbaaf38f758dc95
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: