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,111 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
using UnityEngine;
using UnityEngine.Rendering;
namespace WaveHarmonic.Crest
{
interface ICommandWrapper : IPropertyWrapper
{
void SetInvertCulling(bool invert);
void DrawFullScreenTriangle(Material material, int pass, MaterialPropertyBlock block = null);
void DrawMesh(Mesh mesh, Matrix4x4 matrix, Material material, int pass = -1, MaterialPropertyBlock block = null);
}
readonly struct CommandWrapper : ICommandWrapper
{
public CommandBuffer Commands { get; }
public CommandWrapper(CommandBuffer commands) => Commands = commands;
public void SetFloat(int param, float value) => Commands.SetGlobalFloat(param, value);
public void SetFloatArray(int param, float[] value) => Commands.SetGlobalFloatArray(param, value);
public void SetTexture(int param, Texture value) => Commands.SetGlobalTexture(param, value);
public void SetVector(int param, Vector4 value) => Commands.SetGlobalVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => Commands.SetGlobalVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => Commands.SetGlobalMatrix(param, value);
public void SetInteger(int param, int value) => Commands.SetGlobalInteger(param, value);
public void SetBoolean(int param, bool value) => Commands.SetGlobalInteger(param, value ? 1 : 0);
public void GetBlock() { }
public void SetBlock() { }
public void SetInvertCulling(bool invert) => Commands.SetInvertCulling(invert);
public void DrawFullScreenTriangle(Material material, int pass = -1, MaterialPropertyBlock block = null)
{
Commands.DrawProcedural
(
Matrix4x4.identity,
material,
pass,
MeshTopology.Triangles,
vertexCount: 3,
instanceCount: 1,
block
);
}
public void DrawMesh(Mesh mesh, Matrix4x4 matrix, Material material, int pass = -1, MaterialPropertyBlock block = null)
{
Commands.DrawMesh
(
mesh,
matrix,
material,
submeshIndex: 0,
pass,
block
);
}
}
#if UNITY_6000_0_OR_NEWER
readonly struct RasterCommandWrapper : ICommandWrapper
{
public RasterCommandBuffer Commands { get; }
public RasterCommandWrapper(RasterCommandBuffer commands) => Commands = commands;
public void SetFloat(int param, float value) => Commands.SetGlobalFloat(param, value);
public void SetFloatArray(int param, float[] value) => Commands.SetGlobalFloatArray(param, value);
// WARNING: bypasses RG checks. Only use for textures external to RG.
public void SetTexture(int param, Texture value) => Commands.m_WrappedCommandBuffer.SetGlobalTexture(param, value);
public void SetVector(int param, Vector4 value) => Commands.SetGlobalVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => Commands.SetGlobalVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => Commands.SetGlobalMatrix(param, value);
public void SetInteger(int param, int value) => Commands.SetGlobalInteger(param, value);
public void SetBoolean(int param, bool value) => Commands.SetGlobalInteger(param, value ? 1 : 0);
public void GetBlock() { }
public void SetBlock() { }
public void SetInvertCulling(bool invert) => Commands.SetInvertCulling(invert);
public void DrawFullScreenTriangle(Material material, int pass, MaterialPropertyBlock block = null)
{
Commands.DrawProcedural
(
Matrix4x4.identity,
material,
pass,
MeshTopology.Triangles,
vertexCount: 3,
instanceCount: 1,
block
);
}
public void DrawMesh(Mesh mesh, Matrix4x4 matrix, Material material, int pass = -1, MaterialPropertyBlock block = null)
{
Commands.DrawMesh
(
mesh,
matrix,
material,
submeshIndex: 0,
pass,
block
);
}
}
#endif // UNITY_6000_0_OR_NEWER
}

View File

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

View File

@@ -0,0 +1,136 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#if d_UnityHDRP
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
namespace WaveHarmonic.Crest
{
class CustomPass : UnityEngine.Rendering.HighDefinition.CustomPass
{
internal GameObject _GameObject;
internal CustomPassVolume _Volume;
}
static class CustomPassHelpers
{
internal static List<CustomPassVolume> s_Volumes = new();
// Create or update Game Object.
public static GameObject CreateOrUpdate
(
Transform parent,
string name,
bool hide = true
)
{
GameObject gameObject = null;
// Find the existing custom pass volume.
// During recompiles, the reference will be lost so we need to find the game object. It could be limited to
// the editor if it is safe to do so, but there is a potential for leaking game objects.
if (gameObject == null)
{
var transform = parent.Find(name);
if (transform != null)
{
gameObject = transform.gameObject;
}
}
// Create or update the custom pass volume.
if (gameObject == null)
{
gameObject = new()
{
name = name,
hideFlags = hide ? HideFlags.HideAndDontSave : HideFlags.DontSave,
};
// Place the custom pass under the water renderer since it is easier to find later. Transform.Find can
// find inactive game objects unlike GameObject.Find.
gameObject.transform.parent = parent;
}
else
{
gameObject.hideFlags = hide ? HideFlags.HideAndDontSave : HideFlags.DontSave;
gameObject.SetActive(true);
}
return gameObject;
}
// Create or update Custom Pass Volume.
public static void CreateOrUpdate<T>
(
GameObject gameObject,
ref T pass,
string name,
CustomPassInjectionPoint injectionPoint,
int priority = 0
)
where T : CustomPass, new()
{
CustomPassVolume volume = null;
gameObject.GetComponents(s_Volumes);
foreach (var v in s_Volumes)
{
if (v.injectionPoint == injectionPoint)
{
volume = v;
break;
}
}
// Create the custom pass volume if it does not exist.
if (volume == null)
{
// It appears that this is currently the only way to add a custom pass.
volume = gameObject.AddComponent<CustomPassVolume>();
volume.injectionPoint = injectionPoint;
volume.isGlobal = true;
volume.priority = priority;
}
// Create custom pass.
pass ??= new()
{
name = name,
targetColorBuffer = UnityEngine.Rendering.HighDefinition.CustomPass.TargetBuffer.None,
targetDepthBuffer = UnityEngine.Rendering.HighDefinition.CustomPass.TargetBuffer.None,
};
// Add custom pass.
if (!volume.customPasses.Contains(pass))
{
volume.customPasses.Add(pass);
}
pass._GameObject = gameObject;
pass._Volume = volume;
}
public static void Update<T>(GameObject go, T pass, CustomPassInjectionPoint point, int priority = 0) where T : CustomPass
{
CustomPassVolume volume = null;
go.GetComponents(s_Volumes);
foreach (var v in s_Volumes)
{
if (v.customPasses.Contains(pass))
{
volume = v;
break;
}
}
volume.injectionPoint = point;
volume.priority = priority;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,52 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Adapted from:
// https://github.com/keijiro/LightProbeUtility/blob/85c93577338e10a52dd53f263056de08d883337a/Assets/LightProbeUtility.cs
// With fixes from:
// https://github.com/keijiro/LightProbeUtility/pull/2
using UnityEngine;
namespace WaveHarmonic.Crest
{
static class LightProbeUtility
{
static readonly int[] s_SHA =
{
Shader.PropertyToID("unity_SHAr"),
Shader.PropertyToID("unity_SHAg"),
Shader.PropertyToID("unity_SHAb")
};
static readonly int[] s_SHB =
{
Shader.PropertyToID("unity_SHBr"),
Shader.PropertyToID("unity_SHBg"),
Shader.PropertyToID("unity_SHBb")
};
static readonly int s_SHC = Shader.PropertyToID("unity_SHC");
public static void SetSHCoefficients<T>(this T properties, Vector3 position) where T : IPropertyWrapper
{
LightProbes.GetInterpolatedProbe(position, null, out var sh);
// Constant + Linear.
for (var i = 0; i < 3; i++)
{
properties.SetVector(s_SHA[i], new(sh[i, 3], sh[i, 1], sh[i, 2], sh[i, 0] - sh[i, 6]));
}
// Quadratic polynomials.
for (var i = 0; i < 3; i++)
{
properties.SetVector(s_SHB[i], new(sh[i, 4], sh[i, 5], sh[i, 6] * 3, sh[i, 7]));
}
// Final quadratic polynomial.
properties.SetVector(s_SHC, new(sh[0, 8], sh[1, 8], sh[2, 8], 1));
}
}
}

View File

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

View File

@@ -0,0 +1,189 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
using UnityEngine;
using UnityEngine.Rendering;
namespace WaveHarmonic.Crest
{
/// <summary>
/// Unified interface for setting properties on both materials and material property blocks
/// </summary>
interface IPropertyWrapper
{
void SetFloat(int param, float value);
void SetFloatArray(int param, float[] value);
void SetVector(int param, Vector4 value);
void SetVectorArray(int param, Vector4[] value);
void SetTexture(int param, Texture value);
void SetMatrix(int param, Matrix4x4 matrix);
void SetInteger(int param, int value);
void SetBoolean(int param, bool value);
void GetBlock();
void SetBlock();
}
static class PropertyWrapperConstants
{
internal const string k_NoShaderMessage = "Cannot create required material because shader <i>{0}</i> could not be found or loaded."
+ " Try right clicking the Crest folder in the Project view and selecting Reimport, and checking for errors.";
}
readonly struct PropertyWrapperBuffer : IPropertyWrapper
{
public CommandBuffer Buffer { get; }
public PropertyWrapperBuffer(CommandBuffer mpb) => Buffer = mpb;
public void SetFloat(int param, float value) => Buffer.SetGlobalFloat(param, value);
public void SetFloatArray(int param, float[] value) => Buffer.SetGlobalFloatArray(param, value);
public void SetTexture(int param, Texture value) => Buffer.SetGlobalTexture(param, value);
public void SetVector(int param, Vector4 value) => Buffer.SetGlobalVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => Buffer.SetGlobalVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => Buffer.SetGlobalMatrix(param, value);
public void SetInteger(int param, int value) => Buffer.SetGlobalInteger(param, value);
public void SetBoolean(int param, bool value) => Buffer.SetGlobalInteger(param, value ? 1 : 0);
public void GetBlock() { }
public void SetBlock() { }
}
readonly struct PropertyWrapperRenderer : IPropertyWrapper
{
public MaterialPropertyBlock PropertyBlock { get; }
public Renderer Renderer { get; }
public PropertyWrapperRenderer(Renderer renderer, MaterialPropertyBlock block)
{
Renderer = renderer;
PropertyBlock = block;
}
public void SetFloat(int param, float value) => PropertyBlock.SetFloat(param, value);
public void SetFloatArray(int param, float[] value) => PropertyBlock.SetFloatArray(param, value);
public void SetTexture(int param, Texture value) => PropertyBlock.SetTexture(param, value);
public void SetBuffer(int param, ComputeBuffer value) => PropertyBlock.SetBuffer(param, value);
public void SetVector(int param, Vector4 value) => PropertyBlock.SetVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => PropertyBlock.SetVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => PropertyBlock.SetMatrix(param, value);
public void SetInteger(int param, int value) => PropertyBlock.SetInteger(param, value);
public void SetBoolean(int param, bool value) => PropertyBlock.SetInteger(param, value ? 1 : 0);
public void GetBlock() => Renderer.GetPropertyBlock(PropertyBlock);
public void SetBlock() => Renderer.SetPropertyBlock(PropertyBlock);
}
[System.Serializable]
readonly struct PropertyWrapperMaterial : IPropertyWrapper
{
public Material Material { get; }
public PropertyWrapperMaterial(Material material) => Material = material;
public PropertyWrapperMaterial(Shader shader)
{
Debug.Assert(shader != null, "Crest: PropertyWrapperMaterial: Cannot create required material because shader is null");
Material = new(shader);
}
public PropertyWrapperMaterial(string shaderPath)
{
var shader = Shader.Find(shaderPath);
Debug.AssertFormat(shader != null, $"Crest.PropertyWrapperMaterial: {PropertyWrapperConstants.k_NoShaderMessage}", shaderPath);
Material = new(shader);
}
public void SetFloat(int param, float value) => Material.SetFloat(param, value);
public void SetFloatArray(int param, float[] value) => Material.SetFloatArray(param, value);
public void SetTexture(int param, Texture value) => Material.SetTexture(param, value);
public void SetBuffer(int param, ComputeBuffer value) => Material.SetBuffer(param, value);
public void SetVector(int param, Vector4 value) => Material.SetVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => Material.SetVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => Material.SetMatrix(param, value);
public void SetInteger(int param, int value) => Material.SetInteger(param, value);
public void SetBoolean(int param, bool value) => Material.SetInteger(param, value ? 1 : 0);
public void GetBlock() { }
public void SetBlock() { }
// Non-Interface Methods
public void SetKeyword(in LocalKeyword keyword, bool value) => Material.SetKeyword(keyword, value);
}
readonly struct PropertyWrapperMPB : IPropertyWrapper
{
public MaterialPropertyBlock MaterialPropertyBlock { get; }
public PropertyWrapperMPB(MaterialPropertyBlock mpb) => MaterialPropertyBlock = mpb;
public void SetFloat(int param, float value) => MaterialPropertyBlock.SetFloat(param, value);
public void SetFloatArray(int param, float[] value) => MaterialPropertyBlock.SetFloatArray(param, value);
public void SetTexture(int param, Texture value) => MaterialPropertyBlock.SetTexture(param, value);
public void SetVector(int param, Vector4 value) => MaterialPropertyBlock.SetVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => MaterialPropertyBlock.SetVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => MaterialPropertyBlock.SetMatrix(param, value);
public void SetInteger(int param, int value) => MaterialPropertyBlock.SetInteger(param, value);
public void SetBoolean(int param, bool value) => MaterialPropertyBlock.SetInteger(param, value ? 1 : 0);
public void GetBlock() { }
public void SetBlock() { }
}
[System.Serializable]
readonly struct PropertyWrapperCompute : IPropertyWrapper
{
readonly CommandBuffer _Buffer;
readonly ComputeShader _Shader;
readonly int _Kernel;
public PropertyWrapperCompute(CommandBuffer buffer, ComputeShader shader, int kernel)
{
_Buffer = buffer;
_Shader = shader;
_Kernel = kernel;
}
public void SetFloat(int param, float value) => _Buffer.SetComputeFloatParam(_Shader, param, value);
public void SetFloatArray(int param, float[] value) => _Buffer.SetGlobalFloatArray(param, value);
public void SetInteger(int param, int value) => _Buffer.SetComputeIntParam(_Shader, param, value);
public void SetBoolean(int param, bool value) => _Buffer.SetComputeIntParam(_Shader, param, value ? 1 : 0);
public void SetTexture(int param, Texture value) => _Buffer.SetComputeTextureParam(_Shader, _Kernel, param, value);
public void SetTexture(int param, RenderTargetIdentifier value) => _Buffer.SetComputeTextureParam(_Shader, _Kernel, param, value);
public void SetBuffer(int param, ComputeBuffer value) => _Buffer.SetComputeBufferParam(_Shader, _Kernel, param, value);
public void SetVector(int param, Vector4 value) => _Buffer.SetComputeVectorParam(_Shader, param, value);
public void SetVectorArray(int param, Vector4[] value) => _Buffer.SetComputeVectorArrayParam(_Shader, param, value);
public void SetMatrix(int param, Matrix4x4 value) => _Buffer.SetComputeMatrixParam(_Shader, param, value);
public void GetBlock() { }
public void SetBlock() { }
// Non-Interface Methods
public void SetKeyword(in LocalKeyword keyword, bool value) => _Buffer.SetKeyword(_Shader, keyword, value);
public void Dispatch(int x, int y, int z) => _Buffer.DispatchCompute(_Shader, _Kernel, x, y, z);
}
[System.Serializable]
readonly struct PropertyWrapperComputeStandalone : IPropertyWrapper
{
readonly ComputeShader _Shader;
readonly int _Kernel;
public PropertyWrapperComputeStandalone(ComputeShader shader, int kernel)
{
_Shader = shader;
_Kernel = kernel;
}
public void SetFloat(int param, float value) => _Shader.SetFloat(param, value);
public void SetFloatArray(int param, float[] value) => _Shader.SetFloats(param, value);
public void SetInteger(int param, int value) => _Shader.SetInt(param, value);
public void SetBoolean(int param, bool value) => _Shader.SetBool(param, value);
public void SetTexture(int param, Texture value) => _Shader.SetTexture(_Kernel, param, value);
public void SetBuffer(int param, ComputeBuffer value) => _Shader.SetBuffer(_Kernel, param, value);
public void SetConstantBuffer(int param, ComputeBuffer value) => _Shader.SetConstantBuffer(param, value, 0, value.stride);
public void SetVector(int param, Vector4 value) => _Shader.SetVector(param, value);
public void SetVectorArray(int param, Vector4[] value) => _Shader.SetVectorArray(param, value);
public void SetMatrix(int param, Matrix4x4 value) => _Shader.SetMatrix(param, value);
public void GetBlock() { }
public void SetBlock() { }
// Non-Interface Methods
public void SetKeyword(in LocalKeyword keyword, bool value) => _Shader.SetKeyword(keyword, value);
public void Dispatch(int x, int y, int z) => _Shader.Dispatch(_Kernel, x, y, z);
}
}

View File

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

View File

@@ -0,0 +1,37 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// RTHandles for Built-In Render Pipeline.
// We cannot call dispose ourselves, but it does not seem to be a problem.
using UnityEngine;
namespace WaveHarmonic.Crest.Utility
{
static class RTHandles
{
public static void Initialize()
{
if (!RenderPipelineHelper.IsLegacy)
{
return;
}
// Check whether already initialized.
if (UnityEngine.Rendering.RTHandles.maxWidth > 1)
{
return;
}
UnityEngine.Rendering.RTHandles.Initialize(Screen.width, Screen.height);
UnityEngine.Rendering.RTHandles.SetHardwareDynamicResolutionState(false);
}
public static void OnBeginCameraRendering(Camera camera)
{
// Forget Dynamic Scaling, as is broken for Shader Graph and Post-Processing anyway.
// The only foreseeable problem is if a third party calls this with a different size.
UnityEngine.Rendering.RTHandles.SetReferenceSize(camera.pixelWidth, camera.pixelHeight);
}
}
}

View File

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

View File

@@ -0,0 +1,84 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#if d_UnityURP
#if UNITY_6000_0_OR_NEWER
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
namespace WaveHarmonic.Crest
{
static class RenderGraphHelper
{
public struct Handle
{
RTHandle _RTHandle;
TextureHandle _TextureHandle;
public readonly RTHandle Texture { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _RTHandle ?? _TextureHandle; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Handle(RTHandle handle) => new() { _RTHandle = handle };
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Handle(TextureHandle handle) => new() { _TextureHandle = handle };
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator RTHandle(Handle texture) => texture.Texture;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator TextureHandle(Handle texture) => texture._TextureHandle;
}
static readonly FieldInfo s_WrappedContext = typeof(UnsafeGraphContext).GetField("wrappedContext", BindingFlags.NonPublic | BindingFlags.Instance);
public static ScriptableRenderContext GetRenderContext(this UnsafeGraphContext unsafeContext)
{
return ((InternalRenderGraphContext)s_WrappedContext.GetValue(unsafeContext)).renderContext;
}
public static ContextContainer GetFrameData(this ref RenderingData renderingData)
{
return renderingData.frameData;
}
internal class PassData
{
#pragma warning disable IDE1006 // Naming Styles
public UniversalCameraData cameraData;
public UniversalRenderingData renderingData;
public Handle colorTargetHandle;
public Handle depthTargetHandle;
#pragma warning restore IDE1006 // Naming Styles
public void Init(ContextContainer frameData, IUnsafeRenderGraphBuilder builder = null)
{
var resources = frameData.Get<UniversalResourceData>();
cameraData = frameData.Get<UniversalCameraData>();
renderingData = frameData.Get<UniversalRenderingData>();
if (builder == null)
{
#pragma warning disable CS0618 // Type or member is obsolete
colorTargetHandle = cameraData.renderer.cameraColorTargetHandle;
depthTargetHandle = cameraData.renderer.cameraDepthTargetHandle;
#pragma warning restore CS0618 // Type or member is obsolete
}
else
{
colorTargetHandle = resources.activeColorTexture;
depthTargetHandle = resources.activeDepthTexture;
builder.UseTexture(colorTargetHandle, AccessFlags.ReadWrite);
builder.UseTexture(depthTargetHandle, AccessFlags.ReadWrite);
}
}
}
}
}
#endif // UNITY_6000_0_OR_NEWER
#endif // d_UnityURP

View File

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

View File

@@ -0,0 +1,169 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
using UnityEngine;
using UnityEngine.Rendering;
namespace WaveHarmonic.Crest
{
static class RenderPipelineCompatibilityHelper
{
// Taken from:
// https://github.com/Unity-Technologies/Graphics/blob/19ec161f3f752db865597374b3ad1b3eaf110097/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs#L588-L634
/// <summary>
/// Return true if handle does not match descriptor
/// </summary>
/// <param name="handle">RTHandle to check (can be null)</param>
/// <param name="descriptor">Descriptor for the RTHandle to match</param>
/// <param name="filterMode">Filtering mode of the RTHandle.</param>
/// <param name="wrapMode">Addressing mode of the RTHandle.</param>
/// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
/// <param name="anisoLevel">Anisotropic filtering level.</param>
/// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
/// <param name="name">Name of the RTHandle.</param>
/// <param name="scaled">Check if the RTHandle has auto scaling enabled if not, check the widths and heights</param>
/// <returns></returns>
internal static bool RTHandleNeedsReAlloc(
RTHandle handle,
in RenderTextureDescriptor descriptor,
FilterMode filterMode,
TextureWrapMode wrapMode,
bool isShadowMap,
int anisoLevel,
float mipMapBias,
string name,
bool scaled)
{
if (handle == null || handle.rt == null)
return true;
if (handle.useScaling != scaled)
return true;
if (!scaled && (handle.rt.width != descriptor.width || handle.rt.height != descriptor.height))
return true;
return
handle.rt.descriptor.depthBufferBits != descriptor.depthBufferBits ||
(handle.rt.descriptor.depthBufferBits == (int)DepthBits.None && !isShadowMap && handle.rt.descriptor.graphicsFormat != descriptor.graphicsFormat) ||
handle.rt.descriptor.dimension != descriptor.dimension ||
handle.rt.descriptor.enableRandomWrite != descriptor.enableRandomWrite ||
handle.rt.descriptor.useMipMap != descriptor.useMipMap ||
handle.rt.descriptor.autoGenerateMips != descriptor.autoGenerateMips ||
handle.rt.descriptor.msaaSamples != descriptor.msaaSamples ||
handle.rt.descriptor.bindMS != descriptor.bindMS ||
handle.rt.descriptor.useDynamicScale != descriptor.useDynamicScale ||
handle.rt.descriptor.memoryless != descriptor.memoryless ||
handle.rt.filterMode != filterMode ||
handle.rt.wrapMode != wrapMode ||
handle.rt.anisoLevel != anisoLevel ||
handle.rt.mipMapBias != mipMapBias ||
handle.name != name;
}
// https://github.com/Unity-Technologies/Graphics/blob/19ec161f3f752db865597374b3ad1b3eaf110097/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs#L666-L695
/// <summary>
/// Re-allocate fixed-size RTHandle if it is not allocated or doesn't match the descriptor
/// </summary>
/// <param name="handle">RTHandle to check (can be null)</param>
/// <param name="descriptor">Descriptor for the RTHandle to match</param>
/// <param name="filterMode">Filtering mode of the RTHandle.</param>
/// <param name="wrapMode">Addressing mode of the RTHandle.</param>
/// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
/// <param name="anisoLevel">Anisotropic filtering level.</param>
/// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
/// <param name="name">Name of the RTHandle.</param>
/// <returns></returns>
public static bool ReAllocateIfNeeded(
ref RTHandle handle,
in RenderTextureDescriptor descriptor,
FilterMode filterMode = FilterMode.Point,
TextureWrapMode wrapMode = TextureWrapMode.Repeat,
bool isShadowMap = false,
int anisoLevel = 1,
float mipMapBias = 0,
string name = "")
{
if (RTHandleNeedsReAlloc(handle, descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name, false))
{
handle?.Release();
handle = RTHandles.Alloc(descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name);
return true;
}
return false;
}
// https://github.com/Unity-Technologies/Graphics/blob/19ec161f3f752db865597374b3ad1b3eaf110097/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs#L697-L729
/// <summary>
/// Re-allocate dynamically resized RTHandle if it is not allocated or doesn't match the descriptor
/// </summary>
/// <param name="handle">RTHandle to check (can be null)</param>
/// <param name="scaleFactor">Constant scale for the RTHandle size computation.</param>
/// <param name="descriptor">Descriptor for the RTHandle to match</param>
/// <param name="filterMode">Filtering mode of the RTHandle.</param>
/// <param name="wrapMode">Addressing mode of the RTHandle.</param>
/// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
/// <param name="anisoLevel">Anisotropic filtering level.</param>
/// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
/// <param name="name">Name of the RTHandle.</param>
/// <returns>If the RTHandle should be re-allocated</returns>
public static bool ReAllocateIfNeeded(
ref RTHandle handle,
Vector2 scaleFactor,
in RenderTextureDescriptor descriptor,
FilterMode filterMode = FilterMode.Point,
TextureWrapMode wrapMode = TextureWrapMode.Repeat,
bool isShadowMap = false,
int anisoLevel = 1,
float mipMapBias = 0,
string name = "")
{
var usingConstantScale = handle != null && handle.useScaling && handle.scaleFactor == scaleFactor;
if (!usingConstantScale || RTHandleNeedsReAlloc(handle, descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name, true))
{
handle?.Release();
handle = RTHandles.Alloc(scaleFactor, descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name);
return true;
}
return false;
}
// https://github.com/Unity-Technologies/Graphics/blob/19ec161f3f752db865597374b3ad1b3eaf110097/Packages/com.unity.render-pipelines.universal/Runtime/RenderingUtils.cs#L731-L764
/// <summary>
/// Re-allocate dynamically resized RTHandle if it is not allocated or doesn't match the descriptor
/// </summary>
/// <param name="handle">RTHandle to check (can be null)</param>
/// <param name="scaleFunc">Function used for the RTHandle size computation.</param>
/// <param name="descriptor">Descriptor for the RTHandle to match</param>
/// <param name="filterMode">Filtering mode of the RTHandle.</param>
/// <param name="wrapMode">Addressing mode of the RTHandle.</param>
/// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param>
/// <param name="anisoLevel">Anisotropic filtering level.</param>
/// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param>
/// <param name="name">Name of the RTHandle.</param>
/// <returns>If an allocation was done</returns>
public static bool ReAllocateIfNeeded(
ref RTHandle handle,
ScaleFunc scaleFunc,
in RenderTextureDescriptor descriptor,
FilterMode filterMode = FilterMode.Point,
TextureWrapMode wrapMode = TextureWrapMode.Repeat,
bool isShadowMap = false,
int anisoLevel = 1,
float mipMapBias = 0,
string name = "")
{
var usingScaleFunction = handle != null && handle.useScaling && handle.scaleFactor == Vector2.zero;
if (!usingScaleFunction || RTHandleNeedsReAlloc(handle, descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name, true))
{
handle?.Release();
handle = RTHandles.Alloc(scaleFunc, descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name);
return true;
}
return false;
}
}
}

View File

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

View File

@@ -0,0 +1,57 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering.Universal;
namespace WaveHarmonic.Crest
{
enum RenderPipeline
{
Legacy,
HighDefinition,
Universal,
}
sealed class RenderPipelineHelper
{
public static RenderPipeline RenderPipeline => GraphicsSettings.currentRenderPipeline switch
{
#if d_UnityHDRP
HDRenderPipelineAsset => RenderPipeline.HighDefinition,
#endif
#if d_UnityURP
UniversalRenderPipelineAsset => RenderPipeline.Universal,
#endif
_ => RenderPipeline.Legacy,
};
// GraphicsSettings.currentRenderPipeline could be from the graphics setting or current quality level.
public static bool IsLegacy => GraphicsSettings.currentRenderPipeline == null;
public static bool IsUniversal
{
get
{
#if d_UnityURP
return GraphicsSettings.currentRenderPipeline is UniversalRenderPipelineAsset;
#else
return false;
#endif
}
}
public static bool IsHighDefinition
{
get
{
#if d_UnityHDRP
return GraphicsSettings.currentRenderPipeline is HDRenderPipelineAsset;
#else
return false;
#endif
}
}
}
}

View File

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

View File

@@ -0,0 +1,261 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// ENABLE_VR is defined if the platform supports XR.
// d_UnityModuleVR is defined if the VR module is installed.
// VR module depends on XR module (which does nothing by itself) so we only need to check the VR module.
#if ENABLE_VR && d_UnityModuleVR
#define _XR_ENABLED
#endif
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering.Universal;
using UnityEngine.XR;
namespace WaveHarmonic.Crest
{
static partial class Rendering
{
// Adaptor layer for XR module similar to Unity's XRGraphics/XRSRPSettings.
// We cannot use theirs as they keep on renaming it…
public static bool EnabledXR
{
get
{
#if _XR_ENABLED
return XRSettings.enabled;
#else
return false;
#endif
}
}
static bool SinglePassXR
{
get
{
#if _XR_ENABLED
return XRSettings.enabled && (XRSettings.stereoRenderingMode is XRSettings.StereoRenderingMode.SinglePassInstanced or XRSettings.StereoRenderingMode.SinglePassMultiview);
#else
return false;
#endif
}
}
static bool MultiPassXR
{
get
{
#if _XR_ENABLED
return XRSettings.enabled && XRSettings.stereoRenderingMode is XRSettings.StereoRenderingMode.MultiPass;
#else
return false;
#endif
}
}
public static partial class BIRP
{
[Conditional("_XR_ENABLED")]
public static void EnableXR(CommandBuffer commands, Camera camera)
{
#if _XR_ENABLED
if (!SinglePassXR || !camera.stereoEnabled)
{
return;
}
commands.EnableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
[Conditional("_XR_ENABLED")]
public static void DisableXR(CommandBuffer commands, Camera camera)
{
#if _XR_ENABLED
if (!SinglePassXR || !camera.stereoEnabled)
{
return;
}
commands.DisableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
}
//
// Stereo Rendering
//
#if _XR_ENABLED
public static partial class BIRP
{
// NOTE: This is the same value as Unity, but in the future it could be higher.
const int k_MaximumViewsXR = 2;
static partial class ShaderIDs
{
public static readonly int s_StereoInverseViewProjection = Shader.PropertyToID("_Crest_StereoInverseViewProjection");
}
static readonly List<XRDisplaySubsystem> s_DisplayListXR = new();
// Unity only supports one display right now.
static XRDisplaySubsystem DisplayXR => XRSettings.enabled ? s_DisplayListXR[0] : null;
static Matrix4x4[] InverseViewProjectionMatrixXR { get; set; } = new Matrix4x4[2];
static Texture2DArray s_WhiteTextureXR = null;
public static Texture2DArray WhiteTextureXR
{
get
{
if (s_WhiteTextureXR == null)
{
s_WhiteTextureXR = TextureArrayHelpers.CreateTexture2DArray(Texture2D.whiteTexture, k_MaximumViewsXR);
s_WhiteTextureXR.name = "_Crest_WhiteTextureXR";
}
return s_WhiteTextureXR;
}
}
public static void SetMatricesXR(Camera camera)
{
if (!camera.stereoEnabled || !SinglePassXR)
{
return;
}
SubsystemManager.GetSubsystems(s_DisplayListXR);
// XR SPI only has one pass by definition.
DisplayXR.GetRenderPass(renderPassIndex: 0, out var xrPass);
xrPass.GetRenderParameter(camera, renderParameterIndex: 0, out var xrLeftEye);
xrPass.GetRenderParameter(camera, renderParameterIndex: 1, out var xrRightEye);
// We must opt for renderIntoTexture for Unity to handle Y flip.
InverseViewProjectionMatrixXR[0] = (GL.GetGPUProjectionMatrix(xrLeftEye.projection, true) * xrLeftEye.view).inverse;
InverseViewProjectionMatrixXR[1] = (GL.GetGPUProjectionMatrix(xrRightEye.projection, true) * xrRightEye.view).inverse;
Shader.SetGlobalMatrixArray(ShaderIDs.s_StereoInverseViewProjection, InverseViewProjectionMatrixXR);
}
}
#endif // _XR_ENABLED
#if d_UnityURP
public static class URP
{
[Conditional("_XR_ENABLED")]
public static void EnableXR(CommandBuffer commands, CameraData camera)
{
#if _XR_ENABLED
// We need to check the mask or it will cause entire pipeline to output black. Appears to only affect URP.
if (!SinglePassXR || !camera.xrRendering || camera.camera.stereoTargetEye != StereoTargetEyeMask.Both)
{
return;
}
commands.EnableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
[Conditional("_XR_ENABLED")]
public static void DisableXR(CommandBuffer commands, CameraData camera)
{
#if _XR_ENABLED
if (!SinglePassXR || !camera.xrRendering || camera.camera.stereoTargetEye != StereoTargetEyeMask.Both)
{
return;
}
commands.DisableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
#if UNITY_6000_0_OR_NEWER
[Conditional("_XR_ENABLED")]
public static void EnableXR(CommandBuffer commands, UniversalCameraData camera)
{
#if _XR_ENABLED
// We need to check the mask or it will cause entire pipeline to output black. Appears to only affect URP.
if (!SinglePassXR || !camera.xrRendering || camera.camera.stereoTargetEye != StereoTargetEyeMask.Both)
{
return;
}
commands.EnableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
[Conditional("_XR_ENABLED")]
public static void DisableXR(CommandBuffer commands, UniversalCameraData camera)
{
#if _XR_ENABLED
if (!SinglePassXR || !camera.xrRendering || camera.camera.stereoTargetEye != StereoTargetEyeMask.Both)
{
return;
}
commands.DisableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
#endif // UNITY_6000_0_OR_NEWER
}
#endif // d_UnityURP
#if d_UnityHDRP
public static class HDRP
{
[Conditional("_XR_ENABLED")]
public static void EnableXR(CommandBuffer commands, HDAdditionalCameraData camera)
{
#if _XR_ENABLED
if (!SinglePassXR || camera == null || !camera.xrRendering)
{
return;
}
commands.EnableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
[Conditional("_XR_ENABLED")]
public static void DisableXR(CommandBuffer commands, HDAdditionalCameraData camera)
{
#if _XR_ENABLED
if (!SinglePassXR || camera == null || !camera.xrRendering)
{
return;
}
commands.DisableShaderKeyword("STEREO_INSTANCING_ON");
#endif
}
public static bool SkipPassXR(ref int index, HDAdditionalCameraData data)
{
#if _XR_ENABLED
if (MultiPassXR && data != null && data.xrRendering)
{
// Alternate between left and right eye.
index += 1;
index %= 2;
}
else
#endif
{
index = -1;
}
// Skip if rendering the right eye.
return index == 1;
}
}
#endif // d_UnityHDRP
}
}

View File

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

View File

@@ -0,0 +1,94 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
#if ENABLE_VR && d_UnityModuleVR
#define _XR_ENABLED
#endif
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.XR;
namespace WaveHarmonic.Crest
{
static partial class Rendering
{
public static partial class BIRP
{
static partial class ShaderIDs
{
public static readonly int s_InverseViewProjection = Shader.PropertyToID("_Crest_InverseViewProjection");
}
public static Texture GetWhiteTexture(Camera camera)
{
#if _XR_ENABLED
if (camera.stereoEnabled && SinglePassXR)
{
return WhiteTextureXR;
}
#endif
return Texture2D.whiteTexture;
}
public static void SetMatrices(Camera camera)
{
Shader.SetGlobalMatrix(ShaderIDs.s_InverseViewProjection, (GL.GetGPUProjectionMatrix(camera.projectionMatrix, true) * camera.worldToCameraMatrix).inverse);
#if _XR_ENABLED
SetMatricesXR(camera);
#endif
}
public enum FrameBufferFormatOverride
{
None,
LDR,
HDR,
}
public static RenderTextureDescriptor GetCameraTargetDescriptor(Camera camera, FrameBufferFormatOverride hdrOverride = FrameBufferFormatOverride.None)
{
RenderTextureDescriptor descriptor;
#if _XR_ENABLED
if (camera.stereoEnabled)
{
// Will not set the following correctly:
// - HDR format
descriptor = XRSettings.eyeTextureDesc;
}
else
#endif
{
// As recommended by Unity, in 2021.2 using SystemInfo.GetGraphicsFormat with DefaultFormat.LDR is
// necessary or gamma color space texture is returned:
// https://docs.unity3d.com/ScriptReference/Experimental.Rendering.DefaultFormat.html
descriptor = new(camera.pixelWidth, camera.pixelHeight, SystemInfo.GetGraphicsFormat(DefaultFormat.LDR), 0);
}
// Set HDR format.
if (camera.allowHDR && QualitySettings.activeColorSpace == ColorSpace.Linear)
{
var format = DefaultFormat.HDR;
if (hdrOverride is not FrameBufferFormatOverride.None)
{
format = hdrOverride is FrameBufferFormatOverride.HDR ? DefaultFormat.HDR : DefaultFormat.LDR;
}
#if UNITY_ANDROID || UNITY_IOS || UNITY_TVOS
else
{
format = DefaultFormat.LDR;
}
#endif
descriptor.graphicsFormat = SystemInfo.GetGraphicsFormat(format);
}
return descriptor;
}
}
}
}

View File

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

View File

@@ -0,0 +1,45 @@
// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
using UnityEngine;
namespace WaveHarmonic.Crest
{
static class TextureArrayHelpers
{
internal const int k_SmallTextureSize = 4;
public static Texture2D CreateTexture2D(Color color, TextureFormat format)
{
var texture = new Texture2D(k_SmallTextureSize, k_SmallTextureSize, format, false, false);
var pixels = new Color[texture.height * texture.width];
for (var i = 0; i < pixels.Length; i++)
{
pixels[i] = color;
}
texture.SetPixels(pixels);
texture.Apply();
return texture;
}
public static Texture2DArray CreateTexture2DArray(Texture2D texture, int depth)
{
var array = new Texture2DArray(
k_SmallTextureSize, k_SmallTextureSize,
depth,
texture.format,
false,
false
);
for (var textureArrayIndex = 0; textureArrayIndex < array.depth; textureArrayIndex++)
{
Graphics.CopyTexture(texture, 0, 0, array, textureArrayIndex, 0);
}
array.Apply();
return array;
}
}
}

View File

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