Files
beyond/Assets/ThirdParty/ARTnGAME/kMotion/Runtime/MotionVectorRenderPass.cs
2024-11-20 15:21:28 +01:00

163 lines
6.0 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace kTools.Motion
{
sealed class MotionVectorRenderPass : ScriptableRenderPass
{
#region Fields
const string kCameraShader = "Hidden/kMotion/CameraMotionVectors";
const string kObjectShader = "Hidden/kMotion/ObjectMotionVectors";
const string kPreviousViewProjectionMatrix = "_PrevViewProjMatrix";
const string kMotionVectorTexture = "_MotionVectorTexture";
const string kProfilingTag = "Motion Vectors";
static readonly string[] s_ShaderTags = new string[]
{
"UniversalForward",
"LightweightForward",
};
RenderTargetHandle m_MotionVectorHandle;
Material m_CameraMaterial;
Material m_ObjectMaterial;
MotionData m_MotionData;
#endregion
#region Constructors
internal MotionVectorRenderPass()
{
// Set data
renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
}
#endregion
#region State
internal void Setup(MotionData motionData)
{
// Set data
m_MotionData = motionData;
m_CameraMaterial = new Material(Shader.Find(kCameraShader));
m_ObjectMaterial = new Material(Shader.Find(kObjectShader));
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
// Configure Render Target
m_MotionVectorHandle.Init(kMotionVectorTexture);
cmd.GetTemporaryRT(m_MotionVectorHandle.id, cameraTextureDescriptor, FilterMode.Point);
ConfigureTarget(m_MotionVectorHandle.Identifier(), m_MotionVectorHandle.Identifier());
cmd.SetRenderTarget(m_MotionVectorHandle.Identifier(), m_MotionVectorHandle.Identifier());
// TODO: Why do I have to clear here?
cmd.ClearRenderTarget(true, true, Color.black, 1.0f);
}
#endregion
#region Execution
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// Get data
var camera = renderingData.cameraData.camera;
// Never draw in Preview
if(camera.cameraType == CameraType.Preview)
return;
// Profiling command
CommandBuffer cmd = CommandBufferPool.Get(kProfilingTag);
using (new ProfilingSample(cmd, kProfilingTag))
{
ExecuteCommand(context, cmd);
// Shader uniforms
Shader.SetGlobalMatrix(kPreviousViewProjectionMatrix, m_MotionData.previousViewProjectionMatrix);
// These flags are still required in SRP or the engine won't compute previous model matrices...
// If the flag hasn't been set yet on this camera, motion vectors will skip a frame.
camera.depthTextureMode |= DepthTextureMode.MotionVectors | DepthTextureMode.Depth;
// Drawing
DrawCameraMotionVectors(context, cmd, camera);
// DrawObjectMotionVectors(context, ref renderingData, cmd, camera);
}
ExecuteCommand(context, cmd);
}
DrawingSettings GetDrawingSettings(ref RenderingData renderingData)
{
// Drawing Settings
var camera = renderingData.cameraData.camera;
var sortingSettings = new SortingSettings(camera) { criteria = SortingCriteria.CommonOpaque };
var drawingSettings = new DrawingSettings(ShaderTagId.none, sortingSettings)
{
perObjectData = PerObjectData.MotionVectors,
enableDynamicBatching = renderingData.supportsDynamicBatching,
enableInstancing = true,
};
// Shader Tags
for (int i = 0; i < s_ShaderTags.Length; ++i)
{
drawingSettings.SetShaderPassName(i, new ShaderTagId(s_ShaderTags[i]));
}
// Material
drawingSettings.overrideMaterial = m_ObjectMaterial;
drawingSettings.overrideMaterialPassIndex = 0;
return drawingSettings;
}
void DrawCameraMotionVectors(ScriptableRenderContext context, CommandBuffer cmd, Camera camera)
{
// Draw fullscreen quad
cmd.DrawProcedural(Matrix4x4.identity, m_CameraMaterial, 0, MeshTopology.Triangles, 3, 1);
ExecuteCommand(context, cmd);
}
void DrawObjectMotionVectors(ScriptableRenderContext context, ref RenderingData renderingData, CommandBuffer cmd, Camera camera)
{
// Get CullingParameters
var cullingParameters = new ScriptableCullingParameters();
if (!camera.TryGetCullingParameters(out cullingParameters))
return;
// Culling Results
var cullingResults = context.Cull(ref cullingParameters);
var drawingSettings = GetDrawingSettings(ref renderingData);
var filteringSettings = new FilteringSettings(RenderQueueRange.opaque, camera.cullingMask);
var renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
// Draw Renderers
context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings, ref renderStateBlock);
}
#endregion
#region Cleanup
public override void FrameCleanup(CommandBuffer cmd)
{
if (cmd == null)
throw new ArgumentNullException("cmd");
// Reset Render Target
if (m_MotionVectorHandle != RenderTargetHandle.CameraTarget)
{
cmd.ReleaseTemporaryRT(m_MotionVectorHandle.id);
m_MotionVectorHandle = RenderTargetHandle.CameraTarget;
}
}
#endregion
#region CommandBufer
void ExecuteCommand(ScriptableRenderContext context, CommandBuffer cmd)
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
}
#endregion
}
}