2025-07-08 10:46:31 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Experimental.Rendering;
|
|
|
|
|
using UnityEngine.Rendering;
|
|
|
|
|
#if URP
|
|
|
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
|
using UnityEngine.VFX;
|
|
|
|
|
|
|
|
|
|
namespace StylizedWater2.DynamicEffects
|
|
|
|
|
{
|
|
|
|
|
public class DataRenderPass : ScriptableRenderPass
|
|
|
|
|
{
|
|
|
|
|
private const string profilerTag = "Water Dynamic Effects: Data";
|
|
|
|
|
private static readonly ProfilingSampler profilerSampler = new ProfilingSampler(profilerTag);
|
|
|
|
|
|
|
|
|
|
private const string LIGHTMODE_TAG = "WaterDynamicEffect";
|
|
|
|
|
|
|
|
|
|
private float renderRange;
|
|
|
|
|
private float m_renderRange;
|
|
|
|
|
private float fadeRange;
|
|
|
|
|
|
|
|
|
|
private int resolution;
|
|
|
|
|
private bool highPrecision;
|
|
|
|
|
private bool m_highPrecision;
|
|
|
|
|
|
|
|
|
|
private RTHandle renderTarget;
|
|
|
|
|
|
|
|
|
|
private const string WaterDynamicEffectsBufferName = "_WaterDynamicEffectsBuffer";
|
|
|
|
|
private static readonly int _WaterDynamicEffectsBufferID = Shader.PropertyToID(WaterDynamicEffectsBufferName);
|
|
|
|
|
private const string WaterDynamicEffectsCoordsName = "_WaterDynamicEffectsCoords";
|
|
|
|
|
private static readonly int _WaterDynamicEffectsCoords = Shader.PropertyToID(WaterDynamicEffectsCoordsName);
|
|
|
|
|
|
|
|
|
|
public static Vector4 rendererCoords;
|
|
|
|
|
|
|
|
|
|
private static Matrix4x4 projection { set; get; }
|
|
|
|
|
private static Matrix4x4 view { set; get; }
|
|
|
|
|
|
|
|
|
|
private static Vector3 centerPosition;
|
|
|
|
|
private static int CurrentResolution;
|
|
|
|
|
private static float orthoSize;
|
|
|
|
|
|
|
|
|
|
private static Color m_clearColor = new Color(0, 0, 0, 1);
|
|
|
|
|
private static readonly Quaternion viewRotation = Quaternion.Euler(new Vector3(90f, 0f, 0f));
|
|
|
|
|
private static readonly Vector3 viewScale = new Vector3(1, 1, -1);
|
|
|
|
|
private static Rect viewportRect;
|
|
|
|
|
|
|
|
|
|
//Render pass
|
|
|
|
|
FilteringSettings m_FilteringSettings;
|
|
|
|
|
RenderStateBlock m_RenderStateBlock;
|
|
|
|
|
private readonly List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>()
|
|
|
|
|
{
|
|
|
|
|
new ShaderTagId(LIGHTMODE_TAG),
|
|
|
|
|
//new ShaderTagId("UniversalForward")
|
|
|
|
|
};
|
|
|
|
|
//private static readonly Plane[] frustrumPlanes = new Plane[6];
|
|
|
|
|
|
|
|
|
|
#if UNITY_2023_1_OR_NEWER
|
|
|
|
|
private RendererListParams rendererListParams;
|
|
|
|
|
private RendererList rendererList;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private bool enableVFX;
|
|
|
|
|
public static List<VisualEffect> visualEffects = new List<VisualEffect>();
|
|
|
|
|
|
|
|
|
|
public DataRenderPass()
|
|
|
|
|
{
|
|
|
|
|
m_FilteringSettings = new FilteringSettings(RenderQueueRange.all, -1);
|
|
|
|
|
m_RenderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_6000_0_OR_NEWER //Silence warning spam
|
|
|
|
|
public override void RecordRenderGraph(UnityEngine.Rendering.RenderGraphModule.RenderGraph renderGraph, ContextContainer frameData) { }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public void Setup(ref WaterDynamicEffectsRenderFeature.Settings settings, int targetResolution)
|
|
|
|
|
{
|
|
|
|
|
this.renderRange = settings.renderRange;
|
|
|
|
|
//Percentage to units
|
|
|
|
|
this.fadeRange = (settings.renderRange * 0.5f) * (settings.fadePercentage / 100f);
|
|
|
|
|
this.enableVFX = settings.enableVFXGraphHooks;
|
|
|
|
|
this.resolution = targetResolution;
|
|
|
|
|
this.highPrecision = settings.highPrecision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Important to snap the projection to the nearest texel. Otherwise pixel swimming is introduced when moving, due to bilinear filtering
|
|
|
|
|
private static Vector3 StabilizeProjection(Vector3 pos, float texelSize)
|
|
|
|
|
{
|
|
|
|
|
float Snap(float coord, float cellSize) => Mathf.FloorToInt(coord / cellSize) * (cellSize) + (cellSize * 0.5f);
|
|
|
|
|
|
|
|
|
|
return new Vector3(Snap(pos.x, texelSize), Snap(pos.y, texelSize), Snap(pos.z, texelSize));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetupProjection(CommandBuffer cmd, Camera camera)
|
|
|
|
|
{
|
|
|
|
|
centerPosition = camera.transform.position + (camera.transform.forward * (orthoSize - fadeRange));
|
|
|
|
|
|
|
|
|
|
centerPosition = StabilizeProjection(centerPosition, (orthoSize * 2f) / resolution);
|
|
|
|
|
|
|
|
|
|
//var frustumHeight = 2.0f * renderRange * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad); //Still clips, plus doesn't support orthographc
|
|
|
|
|
var frustumHeight = orthoSize * 2f;
|
|
|
|
|
centerPosition += (Vector3.up * frustumHeight * 0.5f);
|
|
|
|
|
|
|
|
|
|
projection = Matrix4x4.Ortho(-orthoSize, orthoSize, -orthoSize, orthoSize, 0.03f, frustumHeight);
|
|
|
|
|
|
|
|
|
|
view = Matrix4x4.TRS(centerPosition, viewRotation, viewScale).inverse;
|
|
|
|
|
|
|
|
|
|
cmd.SetViewProjectionMatrices(view, projection);
|
|
|
|
|
//RenderingUtils.SetViewAndProjectionMatrices(cmd, view, projection, true);
|
|
|
|
|
|
|
|
|
|
viewportRect.width = resolution;
|
|
|
|
|
viewportRect.height = resolution;
|
|
|
|
|
cmd.SetViewport(viewportRect);
|
|
|
|
|
|
|
|
|
|
//Don't actually need this, not performing any AABB operations
|
|
|
|
|
//GeometryUtility.CalculateFrustumPlanes(projection * view, frustrumPlanes);
|
|
|
|
|
|
|
|
|
|
//Position/scale of projection. Converted to a UV in the shader
|
|
|
|
|
rendererCoords.x = centerPosition.x - orthoSize;
|
|
|
|
|
rendererCoords.y = centerPosition.z - orthoSize;
|
|
|
|
|
rendererCoords.z = orthoSize * 2f;
|
|
|
|
|
rendererCoords.w = 1f; //Enable in shader
|
|
|
|
|
|
|
|
|
|
cmd.SetGlobalVector(_WaterDynamicEffectsCoords, rendererCoords);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetupVFX()
|
|
|
|
|
{
|
|
|
|
|
if (enableVFX)
|
|
|
|
|
{
|
|
|
|
|
foreach (VisualEffect vfx in visualEffects)
|
|
|
|
|
{
|
|
|
|
|
if (!vfx) continue;
|
|
|
|
|
|
|
|
|
|
vfx.SetTexture(WaterDynamicEffectsBufferName, renderTarget);
|
|
|
|
|
vfx.SetVector4(WaterDynamicEffectsCoordsName, rendererCoords);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
|
|
|
#pragma warning disable CS0672
|
|
|
|
|
#pragma warning disable CS0618
|
|
|
|
|
#endif
|
|
|
|
|
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
|
|
|
|
|
{
|
|
|
|
|
orthoSize = renderRange * 0.5f;
|
|
|
|
|
|
|
|
|
|
if (resolution != CurrentResolution || highPrecision != m_highPrecision ||renderTarget == null)
|
|
|
|
|
{
|
|
|
|
|
RTHandles.Release(renderTarget);
|
|
|
|
|
|
|
|
|
|
renderTarget = RTHandles.Alloc(resolution, resolution, 1, DepthBits.None,
|
|
|
|
|
highPrecision ? GraphicsFormat.R16G16B16A16_SFloat : GraphicsFormat.R8G8B8A8_SNorm,
|
|
|
|
|
filterMode: FilterMode.Bilinear,
|
|
|
|
|
wrapMode: TextureWrapMode.Clamp,
|
|
|
|
|
useMipMap: false, //TODO: Expose option
|
|
|
|
|
autoGenerateMips: true,
|
|
|
|
|
name: WaterDynamicEffectsBufferName);
|
|
|
|
|
}
|
|
|
|
|
CurrentResolution = resolution;
|
|
|
|
|
m_highPrecision = highPrecision;
|
|
|
|
|
|
|
|
|
|
cmd.SetGlobalTexture(_WaterDynamicEffectsBufferID, renderTarget);
|
|
|
|
|
cmd.SetGlobalInt("_WaterDynamicEffectsHighPrecision", highPrecision ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
ConfigureTarget(renderTarget);
|
|
|
|
|
ConfigureClear(ClearFlag.Color, m_clearColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
|
|
|
{
|
|
|
|
|
CommandBuffer cmd = CommandBufferPool.Get();
|
|
|
|
|
|
|
|
|
|
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, SortingCriteria.RenderQueue | SortingCriteria.SortingLayer | SortingCriteria.CommonTransparent);
|
|
|
|
|
drawingSettings.perObjectData = PerObjectData.None;
|
|
|
|
|
|
|
|
|
|
using (new ProfilingScope(cmd, profilerSampler))
|
|
|
|
|
{
|
|
|
|
|
ref CameraData cameraData = ref renderingData.cameraData;
|
|
|
|
|
|
|
|
|
|
SetupProjection(cmd, cameraData.camera);
|
|
|
|
|
|
|
|
|
|
//Execute current commands first
|
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
|
|
|
cmd.Clear();
|
|
|
|
|
|
|
|
|
|
#if UNITY_2023_1_OR_NEWER
|
|
|
|
|
rendererListParams.cullingResults = renderingData.cullResults;
|
|
|
|
|
rendererListParams.drawSettings = drawingSettings;
|
|
|
|
|
rendererListParams.filteringSettings = m_FilteringSettings;
|
|
|
|
|
rendererList = context.CreateRendererList(ref rendererListParams);
|
|
|
|
|
|
|
|
|
|
cmd.DrawRendererList(rendererList);
|
|
|
|
|
#else
|
|
|
|
|
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings, ref m_RenderStateBlock);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//context.ExecuteCommandBuffer(cmd);
|
|
|
|
|
|
|
|
|
|
//Restore
|
|
|
|
|
//cmd.Clear();
|
|
|
|
|
cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
|
|
|
|
|
//RenderingUtils.SetViewAndProjectionMatrices(cmd, cameraData.GetViewMatrix(), cameraData.GetGPUProjectionMatrix(), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
|
|
|
CommandBufferPool.Release(cmd);
|
|
|
|
|
|
|
|
|
|
SetupVFX();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void FrameCleanup(CommandBuffer cmd)
|
|
|
|
|
{
|
|
|
|
|
rendererCoords.w = 0f; //Boolean in shader code, disables sampling
|
|
|
|
|
cmd.SetGlobalVector(_WaterDynamicEffectsCoords, rendererCoords);
|
|
|
|
|
cmd.DisableShaderKeyword(WaterDynamicEffectsRenderFeature.KEYWORD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Shader.SetGlobalVector(_WaterDynamicEffectsCoords, Vector4.zero);
|
|
|
|
|
RTHandles.Release(renderTarget);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|