- Home /
Use Shader Motion Vectors pass in Surface Shader
Hey everybody, I'm trying to create a shader, where the speed of a pixel (meaning the difference before it's previous position and it's current position) is used for coloring. For example, I want to make the parts of my object glow brighter the faster they are moving. I've been trying to save the previous vertex position in my shader for using it in the next frame to calculate the velocity of the pixel. But that does not seem to work. Or at least I could not get it working that way. ^^"
So, after some further googling I found that Unity now has a pass for Motion vectors. I could not get a clear understanding of how they work in the documentation. So my question is: Can I get the values of the Motion vectors in my surface shader to control it's color based on the pixels velocity?
I would be very grateful for any help :)
Kai
Answer by Voleuro · Feb 19, 2018 at 01:16 PM
So,
After a good nights sleep and a few more hours testing with different shaders and scripts, I've now come to the point where I did write a Post Process Shader that displays the Magnitude of the Motion Vector Buffers in Black and White. So I know the Values are there and I can use them. :D I based my Code upon William Chyr's Depth Shader Code. You can find it here: http://willychyr.com/2013/11/unity-shaders-depth-and-normal-textures/
For anyone interested in it, here's my current version:
The c# Script for the Post Processing Shader:
using UnityEngine;
using System.Collections;
//so that we can see changes we make without having to run the game
[ExecuteInEditMode]
public class PostProcessDepthGrayscale : MonoBehaviour {
public Material mat;
void Start () {
//GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
GetComponent<Camera>().depthTextureMode = DepthTextureMode.MotionVectors;
}
void OnRenderImage (RenderTexture source, RenderTexture destination){
Graphics.Blit(source,destination,mat);
}
}
And the Shader itself:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/DepthGrayscale" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _CameraDepthTexture;
sampler2D _CameraMotionVectorsTexture;
struct v2f {
float4 pos : SV_POSITION;
float4 scrPos:TEXCOORD1;
};
//Vertex Shader
v2f vert (appdata_base v){
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.scrPos=ComputeScreenPos(o.pos);
return o;
}
//Fragment Shader
half4 frag (v2f i) : COLOR{
half4 depth;
depth.r = saturate(abs(300*tex2Dproj(_CameraMotionVectorsTexture, UNITY_PROJ_COORD(i.scrPos)).r));
depth.g = saturate(abs(300*tex2Dproj(_CameraMotionVectorsTexture, UNITY_PROJ_COORD(i.scrPos)).g));
depth.b = saturate(abs(300*tex2Dproj(_CameraMotionVectorsTexture, UNITY_PROJ_COORD(i.scrPos)).b));
depth.a = 1;
float combined = sqrt( depth.r*depth.r + depth.g*depth.g + depth.b*depth.b);
depth.r = combined;
depth.g = combined;
depth.b = combined;
return depth;
}
ENDCG
}
}
FallBack "Diffuse"
}
The only Thing I'm now struggling with is transfering this effect into a surface shader to use as Material on an object. It always gives me the Warning "Motion vectors require depth texture. Adding this flag to depthTexureMode" and somehow uses the DepthTexture of the Scene Viewport, not the Game Viewport. ^^"
I would appreciate your Help with this.
Answer by agentrsdg · Apr 29, 2018 at 09:34 AM
@Voleuro I used fixed4 frag(v2f i) : SV_Target{
instead of half4 frag (v2f i) : COLOR{
and your solution works great! It helped me in my project, so thanks!