diff --git a/Runtime/MotionBlur.cs b/Runtime/MotionBlur.cs
index fb48a15..b147d5a 100644
--- a/Runtime/MotionBlur.cs
+++ b/Runtime/MotionBlur.cs
@@ -8,6 +8,12 @@ namespace kTools.Motion
[Serializable, VolumeComponentMenu("kMotion/Motion Blur")]
public sealed class MotionBlur: VolumeComponent, IPostProcessComponent
{
+ ///
+ /// Enable/Disable camera-based motion blur. Object-based motion blur is applied anyway.
+ ///
+ [Tooltip("Enable/Disable camera-based motion blur. Object-based motion blur is applied anyway.")]
+ public BoolParameter cameraBasedMB = new BoolParameter(true);
+
///
/// The quality of the effect. Lower presets will result in better performance at the expense of visual quality.
///
@@ -19,7 +25,13 @@ public sealed class MotionBlur: VolumeComponent, IPostProcessComponent
///
[Tooltip("The strength of the motion blur filter. Acts as a multiplier for velocities.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
-
+
+ ///
+ /// The minimum velocity for the motion blur filter to be applied.
+ ///
+ [Tooltip("The minimum velocity for the motion blur filter to be applied.")]
+ public ClampedFloatParameter threshold = new ClampedFloatParameter(0.01f, 0f, 1f);
+
///
/// Is the component active?
///
diff --git a/Runtime/MotionBlurRenderPass.cs b/Runtime/MotionBlurRenderPass.cs
index 8dfb0e2..e4cd462 100644
--- a/Runtime/MotionBlurRenderPass.cs
+++ b/Runtime/MotionBlurRenderPass.cs
@@ -24,7 +24,7 @@ sealed class MotionBlurRenderPass : ScriptableRenderPass
internal MotionBlurRenderPass()
{
// Set data
- renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
+ renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
}
#endregion
@@ -33,7 +33,8 @@ internal void Setup(MotionBlur motionBlur)
{
// Set data
m_MotionBlur = motionBlur;
- m_Material = new Material(Shader.Find(kMotionBlurShader));
+ if(!m_Material)
+ m_Material = new Material(Shader.Find(kMotionBlurShader));
}
#endregion
@@ -53,7 +54,8 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData
{
// Set Material properties from VolumeComponent
m_Material.SetFloat("_Intensity", m_MotionBlur.intensity.value);
-
+ m_Material.SetFloat("_Threshold", m_MotionBlur.threshold.value);
+
// TODO: Why doesnt RenderTargetHandle.CameraTarget work?
var colorTextureIdentifier = new RenderTargetIdentifier("_CameraColorTexture");
diff --git a/Runtime/MotionRendererFeature.cs b/Runtime/MotionRendererFeature.cs
index 942eb47..b999485 100644
--- a/Runtime/MotionRendererFeature.cs
+++ b/Runtime/MotionRendererFeature.cs
@@ -8,9 +8,10 @@ namespace kTools.Motion
sealed class MotionRendererFeature : ScriptableRendererFeature
{
#region Fields
+ public LayerMask m_LayerMask;
static MotionRendererFeature s_Instance;
- readonly MotionVectorRenderPass m_MotionVectorRenderPass;
- readonly MotionBlurRenderPass m_MotionBlurRenderPass;
+ static MotionVectorRenderPass m_MotionVectorRenderPass;
+ static MotionBlurRenderPass m_MotionBlurRenderPass;
Dictionary m_MotionDatas;
uint m_FrameCount;
@@ -23,9 +24,6 @@ internal MotionRendererFeature()
{
// Set data
s_Instance = this;
- m_MotionVectorRenderPass = new MotionVectorRenderPass();
- m_MotionBlurRenderPass = new MotionBlurRenderPass();
- m_MotionDatas = new Dictionary();
}
#endregion
@@ -33,12 +31,19 @@ internal MotionRendererFeature()
public override void Create()
{
name = "Motion";
+ m_MotionVectorRenderPass = new MotionVectorRenderPass();
+ m_MotionBlurRenderPass = new MotionBlurRenderPass();
+ m_MotionDatas = new Dictionary();
}
#endregion
#region RenderPass
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
+ // Get motion blur settings
+ var stack = VolumeManager.instance.stack;
+ var motionBlur = stack.GetComponent();
+
// Get MotionData
var camera = renderingData.cameraData.camera;
MotionData motionData;
@@ -53,12 +58,10 @@ public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingD
UpdateMotionData(camera, motionData);
// Motion vector pass
- m_MotionVectorRenderPass.Setup(motionData);
+ m_MotionVectorRenderPass.Setup(motionData, motionBlur, m_LayerMask.value);
renderer.EnqueuePass(m_MotionVectorRenderPass);
// Motion blur pass
- var stack = VolumeManager.instance.stack;
- var motionBlur = stack.GetComponent();
if (motionBlur.IsActive() && !renderingData.cameraData.isSceneViewCamera)
{
m_MotionBlurRenderPass.Setup(motionBlur);
diff --git a/Runtime/MotionVectorRenderPass.cs b/Runtime/MotionVectorRenderPass.cs
index 0456709..96108be 100644
--- a/Runtime/MotionVectorRenderPass.cs
+++ b/Runtime/MotionVectorRenderPass.cs
@@ -24,6 +24,8 @@ sealed class MotionVectorRenderPass : ScriptableRenderPass
Material m_CameraMaterial;
Material m_ObjectMaterial;
MotionData m_MotionData;
+ MotionBlur m_MotionBlur;
+ int m_layerMask;
#endregion
#region Constructors
@@ -35,24 +37,30 @@ internal MotionVectorRenderPass()
#endregion
#region State
- internal void Setup(MotionData motionData)
+ internal void Setup(MotionData motionData, MotionBlur motionBlur, int layerMask)
{
// Set data
m_MotionData = motionData;
- m_CameraMaterial = new Material(Shader.Find(kCameraShader));
- m_ObjectMaterial = new Material(Shader.Find(kObjectShader));
+ m_MotionBlur = motionBlur;
+ m_layerMask = layerMask;
+ if(!m_CameraMaterial)
+ m_CameraMaterial = new Material(Shader.Find(kCameraShader));
+ if(!m_ObjectMaterial)
+ m_ObjectMaterial = new Material(Shader.Find(kObjectShader));
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
// Configure Render Target
m_MotionVectorHandle.Init(kMotionVectorTexture);
+ cameraTextureDescriptor.colorFormat = RenderTextureFormat.RG16;
+ // Debug.Log(cameraTextureDescriptor.colorFormat);
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);
+ // Clear with 0.5 because we packed vectors from clip into NDC space
+ cmd.ClearRenderTarget(true, true, Color.gray, 1.0f);
}
#endregion
@@ -80,7 +88,8 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData
camera.depthTextureMode |= DepthTextureMode.MotionVectors | DepthTextureMode.Depth;
// Drawing
- DrawCameraMotionVectors(context, cmd, camera);
+ if(m_MotionBlur.cameraBasedMB.value)
+ DrawCameraMotionVectors(context, cmd, camera);
DrawObjectMotionVectors(context, ref renderingData, cmd, camera);
}
ExecuteCommand(context, cmd);
@@ -128,7 +137,7 @@ void DrawObjectMotionVectors(ScriptableRenderContext context, ref RenderingData
var cullingResults = context.Cull(ref cullingParameters);
var drawingSettings = GetDrawingSettings(ref renderingData);
- var filteringSettings = new FilteringSettings(RenderQueueRange.opaque, camera.cullingMask);
+ var filteringSettings = new FilteringSettings(RenderQueueRange.opaque, camera.cullingMask & m_layerMask);
var renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
// Draw Renderers
diff --git a/Shaders/CameraMotionVectors.shader b/Shaders/CameraMotionVectors.shader
index 5e27f4a..4944d0a 100644
--- a/Shaders/CameraMotionVectors.shader
+++ b/Shaders/CameraMotionVectors.shader
@@ -69,8 +69,7 @@
// Convert velocity from Clip space (-1..1) to NDC 0..1 space
// Note it doesn't mean we don't have negative value, we store negative or positive offset in NDC space.
- // Note: ((positionVP * 0.5 + 0.5) - (previousPositionVP * 0.5 + 0.5)) = (velocity * 0.5)
- return half4(velocity.xy * 0.5, 0, 0);
+ return half4(velocity.xy * 0.5 + 0.5, 0, 0);
}
ENDHLSL
diff --git a/Shaders/MotionBlur.shader b/Shaders/MotionBlur.shader
index b8ee1b2..eec76c4 100644
--- a/Shaders/MotionBlur.shader
+++ b/Shaders/MotionBlur.shader
@@ -20,6 +20,7 @@
TEXTURE2D(_MotionVectorTexture); SAMPLER(sampler_MotionVectorTexture);
float _Intensity;
+ float _Threshold;
float4 _MainTex_TexelSize;
// -------------------------------------
@@ -52,11 +53,11 @@
// -------------------------------------
// Fragment
- float3 GatherSample(float sampleNumber, float2 velocity, float invSampleCount, float2 centerUV, float randomVal, float velocitySign)
+ float4 GatherSample(float sampleNumber, float2 velocity, float invSampleCount, float2 centerUV, float randomVal, float velocitySign)
{
float offsetLength = (sampleNumber + 0.5) + (velocitySign * (randomVal - 0.5));
float2 sampleUV = centerUV + (offsetLength * invSampleCount) * velocity * velocitySign;
- return SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, sampleUV).xyz;
+ return SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, sampleUV);
}
half4 DoMotionBlur(VaryingsMB input, int iterations)
@@ -64,11 +65,19 @@
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv.xy);
- float2 velocity = SAMPLE_TEXTURE2D(_MotionVectorTexture, sampler_MotionVectorTexture, uv).rg * _Intensity;
+ float2 velocity = (SAMPLE_TEXTURE2D(_MotionVectorTexture, sampler_MotionVectorTexture, uv).rg * 2 - 1);
+ // return half4(abs(velocity), 0, 1);
+
+ if(length(velocity) < _Threshold)
+ {
+ return SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv);
+ }
+ velocity *= _Intensity;
+
float randomVal = InterleavedGradientNoise(uv * _MainTex_TexelSize.zw, 0);
float invSampleCount = rcp(iterations * 2.0);
- half3 color = 0.0;
+ half4 color = 0.0;
UNITY_UNROLL
for (int i = 0; i < iterations; i++)
@@ -77,7 +86,7 @@
color += GatherSample(i, velocity, invSampleCount, uv, randomVal, 1.0);
}
- return half4(color * invSampleCount, 1.0);
+ return color * invSampleCount;
}
ENDHLSL
diff --git a/Shaders/ObjectMotionVectors.shader b/Shaders/ObjectMotionVectors.shader
index 6b9220c..ac1b175 100644
--- a/Shaders/ObjectMotionVectors.shader
+++ b/Shaders/ObjectMotionVectors.shader
@@ -73,7 +73,7 @@
#else
output.positionCS.z += unity_MotionVectorsParams.z * output.positionCS.w;
#endif
-
+
output.positionVP = mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, input.position));
output.previousPositionVP = mul(_PrevViewProjMatrix, mul(unity_MatrixPreviousM, unity_MotionVectorsParams.x == 1 ? float4(input.positionOld, 1) : input.position));
return output;
@@ -105,8 +105,7 @@
// Convert from Clip space (-1..1) to NDC 0..1 space.
// Note it doesn't mean we don't have negative value, we store negative or positive offset in NDC space.
- // Note: ((positionCS * 0.5 + 0.5) - (previousPositionCS * 0.5 + 0.5)) = (velocity * 0.5)
- return float4(velocity.xy * 0.5, 0, 0);
+ return float4(velocity.xy * 0.5 + 0.5, 0, 0);
}
ENDHLSL
}