还原水插件
This commit is contained in:
@@ -22,7 +22,6 @@ namespace WaveHarmonic.Crest
|
||||
public static int s_WaterLineSnappedPosition = Shader.PropertyToID("_Crest_WaterLineSnappedPosition");
|
||||
public static int s_WaterLineResolution = Shader.PropertyToID("_Crest_WaterLineResolution");
|
||||
public static int s_WaterLineTexel = Shader.PropertyToID("_Crest_WaterLineTexel");
|
||||
public static int s_WaterLineFlatWater = Shader.PropertyToID("_Crest_WaterLineFlatWater");
|
||||
}
|
||||
|
||||
RenderTexture _HeightRT;
|
||||
@@ -51,13 +50,6 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
internal void UpdateDisplacedSurfaceData(Camera camera)
|
||||
{
|
||||
Helpers.SetGlobalBoolean(ShaderIDs.s_WaterLineFlatWater, IsQuadMesh);
|
||||
|
||||
if (IsQuadMesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// World size of the texture. Formula should effectively cover the camera.
|
||||
var size = 1f + (camera.nearClipPlane * 2f);
|
||||
|
||||
@@ -92,11 +84,9 @@ namespace WaveHarmonic.Crest
|
||||
BindDisplacedSurfaceData(wrapper);
|
||||
|
||||
var lod = (int)Builder.PatchType.Interior;
|
||||
var mpb = PerCascadeMPB[lod];
|
||||
var mpb = _PerCascadeMPB.Current[lod];
|
||||
|
||||
var viewpoint = _Water.Viewpoint;
|
||||
|
||||
if (viewpoint == null || (viewpoint != camera.transform && Vector3.Distance(viewpoint.position, camera.transform.position) > 0.01f))
|
||||
if (_Water.Viewpoint != camera.transform && Vector3.Distance(_Water.Viewpoint.position, camera.transform.position) > 0.01f)
|
||||
{
|
||||
foreach (var chunk in _Water.Surface.Chunks)
|
||||
{
|
||||
|
||||
@@ -27,9 +27,6 @@ namespace WaveHarmonic.Crest
|
||||
case nameof(_Layer):
|
||||
SetLayer((int)previous, _Layer);
|
||||
break;
|
||||
case nameof(_MeshType):
|
||||
_Water.Rebuild();
|
||||
break;
|
||||
case nameof(_ChunkTemplate):
|
||||
// We have to rebuild, as we instantiate entire GO. If we restricted it to just a
|
||||
// MeshRenderer, then we could just replace those.
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
// Our reflections do not need them.
|
||||
if (camera == _Water.Reflections.ReflectionCamera)
|
||||
if (camera == WaterReflections.CurrentCamera)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -114,7 +114,6 @@ namespace WaveHarmonic.Crest
|
||||
var rld = new RendererListDesc(_ShaderTagID, context.cullingResults, camera)
|
||||
{
|
||||
layerMask = 1 << _Water.Surface.Layer,
|
||||
// Required to set the pass. Use shader to keep WB material overrides.
|
||||
overrideShader = _Water.Surface.Material.shader,
|
||||
overrideShaderPassIndex = _Water.Surface.Material.FindPass("Forward"),
|
||||
renderQueueRange = RenderQueueRange.transparent,
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
CommandBuffer _DrawWaterSurfaceBuffer;
|
||||
MaterialPropertyBlock _QuadMeshMPB;
|
||||
|
||||
void OnBeginCameraRenderingLegacy(Camera camera)
|
||||
{
|
||||
@@ -41,6 +40,8 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
camera.depthTextureMode |= DepthTextureMode.Depth;
|
||||
|
||||
_DrawWaterSurfaceBuffer ??= new() { name = WaterRenderer.k_DrawWater };
|
||||
_DrawWaterSurfaceBuffer.Clear();
|
||||
|
||||
@@ -110,15 +111,6 @@ namespace WaveHarmonic.Crest
|
||||
// Always enabled.
|
||||
commands.SetShaderKeyword("LIGHTPROBE_SH", true);
|
||||
|
||||
if (IsQuadMesh)
|
||||
{
|
||||
_QuadMeshMPB ??= new();
|
||||
new PropertyWrapperMPB(_QuadMeshMPB).SetSHCoefficients(Root.position);
|
||||
Render(camera, commands, Material, pass: 0, mpb: _QuadMeshMPB);
|
||||
commands.EndSample(k_DrawWaterSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateChunkVisibility(camera);
|
||||
|
||||
foreach (var chunk in Chunks)
|
||||
@@ -145,7 +137,9 @@ namespace WaveHarmonic.Crest
|
||||
chunk.Bind();
|
||||
}
|
||||
|
||||
commands.DrawRenderer(chunk.Rend, renderer.sharedMaterial, 0, 0);
|
||||
var mpb = new PropertyWrapperMPB(chunk._MaterialPropertyBlock);
|
||||
mpb.SetSHCoefficients(chunk.transform.position);
|
||||
commands.DrawMesh(chunk._Mesh, chunk.transform.localToWorldMatrix, renderer.sharedMaterial, 0, 0, chunk._MaterialPropertyBlock);
|
||||
}
|
||||
|
||||
commands.EndSample(k_DrawWaterSurface);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if UNITY_EDITOR
|
||||
#if d_UnityHDRP
|
||||
|
||||
using UnityEngine;
|
||||
@@ -57,7 +56,7 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera.cameraType != CameraType.SceneView || (_Water.SingleViewpoint && camera != _Water.Viewer))
|
||||
if (camera.cameraType != CameraType.SceneView || camera != _Water.Viewer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -69,4 +68,3 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
#endif // d_UnityHDRP
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
@@ -14,7 +12,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
void OnPreRenderWaterLevelDepthTexture(Camera camera)
|
||||
{
|
||||
if (camera.cameraType != CameraType.SceneView || (_Water.SingleViewpoint && camera != _Water.Viewer))
|
||||
if (camera.cameraType != CameraType.SceneView || camera != _Water.Viewer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -40,5 +38,3 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
#if d_UnityURP
|
||||
|
||||
using UnityEngine;
|
||||
@@ -39,7 +37,7 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera.cameraType != CameraType.SceneView || (_Water.SingleViewpoint && camera != _Water.Viewer))
|
||||
if (camera.cameraType != CameraType.SceneView || camera != _Water.Viewer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -71,10 +69,7 @@ namespace WaveHarmonic.Crest
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if URP_COMPATIBILITY_MODE
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
[System.Obsolete]
|
||||
#endif
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData data)
|
||||
@@ -84,10 +79,8 @@ namespace WaveHarmonic.Crest
|
||||
context.ExecuteCommandBuffer(buffer);
|
||||
CommandBufferPool.Release(buffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // d_UnityURP
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// FIXME: Broken for BIRP on MacOS. Either platform specific problem or bug in Unity.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
@@ -12,38 +11,16 @@ namespace WaveHarmonic.Crest
|
||||
partial class SurfaceRenderer
|
||||
{
|
||||
RenderTexture _WaterLevelDepthTexture;
|
||||
internal RenderTexture WaterLevelDepthTexture { get; private set; }
|
||||
internal RenderTexture WaterLevelDepthTexture => _WaterLevelDepthTexture;
|
||||
RenderTargetIdentifier _WaterLevelDepthTarget;
|
||||
Material _WaterLevelDepthMaterial;
|
||||
|
||||
internal RenderTexture GetWaterLevelDepthTexture(Camera camera)
|
||||
{
|
||||
// Do not use SeparateViewpoint here, as this is called outside the camera loop.
|
||||
if (_Water.SingleViewpoint)
|
||||
{
|
||||
return WaterLevelDepthTexture;
|
||||
}
|
||||
else if (_PerCameraLevelDepthTexture.ContainsKey(camera))
|
||||
{
|
||||
return _PerCameraLevelDepthTexture[camera];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const string k_WaterLevelDepthTextureName = "Crest Water Level Depth Texture";
|
||||
|
||||
void ExecuteWaterLevelDepthTexture(Camera camera, CommandBuffer buffer)
|
||||
{
|
||||
if (_Water.SingleViewpoint && _WaterLevelDepthTexture == null)
|
||||
{
|
||||
_WaterLevelDepthTexture = new(0, 0, 0);
|
||||
WaterLevelDepthTexture = _WaterLevelDepthTexture;
|
||||
}
|
||||
|
||||
LoadCameraDataLDT(camera);
|
||||
|
||||
WaterLevelDepthTexture.name = k_WaterLevelDepthTextureName;
|
||||
Helpers.CreateRenderTargetTextureReference(ref _WaterLevelDepthTexture, ref _WaterLevelDepthTarget);
|
||||
_WaterLevelDepthTexture.name = k_WaterLevelDepthTextureName;
|
||||
|
||||
if (_WaterLevelDepthMaterial == null)
|
||||
{
|
||||
@@ -64,19 +41,11 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
// Depth texture.
|
||||
// Always release to handle screen size changes.
|
||||
WaterLevelDepthTexture.Release();
|
||||
_WaterLevelDepthTexture.Release();
|
||||
descriptor.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat;
|
||||
descriptor.depthBufferBits = 0;
|
||||
WaterLevelDepthTexture.descriptor = descriptor;
|
||||
WaterLevelDepthTexture.Create();
|
||||
|
||||
_WaterLevelDepthTarget = new
|
||||
(
|
||||
WaterLevelDepthTexture,
|
||||
mipLevel: 0,
|
||||
CubemapFace.Unknown,
|
||||
depthSlice: -1 // Bind all XR slices.
|
||||
);
|
||||
Helpers.SafeCreateRenderTexture(ref _WaterLevelDepthTexture, descriptor);
|
||||
_WaterLevelDepthTexture.Create();
|
||||
|
||||
// Convert.
|
||||
Helpers.Blit(buffer, _WaterLevelDepthTarget, Rendering.BIRP.UtilityMaterial, (int)Rendering.BIRP.UtilityPass.Copy);
|
||||
@@ -112,48 +81,4 @@ namespace WaveHarmonic.Crest
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Multiple Viewpoints
|
||||
// Technically, this should always store an RT per camera, as it is screen-space.
|
||||
// But having it opt-in is not a bad idea.
|
||||
partial class SurfaceRenderer
|
||||
{
|
||||
internal Dictionary<Camera, RenderTexture> _PerCameraLevelDepthTexture = new();
|
||||
|
||||
void LoadCameraDataLDT(Camera camera)
|
||||
{
|
||||
if (_Water.SingleViewpoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_PerCameraLevelDepthTexture.ContainsKey(camera))
|
||||
{
|
||||
var descriptor = new RenderTextureDescriptor(camera.pixelWidth, camera.pixelHeight)
|
||||
{
|
||||
graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.None,
|
||||
depthBufferBits = 32,
|
||||
};
|
||||
|
||||
WaterLevelDepthTexture = new(descriptor);
|
||||
_PerCameraLevelDepthTexture.Add(camera, WaterLevelDepthTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
WaterLevelDepthTexture = _PerCameraLevelDepthTexture[camera];
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveCameraDataLDT(Camera camera)
|
||||
{
|
||||
if (_PerCameraLevelDepthTexture.ContainsKey(camera))
|
||||
{
|
||||
_PerCameraLevelDepthTexture[camera].Release();
|
||||
Helpers.Destroy(_PerCameraLevelDepthTexture[camera]);
|
||||
_PerCameraLevelDepthTexture.Remove(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
_Water = water;
|
||||
renderPassEvent = RenderPassEvent.BeforeRenderingTransparents;
|
||||
ConfigureInput(ScriptableRenderPassInput.None);
|
||||
|
||||
// Copy color happens between "after skybox" and "before transparency".
|
||||
ConfigureInput(ScriptableRenderPassInput.Color | ScriptableRenderPassInput.Depth);
|
||||
}
|
||||
|
||||
public static void Enable(WaterRenderer water)
|
||||
@@ -56,14 +58,12 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
|
||||
// Our reflections do not need them.
|
||||
if (camera == _Water.Reflections.ReflectionCamera)
|
||||
if (camera == WaterReflections.CurrentCamera)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var material = _Water.Surface.Material;
|
||||
|
||||
if (material == null)
|
||||
if (Instance._Water.Surface.Material == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -73,15 +73,6 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Copy color happens between "after skybox" and "before transparency".
|
||||
var pass = ScriptableRenderPassInput.Color | ScriptableRenderPassInput.Depth;
|
||||
#if d_Crest_SimpleTransparency
|
||||
pass = ScriptableRenderPassInput.None;
|
||||
#endif
|
||||
ConfigureInput(pass);
|
||||
}
|
||||
|
||||
camera.GetUniversalAdditionalCameraData().scriptableRenderer.EnqueuePass(Instance);
|
||||
}
|
||||
|
||||
@@ -122,7 +113,6 @@ namespace WaveHarmonic.Crest
|
||||
var rld = new RendererListDesc(_ShaderTagID, renderingData.cullResults, cameraData.camera)
|
||||
{
|
||||
layerMask = 1 << _Water.Surface.Layer,
|
||||
// Required to set the pass. Use shader to keep WB material overrides.
|
||||
overrideShader = _Water.Surface.Material.shader,
|
||||
overrideShaderPassIndex = 0, // UniversalForward
|
||||
renderQueueRange = RenderQueueRange.transparent,
|
||||
@@ -139,10 +129,7 @@ namespace WaveHarmonic.Crest
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if URP_COMPATIBILITY_MODE
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
[System.Obsolete]
|
||||
#endif
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
@@ -157,7 +144,6 @@ namespace WaveHarmonic.Crest
|
||||
var rld = new RendererListDesc(_ShaderTagID, renderingData.cullResults, renderingData.cameraData.camera)
|
||||
{
|
||||
layerMask = 1 << _Water.Surface.Layer,
|
||||
// Required to set the pass. Use shader to keep WB material overrides.
|
||||
overrideShader = _Water.Surface.Material.shader,
|
||||
overrideShaderPassIndex = 0, // UniversalForward
|
||||
renderQueueRange = RenderQueueRange.transparent,
|
||||
@@ -170,7 +156,6 @@ namespace WaveHarmonic.Crest
|
||||
context.ExecuteCommandBuffer(buffer);
|
||||
CommandBufferPool.Release(buffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,19 +5,10 @@ using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
using WaveHarmonic.Crest.Utility;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
enum WaterMeshType
|
||||
{
|
||||
[Tooltip("Chunks implemented as a clip-map.")]
|
||||
Chunks,
|
||||
|
||||
[Tooltip("A single quad.\n\nOptimal for demanding platforms like mobile. Displacement will only contribute to normals.")]
|
||||
Quad,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the water surface.
|
||||
/// </summary>
|
||||
@@ -36,12 +27,6 @@ namespace WaveHarmonic.Crest
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _Enabled = true;
|
||||
|
||||
[@Label("Mesh")]
|
||||
[Tooltip("The meshing solution for the water surface.")]
|
||||
[@DecoratedField]
|
||||
[@SerializeField]
|
||||
WaterMeshType _MeshType;
|
||||
|
||||
[Tooltip("The water chunk renderers will have this layer.")]
|
||||
[@Layer]
|
||||
[@GenerateAPI]
|
||||
@@ -89,12 +74,6 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
[@Heading("Advanced")]
|
||||
|
||||
[Tooltip("Rules to exclude cameras from surface rendering.\n\nThese are exclusion rules, so for all cameras, select Nothing. These rules are applied on top of the Layer rules.")]
|
||||
[@DecoratedField]
|
||||
[@GenerateAPI]
|
||||
[SerializeField]
|
||||
internal WaterCameraExclusion _CameraExclusions = WaterCameraExclusion.Hidden | WaterCameraExclusion.Reflection;
|
||||
|
||||
[Tooltip("How to handle self-intersections of the water surface.\n\nThey can be caused by choppy waves which can cause a flipped underwater effect. When not using the portals/volumes, this fix is only applied when within 2 metres of the water surface. Automatic will disable the fix if portals/volumes are used which is the recommend setting.")]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal SurfaceSelfIntersectionFixMode _SurfaceSelfIntersectionFixMode = SurfaceSelfIntersectionFixMode.Automatic;
|
||||
@@ -143,8 +122,8 @@ namespace WaveHarmonic.Crest
|
||||
// Level of Detail
|
||||
//
|
||||
|
||||
readonly MaterialPropertyBlock[] _PerCascadeMPB = new MaterialPropertyBlock[Lod.k_MaximumSlices];
|
||||
internal MaterialPropertyBlock[] PerCascadeMPB { get; private set; }
|
||||
// Extra frame is for motion vectors.
|
||||
internal BufferedData<MaterialPropertyBlock[]> _PerCascadeMPB = new(2, () => new MaterialPropertyBlock[Lod.k_MaximumSlices]);
|
||||
|
||||
// We are computing these values to be optimal based on the base mesh vertex density.
|
||||
float _LodAlphaBlackPointFade;
|
||||
@@ -176,7 +155,6 @@ namespace WaveHarmonic.Crest
|
||||
internal Material _MotionVectorMaterial;
|
||||
|
||||
internal Material AboveOrBelowSurfaceMaterial => _VolumeMaterial == null ? _Material : _VolumeMaterial;
|
||||
internal bool IsQuadMesh => _MeshType == WaterMeshType.Quad;
|
||||
|
||||
|
||||
//
|
||||
@@ -222,23 +200,8 @@ namespace WaveHarmonic.Crest
|
||||
public static readonly int s_ChunkGeometryGridWidth = Shader.PropertyToID("_Crest_ChunkGeometryGridWidth");
|
||||
public static readonly int s_ChunkFarNormalsWeight = Shader.PropertyToID("_Crest_ChunkFarNormalsWeight");
|
||||
public static readonly int s_ChunkNormalScrollSpeed = Shader.PropertyToID("_Crest_ChunkNormalScrollSpeed");
|
||||
public static readonly int s_NormalMapParameters = Shader.PropertyToID("_Crest_NormalMapParameters");
|
||||
}
|
||||
|
||||
bool _ForceRenderingOff;
|
||||
|
||||
internal bool ForceRenderingOff
|
||||
{
|
||||
get => _ForceRenderingOff;
|
||||
set
|
||||
{
|
||||
_ForceRenderingOff = value;
|
||||
|
||||
if (_Enabled)
|
||||
{
|
||||
Root.gameObject.SetActive(!_ForceRenderingOff && !IsQuadMesh);
|
||||
}
|
||||
}
|
||||
public static readonly int s_ChunkMeshScaleAlphaSource = Shader.PropertyToID("_Crest_ChunkMeshScaleAlphaSource");
|
||||
public static readonly int s_ChunkGeometryGridWidthSource = Shader.PropertyToID("_Crest_ChunkGeometryGridWidthSource");
|
||||
}
|
||||
|
||||
internal void Initialize()
|
||||
@@ -248,10 +211,19 @@ namespace WaveHarmonic.Crest
|
||||
Root.position = _Water.Position;
|
||||
Root.localScale = new(_Water.Scale, 1f, _Water.Scale);
|
||||
|
||||
// Populate MPBs with defaults. Protects against null exceptions etc.
|
||||
PerCascadeMPB = _PerCascadeMPB;
|
||||
NormalMapParameters = _NormalMapParameters;
|
||||
InitializeProperties();
|
||||
// Populate MPBs with defaults.
|
||||
for (var index = 0; index < _Water.LodLevels; index++)
|
||||
{
|
||||
for (var frame = 0; frame < 2; frame++)
|
||||
{
|
||||
var mpb = new MaterialPropertyBlock();
|
||||
mpb.SetInteger(Lod.ShaderIDs.s_LodIndex, index);
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkFarNormalsWeight, 1f);
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkMeshScaleAlpha, 0f);
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkMeshScaleAlphaSource, 0f);
|
||||
_PerCascadeMPB.Previous(frame)[index] = mpb;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolution is 4 tiles across.
|
||||
var baseMeshDensity = _Water.LodResolution * 0.25f / _Water._GeometryDownSampleFactor;
|
||||
@@ -325,11 +297,6 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsQuadMesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryUtility.CalculateFrustumPlanes(camera, _CameraFrustumPlanes);
|
||||
|
||||
foreach (var chunk in Chunks)
|
||||
@@ -380,43 +347,20 @@ namespace WaveHarmonic.Crest
|
||||
_Rebuild = false;
|
||||
}
|
||||
|
||||
internal void DisableChunks()
|
||||
internal void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
foreach (var chunk in Chunks)
|
||||
if (!WaterRenderer.ShouldRender(camera, Layer))
|
||||
{
|
||||
if (chunk.Rend != null) chunk.Rend.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ShouldRender(Camera camera)
|
||||
{
|
||||
if (!_Enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.ShouldRender(camera, Layer, _CameraExclusions))
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Our planar reflection camera must never render the surface.
|
||||
if (camera == _Water.Reflections.ReflectionCamera)
|
||||
if (camera == WaterReflections.CurrentCamera)
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Material == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
if (!ShouldRender(camera))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -424,7 +368,7 @@ namespace WaveHarmonic.Crest
|
||||
WritePerCameraMaterialParameters(camera);
|
||||
|
||||
// Motion Vectors.
|
||||
if (ShouldRenderMotionVectors(camera) && QueueMotionVectors)
|
||||
if (ShouldRenderMotionVectors(camera) && _QueueMotionVectors)
|
||||
{
|
||||
UpdateChunkVisibility(camera);
|
||||
|
||||
@@ -434,7 +378,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable format
|
||||
#if d_UnityURP
|
||||
if (RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
@@ -450,26 +393,19 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
OnBeginCameraRenderingLegacy(camera);
|
||||
}
|
||||
#pragma warning restore format
|
||||
}
|
||||
|
||||
internal void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
_DoneChunkVisibility = false;
|
||||
|
||||
// Restore in case exclusion culling ran.
|
||||
foreach (var chunk in Chunks)
|
||||
{
|
||||
if (chunk.Rend != null && !chunk._Culled) chunk.Rend.enabled = true;
|
||||
}
|
||||
|
||||
if (!WaterRenderer.ShouldRender(camera, Layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Our planar reflection camera must never render the surface.
|
||||
if (camera == _Water.Reflections.ReflectionCamera)
|
||||
if (camera == WaterReflections.CurrentCamera)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -480,20 +416,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeProperties()
|
||||
{
|
||||
System.Array.Fill(NormalMapParameters, new Vector4(0, 0, 1, 0));
|
||||
|
||||
// Populate MPBs with defaults.
|
||||
for (var index = 0; index < PerCascadeMPB.Length; index++)
|
||||
{
|
||||
var block = new MaterialPropertyBlock();
|
||||
block.SetInteger(Lod.ShaderIDs.s_LodIndex, index);
|
||||
block.SetFloat(ShaderIDs.s_ChunkFarNormalsWeight, 1f);
|
||||
PerCascadeMPB[index] = block;
|
||||
}
|
||||
}
|
||||
|
||||
void WritePerCameraMaterialParameters(Camera camera)
|
||||
{
|
||||
if (Material == null)
|
||||
@@ -520,16 +442,14 @@ namespace WaveHarmonic.Crest
|
||||
var value = _SurfaceSelfIntersectionFixMode switch
|
||||
{
|
||||
SurfaceSelfIntersectionFixMode.On =>
|
||||
!_Water._PerCameraHeightReady
|
||||
? ForceFacing.None
|
||||
: height < -2f
|
||||
height < -2f
|
||||
? ForceFacing.BelowWater
|
||||
: height > 2f
|
||||
? ForceFacing.AboveWater
|
||||
: ForceFacing.None,
|
||||
// Skip for portals as it is possible to see both sides of the surface at any position.
|
||||
SurfaceSelfIntersectionFixMode.Automatic =>
|
||||
_Water.Portaled || !_Water._PerCameraHeightReady
|
||||
_Water.Portaled
|
||||
? ForceFacing.None
|
||||
: height < -2f
|
||||
? ForceFacing.BelowWater
|
||||
@@ -551,27 +471,12 @@ namespace WaveHarmonic.Crest
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
if (_ForceRenderingOff)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LoadCameraData(_Water.CurrentCamera);
|
||||
|
||||
Root.position = _Water.Position;
|
||||
Root.localScale = new(_Water.Scale, 1f, _Water.Scale);
|
||||
|
||||
Root.gameObject.SetActive(!IsQuadMesh);
|
||||
Material.SetKeyword(new(Material.shader, "_CREST_CUSTOM_MESH"), IsQuadMesh);
|
||||
|
||||
_PerCascadeMPB.Flip();
|
||||
WritePerCascadeInstanceData();
|
||||
|
||||
if (IsQuadMesh)
|
||||
{
|
||||
LateUpdateQuadMesh();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var chunk in Chunks)
|
||||
{
|
||||
chunk.UpdateMeshBounds(_Water, this);
|
||||
@@ -601,48 +506,60 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
var levels = _Water.LodLevels;
|
||||
var texel = _Water.LodResolution * 0.25f / _Water._GeometryDownSampleFactor;
|
||||
var mpbsCurrent = _PerCascadeMPB.Current;
|
||||
var mpbsPrevious = _PerCascadeMPB.Previous(1);
|
||||
|
||||
// LOD 0
|
||||
{
|
||||
var mpb = mpbsCurrent[0];
|
||||
|
||||
if (_Water.WriteMotionVectors)
|
||||
{
|
||||
// NOTE: it may be more optimal to store in an array than fetching from MPB.
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkMeshScaleAlphaSource, mpbsPrevious[0].GetFloat(ShaderIDs.s_ChunkMeshScaleAlpha));
|
||||
}
|
||||
|
||||
// Blend LOD 0 shape in/out to avoid pop, if scale could increase.
|
||||
PerCascadeMPB[0].SetFloat(ShaderIDs.s_ChunkMeshScaleAlpha, _Water.ScaleCouldIncrease ? _Water.ViewerAltitudeLevelAlpha : 0f);
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkMeshScaleAlpha, _Water.ScaleCouldIncrease ? _Water.ViewerAltitudeLevelAlpha : 0f);
|
||||
}
|
||||
|
||||
// LOD N
|
||||
{
|
||||
var mpb = mpbsCurrent[levels - 1];
|
||||
|
||||
// Blend furthest normals scale in/out to avoid pop, if scale could reduce.
|
||||
var weight = _Water.ScaleCouldDecrease ? _Water.ViewerAltitudeLevelAlpha : 1f;
|
||||
PerCascadeMPB[levels - 1].SetFloat(ShaderIDs.s_ChunkFarNormalsWeight, weight);
|
||||
NormalMapParameters[levels - 1] = new(0, 0, weight, 0);
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkFarNormalsWeight, _Water.ScaleCouldDecrease ? _Water.ViewerAltitudeLevelAlpha : 1f);
|
||||
}
|
||||
|
||||
for (var index = 0; index < levels; index++)
|
||||
{
|
||||
var mpb = PerCascadeMPB[index];
|
||||
var mpbCurrent = mpbsCurrent[index];
|
||||
var mpbPrevious = mpbsPrevious[index];
|
||||
|
||||
// geometry data
|
||||
// compute grid size of geometry. take the long way to get there - make sure we land exactly on a power of two
|
||||
// and not inherit any of the lossy-ness from lossyScale.
|
||||
var scale = _Water.CascadeData.Current[index].x;
|
||||
var scale = _Water._CascadeData.Current[index].x;
|
||||
var width = scale / texel;
|
||||
|
||||
mpb.SetFloat(ShaderIDs.s_ChunkGeometryGridWidth, width);
|
||||
if (_Water.WriteMotionVectors)
|
||||
{
|
||||
// NOTE: it may be more optimal to store in an array than fetching from MPB.
|
||||
mpbPrevious.SetFloat(ShaderIDs.s_ChunkGeometryGridWidthSource, mpbCurrent.GetFloat(ShaderIDs.s_ChunkGeometryGridWidth));
|
||||
}
|
||||
|
||||
mpbCurrent.SetFloat(ShaderIDs.s_ChunkGeometryGridWidth, width);
|
||||
|
||||
var mul = 1.875f; // fudge 1
|
||||
var pow = 1.4f; // fudge 2
|
||||
var texelWidth = width / _Water._GeometryDownSampleFactor;
|
||||
var speed = new Vector2
|
||||
mpbCurrent.SetVector(ShaderIDs.s_ChunkNormalScrollSpeed, new
|
||||
(
|
||||
Mathf.Pow(Mathf.Log(1f + 2f * texelWidth) * mul, pow),
|
||||
Mathf.Pow(Mathf.Log(1f + 4f * texelWidth) * mul, pow)
|
||||
);
|
||||
|
||||
mpb.SetVector(ShaderIDs.s_ChunkNormalScrollSpeed, speed);
|
||||
|
||||
var normals = NormalMapParameters[index];
|
||||
normals.x = speed.x;
|
||||
normals.y = speed.y;
|
||||
NormalMapParameters[index] = normals;
|
||||
Mathf.Pow(Mathf.Log(1f + 4f * texelWidth) * mul, pow),
|
||||
0,
|
||||
0
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +649,7 @@ namespace WaveHarmonic.Crest
|
||||
_CanSkipCulling = WaterBody.WaterBodies.Count == 0;
|
||||
}
|
||||
|
||||
internal void Render(Camera camera, CommandBuffer buffer, Material material = null, int pass = 0, bool culled = false, MaterialPropertyBlock mpb = null)
|
||||
internal void Render(Camera camera, CommandBuffer buffer, Material material = null, int pass = 0, bool culled = false)
|
||||
{
|
||||
var noMaterial = material == null;
|
||||
|
||||
@@ -741,12 +658,6 @@ namespace WaveHarmonic.Crest
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsQuadMesh)
|
||||
{
|
||||
buffer.DrawMesh(Helpers.QuadMesh, Matrix4x4.TRS(Root.position, Quaternion.Euler(90f, 0, 0), new(10000, 10000, 1)), noMaterial ? Material : material, 0, shaderPass: pass, mpb);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateChunkVisibility(camera);
|
||||
|
||||
// Spends approx 0.2-0.3ms here on 2018 Dell XPS 15.
|
||||
@@ -841,7 +752,6 @@ namespace WaveHarmonic.Crest
|
||||
partial class SurfaceRenderer
|
||||
{
|
||||
bool _QueueMotionVectors;
|
||||
bool QueueMotionVectors => _QueueMotionVectors && !IsQuadMesh;
|
||||
|
||||
bool ShouldRenderMotionVectors(Camera camera)
|
||||
{
|
||||
@@ -907,7 +817,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
void UpdateMotionVectorsMaterial(Material surface, ref Material motion)
|
||||
{
|
||||
if (!QueueMotionVectors)
|
||||
if (!_QueueMotionVectors)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -945,80 +855,4 @@ namespace WaveHarmonic.Crest
|
||||
motion.SetFloat(ShaderIDs.s_BuiltShadowCasterZTest, 1); // ZTest Never
|
||||
}
|
||||
}
|
||||
|
||||
partial class SurfaceRenderer
|
||||
{
|
||||
internal Dictionary<Camera, MaterialPropertyBlock[]> _PerCameraPerCascadeMPB = new();
|
||||
internal Dictionary<Camera, Vector4[]> _PerCameraNormalMapParameters = new();
|
||||
|
||||
void LoadCameraData(Camera camera)
|
||||
{
|
||||
if (!_Water.SeparateViewpoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_PerCameraPerCascadeMPB.ContainsKey(camera))
|
||||
{
|
||||
PerCascadeMPB = new MaterialPropertyBlock[Lod.k_MaximumSlices];
|
||||
_PerCameraPerCascadeMPB.Add(camera, PerCascadeMPB);
|
||||
NormalMapParameters = new Vector4[Lod.k_MaximumSlices];
|
||||
_PerCameraNormalMapParameters.Add(camera, NormalMapParameters);
|
||||
InitializeProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
PerCascadeMPB = _PerCameraPerCascadeMPB[camera];
|
||||
NormalMapParameters = _PerCameraNormalMapParameters[camera];
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveCameraData(Camera camera)
|
||||
{
|
||||
if (_PerCameraPerCascadeMPB.ContainsKey(camera))
|
||||
{
|
||||
_PerCameraPerCascadeMPB.Remove(camera);
|
||||
_PerCameraNormalMapParameters.Remove(camera);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
RemoveCameraDataLDT(camera);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Quad
|
||||
partial class SurfaceRenderer
|
||||
{
|
||||
readonly Vector4[] _NormalMapParameters = new Vector4[Lod.k_MaximumSlices];
|
||||
Vector4[] NormalMapParameters { get; set; }
|
||||
|
||||
void LateUpdateQuadMesh()
|
||||
{
|
||||
Shader.SetGlobalVectorArray(ShaderIDs.s_NormalMapParameters, NormalMapParameters);
|
||||
|
||||
var scale = new Vector3(10000 * _Water.Scale, 10000 * _Water.Scale, 1);
|
||||
var bounds = Helpers.QuadMesh.bounds;
|
||||
bounds.Expand(scale);
|
||||
Graphics.RenderMesh
|
||||
(
|
||||
new()
|
||||
{
|
||||
motionVectorMode = MotionVectorGenerationMode.Camera,
|
||||
material = Material,
|
||||
worldBounds = Root.TransformBounds(bounds),
|
||||
layer = Layer,
|
||||
shadowCastingMode = CastShadows ? ShadowCastingMode.On : ShadowCastingMode.Off,
|
||||
lightProbeUsage = LightProbeUsage.Off,
|
||||
reflectionProbeUsage = ReflectionProbeUsage.BlendProbesAndSkybox,
|
||||
renderingLayerMask = (uint)Layer,
|
||||
},
|
||||
Helpers.QuadMesh,
|
||||
submeshIndex: 0,
|
||||
Matrix4x4.TRS(Root.position, Quaternion.Euler(90f, 0, 0), scale)
|
||||
);
|
||||
|
||||
UpdateMaterial(_Material, ref _MotionVectorMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
interface IReportsHeight
|
||||
{
|
||||
bool ReportHeight(WaterRenderer water, ref Rect bounds, ref float minimum, ref float maximum);
|
||||
bool ReportHeight(ref Rect bounds, ref float minimum, ref float maximum);
|
||||
}
|
||||
|
||||
interface IReportsDisplacement
|
||||
{
|
||||
bool ReportDisplacement(WaterRenderer water, ref Rect bounds, ref float horizontal, ref float vertical);
|
||||
bool ReportDisplacement(ref Rect bounds, ref float horizontal, ref float vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -24,7 +24,7 @@ namespace WaveHarmonic.Crest
|
||||
[AddComponentMenu("")]
|
||||
#endif
|
||||
[@ExecuteDuringEditMode]
|
||||
sealed partial class WaterChunkRenderer : ManagedBehaviour<WaterRenderer>
|
||||
sealed class WaterChunkRenderer : ManagedBehaviour<WaterRenderer>
|
||||
{
|
||||
[SerializeField]
|
||||
internal bool _DrawRenderBounds = false;
|
||||
@@ -61,6 +61,8 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
int _LodIndex = -1;
|
||||
|
||||
public static List<IReportsHeight> HeightReporters { get; } = new();
|
||||
public static List<IReportsDisplacement> DisplacementReporters { get; } = new();
|
||||
|
||||
// There is a 1-frame delay with Initialized in edit mode due to setting
|
||||
// enableInEditMode in EditorApplication.update. This only really affect this
|
||||
@@ -73,12 +75,6 @@ namespace WaveHarmonic.Crest
|
||||
_Mesh = mesh;
|
||||
_PreviousObjectToWorld = _CurrentObjectToWorld = transform.localToWorldMatrix;
|
||||
_Transform = transform;
|
||||
WaterRenderer.s_OnLoadCameraData -= LoadCameraData;
|
||||
WaterRenderer.s_OnLoadCameraData += LoadCameraData;
|
||||
WaterRenderer.s_OnStoreCameraData -= StoreCameraData;
|
||||
WaterRenderer.s_OnStoreCameraData += StoreCameraData;
|
||||
WaterRenderer.s_OnRemoveCameraData -= RemoveCameraData;
|
||||
WaterRenderer.s_OnRemoveCameraData += RemoveCameraData;
|
||||
}
|
||||
|
||||
private protected override void OnStart()
|
||||
@@ -148,7 +144,6 @@ namespace WaveHarmonic.Crest
|
||||
matProps = _MaterialPropertyBlock,
|
||||
worldBounds = Rend.bounds,
|
||||
layer = surface.Layer,
|
||||
renderingLayerMask = (uint)surface.Layer,
|
||||
receiveShadows = false,
|
||||
shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off,
|
||||
lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off,
|
||||
@@ -189,10 +184,11 @@ namespace WaveHarmonic.Crest
|
||||
};
|
||||
}
|
||||
|
||||
// Used by the water mask system if we need to render the water mask in situations
|
||||
// where the water itself doesn't need to be rendered or has otherwise been disabled
|
||||
internal void Bind()
|
||||
{
|
||||
_MaterialPropertyBlock = _Water.Surface.PerCascadeMPB[_LodIndex];
|
||||
new PropertyWrapperMPB(_MaterialPropertyBlock).SetSHCoefficients(_Transform.position);
|
||||
_MaterialPropertyBlock = _Water.Surface._PerCascadeMPB.Current[_LodIndex];
|
||||
Rend.SetPropertyBlock(_MaterialPropertyBlock);
|
||||
|
||||
_WaterDataHasBeenBound = true;
|
||||
@@ -238,12 +234,21 @@ namespace WaveHarmonic.Crest
|
||||
var scale = transform.lossyScale;
|
||||
var rotation = transform.rotation;
|
||||
|
||||
var boundsPadding = _Water.MaximumHorizontalDisplacement;
|
||||
var expandXZ = boundsPadding / scale.x;
|
||||
var boundsY = _Water.MaximumVerticalDisplacement;
|
||||
|
||||
// Extend the kinematic bounds slightly to give room for dynamic waves.
|
||||
if (_Water._DynamicWavesLod.Enabled)
|
||||
{
|
||||
extents.y += 5f;
|
||||
boundsY += 5f;
|
||||
}
|
||||
|
||||
// Extend bounds by global waves.
|
||||
extents.x += expandXZ;
|
||||
extents.y += boundsY;
|
||||
extents.z += expandXZ;
|
||||
|
||||
// Get XZ bounds. Doing this manually bypasses updating render bounds call.
|
||||
Rect rect;
|
||||
{
|
||||
@@ -263,15 +268,23 @@ namespace WaveHarmonic.Crest
|
||||
var totalHorizontal = 0f;
|
||||
var totalVertical = 0f;
|
||||
|
||||
foreach (var (key, input) in AnimatedWavesLod.s_Inputs)
|
||||
foreach (var reporter in DisplacementReporters)
|
||||
{
|
||||
input.DisplacementReporter?.ReportDisplacement(_Water, ref rect, ref totalHorizontal, ref totalVertical);
|
||||
var horizontal = 0f;
|
||||
var vertical = 0f;
|
||||
if (reporter.ReportDisplacement(ref rect, ref horizontal, ref vertical))
|
||||
{
|
||||
totalHorizontal += horizontal;
|
||||
totalVertical += vertical;
|
||||
}
|
||||
}
|
||||
|
||||
var expandXZ = totalHorizontal / scale.x;
|
||||
boundsPadding = totalHorizontal;
|
||||
expandXZ = boundsPadding / scale.x;
|
||||
boundsY = totalVertical;
|
||||
|
||||
extents.x += expandXZ;
|
||||
extents.y += totalVertical;
|
||||
extents.y += boundsY;
|
||||
extents.z += expandXZ;
|
||||
}
|
||||
|
||||
@@ -280,59 +293,37 @@ namespace WaveHarmonic.Crest
|
||||
var minimumWaterLevelBounds = 0f;
|
||||
var maximumWaterLevelBounds = 0f;
|
||||
|
||||
foreach (var (key, input) in LevelLod.s_Inputs)
|
||||
foreach (var reporter in HeightReporters)
|
||||
{
|
||||
input.HeightReporter?.ReportHeight(_Water, ref rect, ref minimumWaterLevelBounds, ref maximumWaterLevelBounds);
|
||||
var minimum = 0f;
|
||||
var maximum = 0f;
|
||||
if (reporter.ReportHeight(ref rect, ref minimum, ref maximum))
|
||||
{
|
||||
minimumWaterLevelBounds = Mathf.Max(minimumWaterLevelBounds, Mathf.Abs(Mathf.Min(minimum, _Water.SeaLevel) - _Water.SeaLevel));
|
||||
maximumWaterLevelBounds = Mathf.Max(maximumWaterLevelBounds, Mathf.Abs(Mathf.Max(maximum, _Water.SeaLevel) - _Water.SeaLevel));
|
||||
}
|
||||
}
|
||||
|
||||
extents.y += Mathf.Abs((minimumWaterLevelBounds - maximumWaterLevelBounds) * 0.5f);
|
||||
minimumWaterLevelBounds *= 0.5f;
|
||||
maximumWaterLevelBounds *= 0.5f;
|
||||
|
||||
boundsY = minimumWaterLevelBounds + maximumWaterLevelBounds;
|
||||
extents.y += boundsY;
|
||||
bounds.extents = extents;
|
||||
|
||||
var offset = Mathf.Lerp(minimumWaterLevelBounds, maximumWaterLevelBounds, 0.5f);
|
||||
var offset = maximumWaterLevelBounds - minimumWaterLevelBounds;
|
||||
center.y += offset;
|
||||
bounds.center = center;
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
|
||||
partial class WaterChunkRenderer
|
||||
{
|
||||
class AdditionalCameraData
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
static void InitStatics()
|
||||
{
|
||||
public Matrix4x4 _CurrentObjectToWorld;
|
||||
public Matrix4x4 _PreviousObjectToWorld;
|
||||
}
|
||||
|
||||
readonly Dictionary<Camera, AdditionalCameraData> _CameraData = new();
|
||||
AdditionalCameraData _AdditionalCameraData;
|
||||
|
||||
void LoadCameraData(Camera camera)
|
||||
{
|
||||
if (!_CameraData.ContainsKey(camera))
|
||||
{
|
||||
_CameraData[camera] = new();
|
||||
}
|
||||
|
||||
_AdditionalCameraData = _CameraData[camera];
|
||||
_CurrentObjectToWorld = _AdditionalCameraData._CurrentObjectToWorld;
|
||||
_PreviousObjectToWorld = _AdditionalCameraData._PreviousObjectToWorld;
|
||||
}
|
||||
|
||||
void StoreCameraData(Camera camera)
|
||||
{
|
||||
if (_AdditionalCameraData == null) return;
|
||||
_AdditionalCameraData._CurrentObjectToWorld = _CurrentObjectToWorld;
|
||||
_AdditionalCameraData._PreviousObjectToWorld = _PreviousObjectToWorld;
|
||||
}
|
||||
|
||||
void RemoveCameraData(Camera camera)
|
||||
{
|
||||
if (_CameraData.ContainsKey(camera))
|
||||
{
|
||||
_CameraData.Remove(camera);
|
||||
}
|
||||
HeightReporters.Clear();
|
||||
DisplacementReporters.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
#if d_UnityURP
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.RenderGraphModule;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
partial class WaterReflections
|
||||
{
|
||||
CopyDepthRenderPass _CopyTargetsRenderPass;
|
||||
|
||||
void CaptureTargetDepth(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
if (camera != ReflectionCamera)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RenderPipelineHelper.IsUniversal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if URP_COMPATIBILITY_MODE
|
||||
#if !UNITY_6000_4_OR_NEWER
|
||||
if (GraphicsSettings.GetRenderPipelineSettings<RenderGraphSettings>().enableRenderCompatibilityMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_CopyTargetsRenderPass ??= new(this);
|
||||
var renderer = camera.GetUniversalAdditionalCameraData().scriptableRenderer;
|
||||
renderer.EnqueuePass(_CopyTargetsRenderPass);
|
||||
}
|
||||
|
||||
sealed class CopyDepthRenderPass : ScriptableRenderPass
|
||||
{
|
||||
readonly WaterReflections _Renderer;
|
||||
RTHandle _Wrapper;
|
||||
|
||||
class CopyPassData
|
||||
{
|
||||
public TextureHandle _Source;
|
||||
public TextureHandle _Target;
|
||||
public int _Slice;
|
||||
}
|
||||
|
||||
public CopyDepthRenderPass(WaterReflections renderer)
|
||||
{
|
||||
_Renderer = renderer;
|
||||
renderPassEvent = RenderPassEvent.AfterRendering;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_Wrapper?.Release();
|
||||
_Wrapper = null;
|
||||
}
|
||||
|
||||
public override void RecordRenderGraph(RenderGraph graph, ContextContainer frame)
|
||||
{
|
||||
var resources = frame.Get<UniversalResourceData>();
|
||||
|
||||
var source = resources.cameraDepth;
|
||||
|
||||
if (!source.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a wrapper. Does not appear to be anything heavy in here.
|
||||
_Wrapper ??= RTHandles.Alloc(_Renderer._DepthTexture);
|
||||
_Wrapper.SetRenderTexture(_Renderer._DepthTexture);
|
||||
|
||||
var texture = graph.ImportTexture(_Wrapper);
|
||||
|
||||
using var builder = graph.AddUnsafePass<CopyPassData>("Crest.CopyDepth", out var data);
|
||||
|
||||
data._Source = source;
|
||||
data._Target = graph.ImportTexture(_Wrapper);
|
||||
data._Slice = _Renderer._ActiveSlice;
|
||||
|
||||
builder.UseTexture(data._Source, AccessFlags.Read);
|
||||
builder.UseTexture(data._Target, AccessFlags.Write);
|
||||
|
||||
// Unity's AddCopyPass cannot handle this it seems.
|
||||
builder.SetRenderFunc((CopyPassData data, UnsafeGraphContext context) =>
|
||||
{
|
||||
RTHandle source = data._Source;
|
||||
RTHandle target = data._Target;
|
||||
|
||||
// Just in case. Planar Reflections will work mostly without it.
|
||||
if (source.rt == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (source.rt.graphicsFormat == target.rt.graphicsFormat && source.rt.depthStencilFormat == target.rt.depthStencilFormat)
|
||||
{
|
||||
context.cmd.m_WrappedCommandBuffer.CopyTexture(source.rt, 0, 0, target.rt, data._Slice, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79f370973399f49f38382da0814a25cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 205
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -10,7 +10,6 @@ using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
@@ -70,12 +69,6 @@ namespace WaveHarmonic.Crest
|
||||
[@Delayed, SerializeField]
|
||||
int _Resolution = 256;
|
||||
|
||||
[Tooltip("Overscan amount to capture off-screen content.\n\nRenders the reflections at a larger viewport size to capture off-screen content when the surface reflects off-screen. This avoids a category of artifacts - especially when looking down. This can be expensive, as the value is a multiplier to the capture size.")]
|
||||
[@Range(1, 2)]
|
||||
[@GenerateAPI]
|
||||
[SerializeField]
|
||||
float _Overscan = 1.5f;
|
||||
|
||||
[Tooltip("Whether to render to the viewer camera only.\n\nWhen disabled, reflections will render for all cameras rendering the water layer, which currently this prevents Refresh Rate from working. Enabling will unlock the Refresh Rate heading.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
@@ -110,6 +103,11 @@ namespace WaveHarmonic.Crest
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _Stencil = false;
|
||||
|
||||
[Tooltip("Whether to allow MSAA.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _AllowMSAA = false;
|
||||
|
||||
[@Space(10)]
|
||||
|
||||
[Tooltip("Overrides global quality settings.")]
|
||||
@@ -191,12 +189,6 @@ namespace WaveHarmonic.Crest
|
||||
[Tooltip("Rendering reflections per-camera requires recursive rendering. Check this toggle if experiencing issues. The other downside without it is a one-frame delay.")]
|
||||
[@DecoratedField, SerializeField]
|
||||
internal bool _DisableRecursiveRendering;
|
||||
|
||||
[Tooltip("Whether to create a context more compatible for planar reflections camera. Try enabling this if you are getting exceptions.")]
|
||||
[@Predicated(RenderPipeline.Universal, hide: true)]
|
||||
[@DecoratedField]
|
||||
[SerializeField]
|
||||
internal bool _ForceCompatibility;
|
||||
}
|
||||
|
||||
|
||||
@@ -208,81 +200,55 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
static class ShaderIDs
|
||||
{
|
||||
public static int s_ReflectionColorTexture = Shader.PropertyToID("_Crest_ReflectionColorTexture");
|
||||
public static int s_ReflectionDepthTexture = Shader.PropertyToID("_Crest_ReflectionDepthTexture");
|
||||
public static int s_ReflectionTexture = Shader.PropertyToID("_Crest_ReflectionTexture");
|
||||
public static int s_ReflectionPositionNormal = Shader.PropertyToID("_Crest_ReflectionPositionNormal");
|
||||
public static readonly int s_ReflectionMatrixIVP = Shader.PropertyToID("_Crest_ReflectionMatrixIVP");
|
||||
public static readonly int s_ReflectionMatrixV = Shader.PropertyToID("_Crest_ReflectionMatrixV");
|
||||
public static readonly int s_Crest_ReflectionOverscan = Shader.PropertyToID("_Crest_ReflectionOverscan");
|
||||
|
||||
public static readonly int s_PlanarReflectionsApplySmoothness = Shader.PropertyToID("_Crest_PlanarReflectionsApplySmoothness");
|
||||
}
|
||||
|
||||
// Checked in underwater to filter cameras.
|
||||
internal static Camera CurrentCamera { get; private set; }
|
||||
|
||||
internal WaterRenderer _Water;
|
||||
internal UnderwaterRenderer _UnderWater;
|
||||
|
||||
bool _ApplySmoothness;
|
||||
|
||||
RenderTexture _ColorTexture;
|
||||
RenderTexture _DepthTexture;
|
||||
internal RenderTexture ColorTexture => _ColorTexture;
|
||||
internal RenderTexture DepthTexture => _DepthTexture;
|
||||
RenderTexture _ReflectionTexture;
|
||||
internal RenderTexture ReflectionTexture => _ReflectionTexture;
|
||||
readonly Vector4[] _ReflectionPositionNormal = new Vector4[2];
|
||||
readonly Matrix4x4[] _ReflectionMatrixIVP = new Matrix4x4[2];
|
||||
readonly Matrix4x4[] _ReflectionMatrixV = new Matrix4x4[2];
|
||||
|
||||
internal int _ActiveSlice;
|
||||
|
||||
Camera _CameraViewpoint;
|
||||
Skybox _CameraViewpointSkybox;
|
||||
Camera _CameraReflections;
|
||||
Skybox _CameraReflectionsSkybox;
|
||||
internal Camera ReflectionCamera => _CameraReflections;
|
||||
|
||||
int RefreshPerFrames => _RenderOnlySingleCamera ? _RefreshPerFrames : 1;
|
||||
long _LastRefreshOnFrame = -1;
|
||||
|
||||
internal bool SupportsRecursiveRendering => _Water.SupportsRecursiveRendering && !_Debug._DisableRecursiveRendering;
|
||||
internal bool SupportsRecursiveRendering =>
|
||||
#if !UNITY_6000_0_OR_NEWER
|
||||
// HDRP cannot recursive render for 2022.
|
||||
!RenderPipelineHelper.IsHighDefinition &&
|
||||
#endif
|
||||
!_Debug._DisableRecursiveRendering;
|
||||
|
||||
readonly float[] _CullDistances = new float[32];
|
||||
|
||||
Texture _CameraDepthTexture;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the reflection camera is created.
|
||||
/// </summary>
|
||||
public static Action<Camera> OnCameraAdded { get; set; }
|
||||
|
||||
bool RequireTemporaryTargets =>
|
||||
#if UNITY_6000_0_OR_NEWER && d_UnityURP
|
||||
// As of Unity 6 we can write directly to a slice for URP.
|
||||
!RenderPipelineHelper.IsUniversal &&
|
||||
#endif
|
||||
true;
|
||||
|
||||
internal void OnEnable()
|
||||
{
|
||||
// We initialized here previously to fix the first frame being black, but could not
|
||||
// replicate anymore.
|
||||
_CameraViewpoint = _Water.Viewer;
|
||||
_CameraViewpointSkybox = _CameraViewpoint.GetComponent<Skybox>();
|
||||
|
||||
#if d_UnityURP
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
RenderPipelineManager.beginCameraRendering -= CaptureTargetDepth;
|
||||
RenderPipelineManager.beginCameraRendering += CaptureTargetDepth;
|
||||
#endif
|
||||
#endif
|
||||
// This is called also called every frame, but was required here as there was a
|
||||
// black reflection for a frame without this earlier setup call.
|
||||
CreateWaterObjects(_CameraViewpoint);
|
||||
}
|
||||
|
||||
internal void OnDisable()
|
||||
{
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionColorTexture, Texture2D.blackTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionDepthTexture, Texture2D.blackTexture);
|
||||
|
||||
#if d_UnityURP
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
RenderPipelineManager.beginCameraRendering -= CaptureTargetDepth;
|
||||
#endif
|
||||
#endif
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionTexture, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
internal void OnDestroy()
|
||||
@@ -293,18 +259,11 @@ namespace WaveHarmonic.Crest
|
||||
_CameraReflections = null;
|
||||
}
|
||||
|
||||
if (_ColorTexture)
|
||||
if (_ReflectionTexture)
|
||||
{
|
||||
_ColorTexture.Release();
|
||||
Helpers.Destroy(_ColorTexture);
|
||||
_ColorTexture = null;
|
||||
}
|
||||
|
||||
if (_DepthTexture)
|
||||
{
|
||||
_DepthTexture.Release();
|
||||
Helpers.Destroy(_DepthTexture);
|
||||
_DepthTexture = null;
|
||||
_ReflectionTexture.Release();
|
||||
Helpers.Destroy(_ReflectionTexture);
|
||||
_ReflectionTexture = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +278,7 @@ namespace WaveHarmonic.Crest
|
||||
// This method could be executed twice: once by the camera rendering the surface,
|
||||
// and once again by the planar reflection camera. For the latter, we do not want
|
||||
// to proceed or infinite recursion. For safety.
|
||||
if (camera == _CameraReflections)
|
||||
if (camera == CurrentCamera)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -355,46 +314,18 @@ namespace WaveHarmonic.Crest
|
||||
if (camera == _CameraViewpoint)
|
||||
{
|
||||
// TODO: Emit an event instead so WBs can listen.
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionColorTexture, _ColorTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionDepthTexture, _DepthTexture);
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionTexture, _ReflectionTexture);
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnEndCameraRendering(Camera camera)
|
||||
{
|
||||
if (camera == ReflectionCamera)
|
||||
{
|
||||
// Appears to be the only reasonable way to get camera depth separately for SRPs.
|
||||
_CameraDepthTexture = Shader.GetGlobalTexture(Crest.ShaderIDs.Unity.s_CameraDepthTexture);
|
||||
}
|
||||
|
||||
if (!ShouldRender(camera))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionColorTexture, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
internal void LateUpdate()
|
||||
{
|
||||
// Check if enabled for at least one material every frame.
|
||||
_ApplySmoothness = false;
|
||||
|
||||
CheckSurfaceMaterial(_Water.Surface.Material);
|
||||
|
||||
foreach (var wb in WaterBody.WaterBodies)
|
||||
{
|
||||
CheckSurfaceMaterial(wb._Material);
|
||||
}
|
||||
|
||||
if (SupportsRecursiveRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Passing a struct.
|
||||
LateUpdate(new());
|
||||
Shader.SetGlobalTexture(ShaderIDs.s_ReflectionTexture, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
internal void LateUpdate(ScriptableRenderContext context)
|
||||
@@ -445,18 +376,19 @@ namespace WaveHarmonic.Crest
|
||||
UpdateCameraModes();
|
||||
ForceDistanceCulling(_FarClipPlane);
|
||||
|
||||
_CameraReflections.targetTexture = _ReflectionTexture;
|
||||
|
||||
// TODO: Do not do this every frame.
|
||||
if (_Mode != WaterReflectionSide.Both)
|
||||
{
|
||||
Helpers.ClearRenderTexture(_ColorTexture, Color.clear, depth: true);
|
||||
Helpers.ClearRenderTexture(_DepthTexture, Color.clear, depth: true);
|
||||
Helpers.ClearRenderTexture(_ReflectionTexture, Color.clear, depth: false);
|
||||
}
|
||||
|
||||
var isActive = _Water.Surface.Root.gameObject.activeSelf;
|
||||
|
||||
// We do not want the water plane when rendering planar reflections.
|
||||
_Water.Surface.Root.gameObject.SetActive(false);
|
||||
|
||||
CurrentCamera = _CameraReflections;
|
||||
|
||||
// Optionally disable pixel lights for reflection/refraction
|
||||
var oldPixelLightCount = QualitySettings.pixelLightCount;
|
||||
if (_DisablePixelLights)
|
||||
@@ -504,7 +436,8 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
_QualitySettingsOverride.Restore();
|
||||
|
||||
_Water.Surface.Root.gameObject.SetActive(isActive);
|
||||
CurrentCamera = null;
|
||||
_Water.Surface.Root.gameObject.SetActive(true);
|
||||
|
||||
// Remember this frame as last refreshed.
|
||||
_LastRefreshOnFrame = Time.renderedFrameCount;
|
||||
@@ -513,60 +446,41 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
void Render(ScriptableRenderContext context)
|
||||
{
|
||||
var colorTarget = _ColorTexture;
|
||||
var depthTarget = _DepthTexture;
|
||||
|
||||
if (RequireTemporaryTargets)
|
||||
{
|
||||
var descriptor = _ColorTexture.descriptor;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
descriptor.volumeDepth = 1;
|
||||
descriptor.useMipMap = false;
|
||||
// No need to clear, as camera clears using the skybox.
|
||||
colorTarget = RenderTexture.GetTemporary(descriptor);
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
descriptor = _DepthTexture.descriptor;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
descriptor.volumeDepth = 1;
|
||||
descriptor.useMipMap = false;
|
||||
// No need to clear, as camera clears using the skybox.
|
||||
depthTarget = RenderTexture.GetTemporary(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
if (RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
// Not documented, but does not work for SRPs.
|
||||
_CameraReflections.SetTargetBuffers(colorTarget.colorBuffer, depthTarget.depthBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_CameraReflections.targetTexture = colorTarget;
|
||||
}
|
||||
#if UNITY_6000_0_OR_NEWER && d_UnityURP
|
||||
_CameraReflections.targetTexture = _ReflectionTexture;
|
||||
#else
|
||||
var descriptor = _ReflectionTexture.descriptor;
|
||||
descriptor.dimension = TextureDimension.Tex2D;
|
||||
descriptor.volumeDepth = 1;
|
||||
descriptor.useMipMap = false;
|
||||
// No need to clear, as camera clears using the skybox.
|
||||
var target = RenderTexture.GetTemporary(descriptor);
|
||||
_CameraReflections.targetTexture = target;
|
||||
#endif
|
||||
|
||||
if (_Mode != WaterReflectionSide.Below)
|
||||
{
|
||||
_ReflectionPositionNormal[0] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, 0.05f, false);
|
||||
|
||||
if (_UnderWater._Enabled)
|
||||
{
|
||||
// Disable underwater layer. It is the only way to exclude probes.
|
||||
_CameraReflections.cullingMask = _Layers & ~(1 << _UnderWater.Layer);
|
||||
}
|
||||
|
||||
_ActiveSlice = 0;
|
||||
|
||||
RenderCamera(context, _CameraReflections, Vector3.up, false, 0);
|
||||
|
||||
CopyTargets(colorTarget, depthTarget, 0);
|
||||
|
||||
_ReflectionPositionNormal[0] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, 0.05f, false);
|
||||
#if !(UNITY_6000_0_OR_NEWER && d_UnityURP)
|
||||
Graphics.CopyTexture(target, 0, 0, _ReflectionTexture, 0, 0);
|
||||
#endif
|
||||
|
||||
_CameraReflections.ResetProjectionMatrix();
|
||||
}
|
||||
|
||||
if (_Mode != WaterReflectionSide.Above)
|
||||
{
|
||||
_ReflectionPositionNormal[1] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, -0.05f, true);
|
||||
|
||||
if (_UnderWater._Enabled)
|
||||
{
|
||||
// Enable underwater layer.
|
||||
@@ -575,32 +489,22 @@ namespace WaveHarmonic.Crest
|
||||
_CameraReflections.depthTextureMode = DepthTextureMode.Depth;
|
||||
}
|
||||
|
||||
_ActiveSlice = 1;
|
||||
|
||||
RenderCamera(context, _CameraReflections, Vector3.down, _NonObliqueNearSurface, 1);
|
||||
|
||||
CopyTargets(colorTarget, depthTarget, 1);
|
||||
|
||||
_ReflectionPositionNormal[1] = ComputeHorizonPositionAndNormal(_CameraReflections, _Water.SeaLevel, -0.05f, true);
|
||||
#if !(UNITY_6000_0_OR_NEWER && d_UnityURP)
|
||||
Graphics.CopyTexture(target, 0, 0, _ReflectionTexture, 1, 0);
|
||||
#endif
|
||||
|
||||
_CameraReflections.ResetProjectionMatrix();
|
||||
}
|
||||
|
||||
if (RequireTemporaryTargets)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(colorTarget);
|
||||
if (RenderPipelineHelper.IsLegacy) RenderTexture.ReleaseTemporary(depthTarget);
|
||||
}
|
||||
#if !(UNITY_6000_0_OR_NEWER && d_UnityURP)
|
||||
RenderTexture.ReleaseTemporary(target);
|
||||
#endif
|
||||
|
||||
if (_ApplySmoothness)
|
||||
{
|
||||
// We are only using mip-maps if applying smoothness/roughness.
|
||||
_ColorTexture.GenerateMips();
|
||||
}
|
||||
_ReflectionTexture.GenerateMips();
|
||||
|
||||
Shader.SetGlobalVectorArray(ShaderIDs.s_ReflectionPositionNormal, _ReflectionPositionNormal);
|
||||
Shader.SetGlobalMatrixArray(ShaderIDs.s_ReflectionMatrixIVP, _ReflectionMatrixIVP);
|
||||
Shader.SetGlobalMatrixArray(ShaderIDs.s_ReflectionMatrixV, _ReflectionMatrixV);
|
||||
}
|
||||
|
||||
void RenderCamera(ScriptableRenderContext context, Camera camera, Vector3 planeNormal, bool nonObliqueNearSurface, int slice)
|
||||
@@ -613,9 +517,10 @@ namespace WaveHarmonic.Crest
|
||||
var viewpoint = _CameraViewpoint.transform;
|
||||
if (offset == 0f && viewpoint.position.y == planePosition.y)
|
||||
{
|
||||
// Minor offset to prevent "Screen position out of view frustum". Needs to scale
|
||||
// with distance from center.
|
||||
offset = viewpoint.position.magnitude >= 15000f ? 0.01f : 0.001f;
|
||||
// Minor offset to prevent "Screen position out of view frustum". Smallest number
|
||||
// to work with both above and below. Smallest number to work with both above and
|
||||
// below. Could be BIRP only.
|
||||
offset = 0.00001f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,12 +539,7 @@ namespace WaveHarmonic.Crest
|
||||
|
||||
if (_UseObliqueMatrix && (!nonObliqueNearSurface || Mathf.Abs(_CameraViewpoint.transform.position.y - planePosition.y) > _NonObliqueNearSurfaceThreshold))
|
||||
{
|
||||
var matrix = _CameraViewpoint.CalculateObliqueMatrix(clipPlane);
|
||||
// Overscan.
|
||||
var overscan = 1f - (_Overscan - 1f) * 0.5f;
|
||||
matrix[0, 0] *= overscan;
|
||||
matrix[1, 1] *= overscan;
|
||||
camera.projectionMatrix = matrix;
|
||||
camera.projectionMatrix = _CameraViewpoint.CalculateObliqueMatrix(clipPlane);
|
||||
}
|
||||
|
||||
// Set custom culling matrix from the current camera
|
||||
@@ -650,12 +550,9 @@ namespace WaveHarmonic.Crest
|
||||
camera.transform.eulerAngles = new(-euler.x, euler.y, euler.z);
|
||||
camera.cullingMatrix = camera.projectionMatrix * camera.worldToCameraMatrix;
|
||||
|
||||
_ReflectionMatrixV[slice] = camera.worldToCameraMatrix;
|
||||
_ReflectionMatrixIVP[slice] = (GL.GetGPUProjectionMatrix(camera.projectionMatrix, true) * camera.worldToCameraMatrix).inverse;
|
||||
|
||||
if (SupportsRecursiveRendering)
|
||||
{
|
||||
Helpers.RenderCamera(camera, context, slice, _Debug._ForceCompatibility);
|
||||
Helpers.RenderCamera(camera, context, slice);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -663,35 +560,6 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
}
|
||||
|
||||
void CopyTargets(Texture color, Texture depth, int slice)
|
||||
{
|
||||
if (RequireTemporaryTargets)
|
||||
{
|
||||
Graphics.CopyTexture(color, 0, 0, 0, 0, _Resolution, _Resolution, _ColorTexture, slice, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (!RenderPipelineHelper.IsLegacy)
|
||||
{
|
||||
depth = _CameraDepthTexture;
|
||||
}
|
||||
|
||||
if (Rendering.IsRenderGraph)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This can change between depth and R32 based on settings.
|
||||
if (depth != null && depth.graphicsFormat != _DepthTexture.graphicsFormat)
|
||||
{
|
||||
RecreateDepth(depth);
|
||||
}
|
||||
|
||||
if (depth != null && depth.width >= _Resolution)
|
||||
{
|
||||
Graphics.CopyTexture(depth, 0, 0, 0, 0, _Resolution, _Resolution, _DepthTexture, slice, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Limit render distance for reflection camera for first 32 layers
|
||||
/// </summary>
|
||||
@@ -755,101 +623,38 @@ namespace WaveHarmonic.Crest
|
||||
_CameraReflections.orthographic = _CameraViewpoint.orthographic;
|
||||
_CameraReflections.fieldOfView = _CameraViewpoint.fieldOfView;
|
||||
_CameraReflections.orthographicSize = _CameraViewpoint.orthographicSize;
|
||||
_CameraReflections.allowMSAA = false;
|
||||
_CameraReflections.allowMSAA = _AllowMSAA;
|
||||
_CameraReflections.aspect = _CameraViewpoint.aspect;
|
||||
_CameraReflections.useOcclusionCulling = !_DisableOcclusionCulling && _CameraViewpoint.useOcclusionCulling;
|
||||
_CameraReflections.depthTextureMode = _CameraViewpoint.depthTextureMode;
|
||||
|
||||
// Overscan
|
||||
{
|
||||
_CameraReflections.usePhysicalProperties = _Overscan > 1f;
|
||||
|
||||
var baseSensor = new Vector2(36f, 24f);
|
||||
var focal = (baseSensor.y * 0.5f) / Mathf.Tan(_CameraViewpoint.fieldOfView * 0.5f * Mathf.Deg2Rad);
|
||||
|
||||
var overscan = 1f - (_Overscan - 1f) * 0.5f;
|
||||
_CameraReflections.sensorSize = baseSensor / overscan;
|
||||
_CameraReflections.focalLength = focal;
|
||||
|
||||
Shader.SetGlobalFloat(ShaderIDs.s_Crest_ReflectionOverscan, overscan);
|
||||
}
|
||||
}
|
||||
|
||||
void RecreateDepth(Texture depth)
|
||||
{
|
||||
if (_DepthTexture != null && _DepthTexture.IsCreated())
|
||||
{
|
||||
_DepthTexture.Release();
|
||||
_DepthTexture.descriptor = depth.GetDescriptor();
|
||||
}
|
||||
else
|
||||
{
|
||||
_DepthTexture = new(depth.GetDescriptor());
|
||||
}
|
||||
|
||||
_DepthTexture.name = "_Crest_ReflectionDepth";
|
||||
_DepthTexture.width = _DepthTexture.height = _Resolution;
|
||||
_DepthTexture.isPowerOfTwo = true;
|
||||
_DepthTexture.useMipMap = false;
|
||||
_DepthTexture.autoGenerateMips = false;
|
||||
_DepthTexture.filterMode = FilterMode.Point;
|
||||
_DepthTexture.volumeDepth = 2;
|
||||
_DepthTexture.dimension = TextureDimension.Tex2DArray;
|
||||
_DepthTexture.Create();
|
||||
}
|
||||
|
||||
// On-demand create any objects we need for water
|
||||
void CreateWaterObjects(Camera currentCamera)
|
||||
{
|
||||
// We cannot exclude stencil for URP, as the depth texture format always has it.
|
||||
var colorFormat = Rendering.GetDefaultColorFormat(_HDR);
|
||||
var depthFormat = Rendering.GetDefaultDepthFormat(_Stencil || RenderPipelineHelper.IsUniversal);
|
||||
var format = _HDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
|
||||
var stencil = _Stencil ? 24 : 16;
|
||||
|
||||
// Reflection render texture
|
||||
if (!_ColorTexture || _ColorTexture.width != _Resolution || _ColorTexture.graphicsFormat != colorFormat || _ColorTexture.depthStencilFormat != depthFormat)
|
||||
if (!_ReflectionTexture || _ReflectionTexture.width != _Resolution || _ReflectionTexture.format != format || _ReflectionTexture.depth != stencil)
|
||||
{
|
||||
if (_ColorTexture)
|
||||
if (_ReflectionTexture)
|
||||
{
|
||||
Helpers.Destroy(_ColorTexture);
|
||||
Helpers.Destroy(_DepthTexture);
|
||||
Helpers.Destroy(_ReflectionTexture);
|
||||
}
|
||||
|
||||
var descriptor = new RenderTextureDescriptor(_Resolution, _Resolution)
|
||||
Debug.Assert(SystemInfo.SupportsRenderTextureFormat(format), "Crest: The graphics device does not support the render texture format " + format.ToString());
|
||||
_ReflectionTexture = new(_Resolution, _Resolution, stencil, format)
|
||||
{
|
||||
name = "_Crest_WaterReflection",
|
||||
isPowerOfTwo = true,
|
||||
dimension = TextureDimension.Tex2DArray,
|
||||
volumeDepth = 2,
|
||||
depthStencilFormat = depthFormat,
|
||||
msaaSamples = 1,
|
||||
};
|
||||
|
||||
_ColorTexture = new(descriptor)
|
||||
{
|
||||
name = "_Crest_ReflectionColor",
|
||||
graphicsFormat = colorFormat,
|
||||
isPowerOfTwo = true,
|
||||
useMipMap = true,
|
||||
autoGenerateMips = false,
|
||||
filterMode = FilterMode.Trilinear,
|
||||
};
|
||||
_ColorTexture.Create();
|
||||
|
||||
_DepthTexture = new(descriptor)
|
||||
{
|
||||
name = "_Crest_ReflectionDepth",
|
||||
graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.None,
|
||||
isPowerOfTwo = true,
|
||||
useMipMap = false,
|
||||
autoGenerateMips = false,
|
||||
filterMode = FilterMode.Point,
|
||||
};
|
||||
|
||||
if (RenderPipelineHelper.IsHighDefinition)
|
||||
{
|
||||
_DepthTexture.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat;
|
||||
_DepthTexture.depthStencilFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.None;
|
||||
}
|
||||
|
||||
_DepthTexture.Create();
|
||||
_ReflectionTexture.Create();
|
||||
}
|
||||
|
||||
// Camera for reflection
|
||||
@@ -886,8 +691,8 @@ namespace WaveHarmonic.Crest
|
||||
{
|
||||
var additionalCameraData = _CameraReflections.gameObject.AddComponent<UniversalAdditionalCameraData>();
|
||||
additionalCameraData.renderShadows = !_DisableShadows;
|
||||
additionalCameraData.requiresColorTexture = _Mode != WaterReflectionSide.Above; // or incur assertions
|
||||
additionalCameraData.requiresDepthTexture = true;
|
||||
additionalCameraData.requiresColorTexture = false;
|
||||
additionalCameraData.requiresDepthTexture = false;
|
||||
}
|
||||
#endif
|
||||
OnCameraAdded?.Invoke(_CameraReflections);
|
||||
@@ -1059,19 +864,6 @@ namespace WaveHarmonic.Crest
|
||||
return new(position.x, position.y, normal.x, normal.y);
|
||||
}
|
||||
|
||||
void CheckSurfaceMaterial(Material material)
|
||||
{
|
||||
if (material == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_ApplySmoothness)
|
||||
{
|
||||
_ApplySmoothness = material.GetBoolean(ShaderIDs.s_PlanarReflectionsApplySmoothness);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEnabled(bool previous, bool current)
|
||||
{
|
||||
if (previous == current) return;
|
||||
@@ -1092,15 +884,4 @@ namespace WaveHarmonic.Crest
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
partial class WaterReflections
|
||||
{
|
||||
// MSAA would require separate textures to resolve to. Not worth the expense.
|
||||
[HideInInspector]
|
||||
[Obsolete("MSAA for the planar reflection camera is no longer supported. This setting will be ignored.")]
|
||||
[Tooltip("Whether to allow MSAA.")]
|
||||
[@GenerateAPI]
|
||||
[@DecoratedField, SerializeField]
|
||||
bool _AllowMSAA;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user