'push'
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
// Crest Water System
|
||||
// Copyright © 2024 Wave Harmonic. All rights reserved.
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using WaveHarmonic.Crest.Internal;
|
||||
|
||||
namespace WaveHarmonic.Crest
|
||||
{
|
||||
partial class UnderwaterRenderer : MaskRenderer.IMaskReceiver, MaskRenderer.IMaskProvider
|
||||
{
|
||||
internal const string k_DrawMask = "Crest.DrawMask";
|
||||
const string k_DrawMaskHorizon = "Horizon";
|
||||
const string k_DrawMaskSurface = "Surface";
|
||||
|
||||
internal const int k_VolumeMaskQueue = 1000;
|
||||
|
||||
internal const int k_ShaderPassWaterSurfaceMask = 0;
|
||||
internal const int k_ShaderPassWaterSurfaceDepth = 1;
|
||||
internal const int k_ShaderPassWaterHorizonMask = 0;
|
||||
|
||||
internal const string k_ComputeShaderKernelFillMaskArtefacts = "FillMaskArtefacts";
|
||||
|
||||
static partial class ShaderIDs
|
||||
{
|
||||
// Local
|
||||
public static readonly int s_FarPlaneOffset = Shader.PropertyToID("_Crest_FarPlaneOffset");
|
||||
}
|
||||
|
||||
internal Material _MaskMaterial;
|
||||
internal Material _HorizonMaskMaterial;
|
||||
|
||||
ComputeShader _ArtifactsShader;
|
||||
bool _ArtifactsShaderInitialized;
|
||||
int _ArtifactsKernel;
|
||||
uint _ArtifactsThreadGroupSizeX;
|
||||
uint _ArtifactsThreadGroupSizeY;
|
||||
|
||||
internal void OnEnableMask()
|
||||
{
|
||||
_Water._Mask.Add(this);
|
||||
_Water._Mask.Add(k_VolumeMaskQueue, this);
|
||||
|
||||
SetUpArtifactsShader();
|
||||
}
|
||||
|
||||
internal void OnDisableMask()
|
||||
{
|
||||
if (_Water == null) return;
|
||||
_Water._Mask?.Remove(this as MaskRenderer.IMaskReceiver);
|
||||
_Water._Mask?.Remove(this as MaskRenderer.IMaskProvider);
|
||||
}
|
||||
|
||||
internal void SetUpArtifactsShader()
|
||||
{
|
||||
if (_ArtifactsShaderInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ArtifactsKernel = _ArtifactsShader.FindKernel(k_ComputeShaderKernelFillMaskArtefacts);
|
||||
_ArtifactsShader.GetKernelThreadGroupSizes
|
||||
(
|
||||
_ArtifactsKernel,
|
||||
out _ArtifactsThreadGroupSizeX,
|
||||
out _ArtifactsThreadGroupSizeY,
|
||||
out _
|
||||
);
|
||||
|
||||
_ArtifactsShaderInitialized = true;
|
||||
}
|
||||
|
||||
void MaskRenderer.IMaskProvider.OnMaskPass(CommandBuffer commands, Camera camera, MaskRenderer mask)
|
||||
{
|
||||
var color = mask.ColorRTH;
|
||||
var depth = mask.DepthRTH;
|
||||
|
||||
var size = color.GetScaledSize(color.rtHandleProperties.currentViewportSize);
|
||||
var descriptor = color.rt.descriptor;
|
||||
descriptor.width = size.x; descriptor.height = size.y;
|
||||
|
||||
if (UseLegacyMask)
|
||||
{
|
||||
// Portals changes the target.
|
||||
// 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.
|
||||
CoreUtils.SetRenderTarget(commands, color, depth, UseStencilBuffer ? ClearFlag.Color : ClearFlag.DepthStencil);
|
||||
Helpers.ScaleViewport(camera, commands, color);
|
||||
|
||||
PopulateMask(commands, camera);
|
||||
FixMaskArtefacts(commands, descriptor, mask._ColorRTI);
|
||||
}
|
||||
// Portals have their own fitted to the portal bounds.
|
||||
else
|
||||
#if d_CrestPortals
|
||||
if (!Portaled || _Water.Portals.RequiresFullScreenMask)
|
||||
#endif
|
||||
{
|
||||
#if d_CrestPortals
|
||||
if (_Water.Portals.Mode != Portals.PortalMode.VolumeFlyThrough)
|
||||
#endif
|
||||
{
|
||||
RenderLineMask(commands, camera, mask.ColorRT.descriptor, mask._ColorRTI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void RenderLineMask(CommandBuffer buffer, Camera camera, RenderTextureDescriptor descriptor, RenderTargetIdentifier target)
|
||||
{
|
||||
if (!_Water.Surface.Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new PropertyWrapperCompute(buffer, WaterResources.Instance.Compute._Mask, (int)RenderPipelineHelper.RenderPipeline);
|
||||
|
||||
var parameters = _Water.Surface._SurfaceDataParameters;
|
||||
|
||||
wrapper.SetTexture(SurfaceRenderer.ShaderIDs.s_WaterLine, _Water.Surface.HeightRT);
|
||||
wrapper.SetVector(SurfaceRenderer.ShaderIDs.s_WaterLineSnappedPosition, parameters._SnappedPosition);
|
||||
wrapper.SetVector(SurfaceRenderer.ShaderIDs.s_WaterLineResolution, parameters._Resolution);
|
||||
wrapper.SetFloat(SurfaceRenderer.ShaderIDs.s_WaterLineTexel, parameters._Texel);
|
||||
|
||||
// XR SPI will have a volume depth of two. If using RTHandles, then set manually as will be two for all cameras.
|
||||
wrapper.SetKeyword(new(WaterResources.Instance.Compute._Mask, "STEREO_INSTANCING_ON"), descriptor.dimension == TextureDimension.Tex2DArray);
|
||||
|
||||
// Setting this sets unity_CameraToWorld.
|
||||
wrapper.SetMatrix(Crest.ShaderIDs.Unity.s_CameraToWorld, camera.cameraToWorldMatrix);
|
||||
|
||||
// Viewport sizes are not perfect so round up to cover.
|
||||
wrapper.Dispatch(Mathf.CeilToInt(descriptor.width / 8f), Mathf.CeilToInt(descriptor.height / 8f), descriptor.volumeDepth);
|
||||
}
|
||||
|
||||
internal void FixMaskArtefacts(CommandBuffer buffer, RenderTextureDescriptor descriptor, RenderTargetIdentifier target)
|
||||
{
|
||||
if (_Debug._DisableArtifactCorrection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_Water.Surface.Enabled && Portaled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.SetComputeTextureParam(_ArtifactsShader, _ArtifactsKernel, MaskRenderer.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)
|
||||
{
|
||||
if (!_Water.Surface.Enabled && Portaled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
_HorizonMaskMaterial.SetFloat(ShaderIDs.s_FarPlaneOffset, Helpers.LinearDepthToNonLinear(_FarPlaneMultiplier, zBufferParameters));
|
||||
|
||||
// Render fullscreen triangle with horizon mask pass.
|
||||
commandBuffer.BeginSample(k_DrawMaskHorizon);
|
||||
commandBuffer.DrawProcedural(Matrix4x4.identity, _HorizonMaskMaterial, shaderPass: k_ShaderPassWaterHorizonMask, MeshTopology.Triangles, 3, 1);
|
||||
commandBuffer.EndSample(k_DrawMaskHorizon);
|
||||
}
|
||||
|
||||
// Get all water chunks and render them using cmd buffer, but with mask shader.
|
||||
if (!_Debug._DisableMask)
|
||||
{
|
||||
commandBuffer.BeginSample(k_DrawMaskSurface);
|
||||
_Water.Surface.Render(camera, commandBuffer, _MaskMaterial, k_ShaderPassWaterSurfaceMask);
|
||||
commandBuffer.EndSample(k_DrawMaskSurface);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool _MaskRead;
|
||||
bool _DoneMaskRead;
|
||||
|
||||
MaskRenderer.MaskInput MaskRenderer.IMaskProvider.Allocate()
|
||||
{
|
||||
return MaskRenderer.MaskInput.Both;
|
||||
}
|
||||
|
||||
MaskRenderer.MaskInput MaskRenderer.IMaskReceiver.Allocate()
|
||||
{
|
||||
return MaskRenderer.MaskInput.Both;
|
||||
}
|
||||
|
||||
MaskRenderer.MaskInput MaskRenderer.IMaskProvider.Write(Camera camera)
|
||||
{
|
||||
if (!_DoneMaskRead)
|
||||
{
|
||||
_MaskRead = ShouldRender(camera, Pass.Mask);
|
||||
_DoneMaskRead = true;
|
||||
}
|
||||
|
||||
return _MaskRead ? _Water.Surface.Enabled ? MaskRenderer.MaskInput.Both : MaskRenderer.MaskInput.Color : MaskRenderer.MaskInput.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user