移除水
This commit is contained in:
@@ -1,253 +0,0 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
partial class UnderwaterRenderer
|
||||
{
|
||||
// Adapted from:
|
||||
// Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs
|
||||
#if UNITY_SWITCH || UNITY_ANDROID || UNITY_EMBEDDED_LINUX || UNITY_QNX
|
||||
internal const GraphicsFormat k_DepthStencilFormat = GraphicsFormat.D24_UNorm_S8_UInt;
|
||||
internal const int k_DepthBufferBits = 24;
|
||||
internal const DepthBits k_DepthBits = DepthBits.Depth24;
|
||||
#else
|
||||
internal const GraphicsFormat k_DepthStencilFormat = GraphicsFormat.D32_SFloat_S8_UInt;
|
||||
internal const int k_DepthBufferBits = 32;
|
||||
internal const DepthBits k_DepthBits = DepthBits.Depth32;
|
||||
#endif
|
||||
|
||||
internal const int k_ShaderPassWaterSurfaceMask = 0;
|
||||
internal const int k_ShaderPassWaterSurfaceDepth = 1;
|
||||
internal const int k_ShaderPassWaterHorizonMask = 2;
|
||||
|
||||
// NOTE: Must match CREST_MASK_BELOW_SURFACE in Constants.hlsl.
|
||||
const float k_MaskBelowSurface = -1f;
|
||||
// NOTE: Must match CREST_MASK_BELOW_SURFACE_CULLED in Constants.hlsl.
|
||||
const float k_MaskBelowSurfaceCull = -2f;
|
||||
|
||||
internal const string k_ComputeShaderKernelFillMaskArtefacts = "FillMaskArtefacts";
|
||||
|
||||
static partial class ShaderIDs
|
||||
{
|
||||
// Local
|
||||
public static readonly int s_FarPlaneOffset = Shader.PropertyToID("_Crest_FarPlaneOffset");
|
||||
public static readonly int s_MaskBelowSurface = Shader.PropertyToID("_Crest_MaskBelowSurface");
|
||||
|
||||
// Global
|
||||
public static readonly int s_WaterMaskTexture = Shader.PropertyToID("_Crest_WaterMaskTexture");
|
||||
public static readonly int s_WaterMaskDepthTexture = Shader.PropertyToID("_Crest_WaterMaskDepthTexture");
|
||||
|
||||
public static readonly int s_StencilRef = Shader.PropertyToID("_StencilRef");
|
||||
}
|
||||
|
||||
internal Material _MaskMaterial;
|
||||
|
||||
internal RenderTargetIdentifier _MaskTarget;
|
||||
internal RenderTargetIdentifier _DepthTarget;
|
||||
|
||||
internal readonly Plane[] _CameraFrustumPlanes = new Plane[6];
|
||||
CommandBuffer _MaskCommandBuffer;
|
||||
|
||||
internal RenderTexture _MaskRT;
|
||||
RenderTexture _DepthRT;
|
||||
|
||||
ComputeShader _ArtifactsShader;
|
||||
bool _ArtifactsShaderInitialized;
|
||||
int _ArtifactsKernel;
|
||||
uint _ArtifactsThreadGroupSizeX;
|
||||
uint _ArtifactsThreadGroupSizeY;
|
||||
|
||||
void SetupMask()
|
||||
{
|
||||
_MaskCommandBuffer ??= new()
|
||||
{
|
||||
name = "Crest: Underwater Mask",
|
||||
};
|
||||
}
|
||||
|
||||
internal void OnEnableMask()
|
||||
{
|
||||
// Create a reference to handle the RT. The RT properties will be replaced with a descriptor before the
|
||||
// native object is created, and since it is lazy it is near zero cost.
|
||||
Helpers.CreateRenderTargetTextureReference(ref _MaskRT, ref _MaskTarget);
|
||||
_MaskRT.name = "_Crest_WaterMaskTexture";
|
||||
Helpers.CreateRenderTargetTextureReference(ref _DepthRT, ref _DepthTarget);
|
||||
_DepthRT.name = "_Crest_WaterMaskDepthTexture";
|
||||
|
||||
SetUpArtifactsShader();
|
||||
}
|
||||
|
||||
internal void OnDisableMask()
|
||||
{
|
||||
if (_MaskRT != null) _MaskRT.Release();
|
||||
if (_DepthRT != null) _DepthRT.Release();
|
||||
}
|
||||
|
||||
internal void SetUpArtifactsShader()
|
||||
{
|
||||
if (_ArtifactsShaderInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ArtifactsKernel = _ArtifactsShader.FindKernel(k_ComputeShaderKernelFillMaskArtefacts);
|
||||
_ArtifactsShader.GetKernelThreadGroupSizes
|
||||
(
|
||||
_ArtifactsKernel,
|
||||
out _ArtifactsThreadGroupSizeX,
|
||||
out _ArtifactsThreadGroupSizeY,
|
||||
out _
|
||||
);
|
||||
|
||||
_ArtifactsShaderInitialized = true;
|
||||
}
|
||||
|
||||
internal void SetUpMaskTextures(RenderTextureDescriptor descriptor)
|
||||
{
|
||||
if (!Helpers.RenderTargetTextureNeedsUpdating(_MaskRT, descriptor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This will disable MSAA for our textures as MSAA will break sampling later on. This looks safe to do as
|
||||
// Unity's CopyDepthPass does the same, but a possible better way or supporting MSAA is worth looking into.
|
||||
descriptor.msaaSamples = 1;
|
||||
|
||||
// @Memory: We could investigate making this an 8-bit texture instead to reduce GPU memory usage.
|
||||
// @Memory: We could potentially try a half resolution mask as the mensicus could mask resolution issues.
|
||||
// Intel iGPU for Metal and DirectX both had issues with R16. 2021.11.18
|
||||
descriptor.colorFormat = Helpers.IsIntelGPU() ? RenderTextureFormat.RFloat : RenderTextureFormat.RHalf;
|
||||
descriptor.depthBufferBits = 0;
|
||||
descriptor.enableRandomWrite = true;
|
||||
|
||||
_MaskRT.Release();
|
||||
_MaskRT.descriptor = descriptor;
|
||||
|
||||
descriptor.colorFormat = RenderTextureFormat.Depth;
|
||||
descriptor.depthBufferBits = (int)k_DepthBits;
|
||||
descriptor.enableRandomWrite = false;
|
||||
|
||||
_DepthRT.Release();
|
||||
_DepthRT.descriptor = descriptor;
|
||||
}
|
||||
|
||||
void OnPreRenderMask(Camera camera)
|
||||
{
|
||||
_MaskCommandBuffer.Clear();
|
||||
|
||||
var descriptor = XRHelpers.GetRenderTextureDescriptor(camera);
|
||||
|
||||
descriptor.useDynamicScale = camera.allowDynamicResolution;
|
||||
|
||||
// Keywords and other things.
|
||||
SetUpMaskTextures(descriptor);
|
||||
|
||||
#if d_CrestPortals
|
||||
// Populate water volume before mask so we can use the stencil.
|
||||
if (_Portals.Active)
|
||||
{
|
||||
_Portals.ReAllocate(descriptor);
|
||||
_Portals.RenderMask(camera, _MaskCommandBuffer, _MaskMaterial);
|
||||
_Portals.RenderStencil(_MaskCommandBuffer, _DepthRT, _DepthTarget);
|
||||
}
|
||||
#endif
|
||||
|
||||
_MaskCommandBuffer.SetRenderTarget(_MaskTarget, _DepthTarget);
|
||||
SetUpMask(_MaskCommandBuffer, _MaskTarget, _DepthTarget);
|
||||
PopulateMask(_MaskCommandBuffer, camera);
|
||||
|
||||
FixMaskArtefacts(_MaskCommandBuffer, descriptor, _MaskTarget);
|
||||
}
|
||||
|
||||
internal void SetUpMask(CommandBuffer buffer, RenderTargetIdentifier maskTarget, RenderTargetIdentifier depthTarget)
|
||||
{
|
||||
// When using the stencil we are already clearing depth and do not want to clear the stencil too. Clear
|
||||
// color only when using the stencil as the horizon effectively clears it when not using it.
|
||||
buffer.ClearRenderTarget(!UseStencilBuffer, UseStencilBuffer, Color.black);
|
||||
buffer.SetGlobalTexture(ShaderIDs.s_WaterMaskTexture, maskTarget);
|
||||
buffer.SetGlobalTexture(ShaderIDs.s_WaterMaskDepthTexture, depthTarget);
|
||||
}
|
||||
|
||||
internal void FixMaskArtefacts(CommandBuffer buffer, RenderTextureDescriptor descriptor, RenderTargetIdentifier target)
|
||||
{
|
||||
if (_Debug._DisableArtifactCorrection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.SetComputeTextureParam(_ArtifactsShader, _ArtifactsKernel, ShaderIDs.s_WaterMaskTexture, target);
|
||||
// XR SPI will have a volume depth of two. If using RTHandles, then set manually as will be two for all cameras.
|
||||
_ArtifactsShader.SetKeyword("STEREO_INSTANCING_ON", descriptor.dimension == TextureDimension.Tex2DArray);
|
||||
|
||||
buffer.DispatchCompute
|
||||
(
|
||||
_ArtifactsShader,
|
||||
_ArtifactsKernel,
|
||||
// Viewport sizes are not perfect so round up to cover.
|
||||
Mathf.CeilToInt((float)descriptor.width / _ArtifactsThreadGroupSizeX),
|
||||
Mathf.CeilToInt((float)descriptor.height / _ArtifactsThreadGroupSizeY),
|
||||
descriptor.volumeDepth
|
||||
);
|
||||
}
|
||||
|
||||
// Populates a screen space mask which will inform the underwater postprocess. As a future optimisation we may
|
||||
// be able to avoid this pass completely if we can reuse the camera depth after transparents are rendered.
|
||||
internal void PopulateMask(CommandBuffer commandBuffer, Camera camera)
|
||||
{
|
||||
// Render horizon into mask using a fullscreen triangle at the far plane. Horizon must be rendered first or
|
||||
// it will overwrite the mask with incorrect values.
|
||||
{
|
||||
var zBufferParameters = Helpers.GetZBufferParameters(camera);
|
||||
// Take 0-1 linear depth and convert non-linear depth.
|
||||
_MaskMaterial.SetFloat(ShaderIDs.s_FarPlaneOffset, Helpers.LinearDepthToNonLinear(_FarPlaneMultiplier, zBufferParameters));
|
||||
|
||||
// Render fullscreen triangle with horizon mask pass.
|
||||
commandBuffer.DrawProcedural(Matrix4x4.identity, _MaskMaterial, shaderPass: k_ShaderPassWaterHorizonMask, MeshTopology.Triangles, 3, 1);
|
||||
}
|
||||
|
||||
GeometryUtility.CalculateFrustumPlanes(camera, _CameraFrustumPlanes);
|
||||
|
||||
// Get all water chunks and render them using cmd buffer, but with mask shader.
|
||||
if (!_Debug._DisableMask)
|
||||
{
|
||||
// Spends approx 0.2-0.3ms here on 2018 Dell XPS 15.
|
||||
foreach (var chunk in _Water.Chunks)
|
||||
{
|
||||
var renderer = chunk.Rend;
|
||||
// Can happen in edit mode.
|
||||
if (renderer == null) continue;
|
||||
var bounds = renderer.bounds;
|
||||
if (GeometryUtility.TestPlanesAABB(_CameraFrustumPlanes, bounds))
|
||||
{
|
||||
if ((!chunk._WaterDataHasBeenBound) && chunk.enabled)
|
||||
{
|
||||
chunk.Bind(camera);
|
||||
}
|
||||
|
||||
// Handle culled tiles for when underwater is rendered before the transparent pass.
|
||||
chunk._MaterialPropertyBlock.SetFloat(ShaderIDs.s_MaskBelowSurface, !_EnableShaderAPI || renderer.enabled ? k_MaskBelowSurface : k_MaskBelowSurfaceCull);
|
||||
renderer.SetPropertyBlock(chunk._MaterialPropertyBlock);
|
||||
|
||||
commandBuffer.DrawRenderer(renderer, _MaskMaterial, submeshIndex: 0, shaderPass: k_ShaderPassWaterSurfaceMask);
|
||||
|
||||
chunk._Visible = true;
|
||||
}
|
||||
chunk._WaterDataHasBeenBound = false;
|
||||
}
|
||||
|
||||
#if d_CrestPortals
|
||||
if (_Portals.Active)
|
||||
{
|
||||
_Portals.PopulateMask(commandBuffer, _MaskMaterial);
|
||||
}
|
||||
#endif // d_CrestPortals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user