The view matrix describes the position and angle of the camera. The projection matrix describes other information such as the aspect ratio and field of view.
You need to store the view matrix and projection matrix, and send them to the shader in the next frame. The shader compares those matrices to the current frame's matrices to figure out how far everything has moved since the previous frame. This creates an image called a velocity map, which uses colours to indicate the velocity of each pixel.
After that, another shader blurs the image on screen based on this velocity map.
Here is the shader that generates the velocity map. I also included some techniques for lighting that are based off of evolved shaders.
// *********************************************************************
// Camera-Based Motion Blur by Randomness128
//
// Lighting portion of the shader is from
// Normal Mapping 2.0 by EVOLVED http://www.vector3r.com/
// *********************************************************************
// ******************************************************
// Matrices
// ******************************************************
matrix CurrentWVP:WorldViewProjection;
matrix CurrentW:World;
matrix PreviousV;
matrix PreviousP;
// ******************************************************
// From Normal Mapping 2.0 by EVOLVED, heavily modified
// ******************************************************
float3 AmbientColor = {0.7f, 0.7f, 1.0f};
float3 LightPosition = {230.0f, 150.0f, -200.0f};
float3 LightColor = {1.8f, 1.8f, 1.0f};
float LightRange = 500.0f;
texture BaseTX
<
string Name="";
>;
sampler2D Base = sampler_state
{
texture = <BaseTX>;
};
// ******************************************************
// MotionBlur structure
// ******************************************************
struct MotionBlur_VS_Output
{
float4 OPos : POSITION;
float4 CurrentPos : TEXCOORD0;
float4 LastPos : TEXCOORD1;
};
// ******************************************************
// From Normal Mapping 2.0 by EVOLVED, heavily modified
// ******************************************************
struct Light_VS_Input
{
float4 Pos:POSITION;
float2 UV:TEXCOORD;
float3 Normal:NORMAL;
};
struct Light_VS_Output
{
float4 OPos:POSITION;
float2 Tex:TEXCOORD0;
float Diffuse:COLOR0;
};
struct Skybox_VS_Output
{
float4 OPos:POSITION;
float2 Tex:TEXCOORD0;
};
// ******************************************************
// Velocity map calculation vertex shader
// ******************************************************
MotionBlur_VS_Output MotionBlur_VS( float4 vPos : POSITION )
{
MotionBlur_VS_Output Output;
Output.OPos = mul(vPos, CurrentWVP );
Output.CurrentPos = Output.OPos;
vPos = mul( vPos, CurrentW );
vPos = mul( vPos, PreviousV );
Output.LastPos = mul(vPos, PreviousP );
return Output;
}
// ******************************************************
// From Normal Mapping 2.0 by EVOLVED, heavily modified
// ******************************************************
Light_VS_Output Light_VS(Light_VS_Input IN)
{
Light_VS_Output OUT;
OUT.OPos=mul(IN.Pos,CurrentWVP);
OUT.Tex=IN.UV;
float3 WPos=mul(IN.Pos,CurrentW);
float3 LightPos=LightPosition-WPos;
OUT.Diffuse=saturate(0.02f+mul(mul(IN.Normal,CurrentW),LightPos)*0.02f);
return OUT;
}
Skybox_VS_Output Skybox_VS( float4 vPos : POSITION, float2 UV : TEXCOORD )
{
Skybox_VS_Output Output;
Output.OPos=mul(vPos,CurrentWVP);
Output.Tex=UV;
return Output;
}
// ******************************************************
// Velocity map calculation pixel shader
// ******************************************************
float4 MotionBlur_PS(MotionBlur_VS_Output In) : COLOR
{
float2 velocity = ((In.CurrentPos/In.CurrentPos.w) - (In.LastPos/In.LastPos.w));
velocity = velocity;
return float4(velocity,0.0f,1.0f);
}
// ******************************************************
// From Normal Mapping 2.0 by EVOLVED, heavily modified
// ******************************************************
float4 Light_PS(Light_VS_Output IN) : COLOR
{
float4 Texture=tex2D(Base,IN.Tex);
float3 Light=IN.Diffuse*LightColor;
return Texture * float4(Light+AmbientColor,1);
}
float4 Skybox_PS(Skybox_VS_Output IN) : COLOR
{
float4 Texture=tex2D(Base,IN.Tex);
return Texture;
}
// ******************************************************
// Velocity map calculation technique
// ******************************************************
technique MotionBlur_Velocity
{
pass P1
{
VertexShader = compile vs_2_0 MotionBlur_VS();
PixelShader = compile ps_2_0 MotionBlur_PS();
}
}
// ******************************************************
// From Normal Mapping 2.0 by EVOLVED, heavily modified
// ******************************************************
technique Simple_Light
{
pass p1
{
VertexShader = compile vs_2_0 Light_VS();
PixelShader = compile ps_2_0 Light_PS();
}
}
technique Show_Skybox
{
pass p1
{
VertexShader = compile vs_2_0 Skybox_VS();
PixelShader = compile ps_2_0 Skybox_PS();
}
}
This shader will blur the image. Use this shader on a plane that has the main camera's image on texture stage 0 and the velocity map on texture stage 1. Make sure the velocity map's camera uses a surface format that uses floats so the texture can contain values below 0.
matrix WVP:WorldViewProjection;
float PixelBlurConst = 0.8f;
static const float NumberOfPostProcessSamples = 12.0f;
//-----------------------------------------------------------------------------
// Texture samplers
//-----------------------------------------------------------------------------
texture ScreenTX
<
string ResourceName="";
>;
sampler2D ScreenImg = sampler_state
{
texture = <ScreenTX>;
};
texture VelocityTX
<
string ResourceName="";
>;
sampler2D VelocityMap = sampler_state
{
texture = <VelocityTX>;
};
//-----------------------------------------------------------------------------
// Structs
//-----------------------------------------------------------------------------
struct PP_VS_Output
{
float4 Pos:POSITION;
float2 Tex:TEXCOORD0;
};
//-----------------------------------------------------------------------------
// Vertex shader
//-----------------------------------------------------------------------------
PP_VS_Output MotionBlur_PostProcess_VS( float4 vPos : POSITION, float2 UV : TEXCOORD )
{
PP_VS_Output Output;
Output.Pos=mul(vPos,WVP);
Output.Tex=UV;
return Output;
}
//-----------------------------------------------------------------------------
// Pixel shader
//-----------------------------------------------------------------------------
float4 MotionBlur_PostProcess_PS( PP_VS_Output Input ) : COLOR
{
float2 pixelVelocity;
float4 FramePixelVelocity = tex2D(VelocityMap, Input.Tex);
pixelVelocity.x = FramePixelVelocity.r * PixelBlurConst;
pixelVelocity.y = -FramePixelVelocity.g * PixelBlurConst;
float3 Blurred = 0;
for (float i = 0; i < NumberOfPostProcessSamples / 2; i++)
{
float2 lookupf = pixelVelocity * i / NumberOfPostProcessSamples + Input.Tex;
float2 lookupb = pixelVelocity * i / NumberOfPostProcessSamples - Input.Tex;
float4 Currentf = tex2D(ScreenImg, lookupf);
float4 Currentb = tex2D(ScreenImg, lookupb);
Blurred += Currentf.rgb + Currentb.rgb;
}
return float4(Blurred / NumberOfPostProcessSamples, 1.0f);
}
//-----------------------------------------------------------------------------
// Technique
//-----------------------------------------------------------------------------
technique MotionBlur_PostProcess
{
pass P0
{
VertexShader = compile vs_2_0 MotionBlur_PostProcess_VS();
PixelShader = compile ps_2_0 MotionBlur_PostProcess_PS();
}
}
The velocity map shader can be modified a bit to do object blur, but you'd probably need a separate shader for each object, since each object has a separate world matrix. Unless someone can think of a better way to get dbpro to send another set of world matrices into shaders.
All anti aliasing and no anisotropic filtering makes Jack a dull texture.