motion blur shader

Posted By: VeT

motion blur shader - 06/04/08 09:33

Code:
//-----------------------------------------------------------------------------
// File: PixelMotionBlur.fx
//
// Desc: Effect file for image based motion blur. The HLSL shaders are used to
//       calculate the velocity of each pixel based on the last frame's matrix 
//       transforms.  This per-pixel velocity is then used in a blur filter to 
//       create the motion blur effect.
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
float4 MaterialAmbientColor;
float4 MaterialDiffuseColor;

float3 LightDir = normalize(float3(1.0f, 1.0f, 1.0f));
float4 LightAmbient = { 1.0f, 1.0f, 1.0f, 1.0f };    // ambient
float4 LightDiffuse = { 1.0f, 1.0f, 1.0f, 1.0f };    // diffuse

texture RenderTargetTexture;
texture MeshTexture;
texture CurFrameVelocityTexture;
texture LastFrameVelocityTexture;

float4x4 mWorld;
float4x4 mWorldViewProjection;
float4x4 mWorldViewProjectionLast;

float PixelBlurConst = 1.0f;
static const float NumberOfPostProcessSamples = 12.0f;
float ConvertToNonHomogeneous;
float VelocityCapSq = 1.0f;
float RenderTargetWidth;
float RenderTargetHeight;


//-----------------------------------------------------------------------------
// Texture samplers
//-----------------------------------------------------------------------------
sampler RenderTargetSampler = 
sampler_state
{
    Texture = <RenderTargetTexture>;
    MinFilter = POINT;  
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler CurFramePixelVelSampler = 
sampler_state
{
    Texture = <CurFrameVelocityTexture>;
    MinFilter = POINT;
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler LastFramePixelVelSampler = 
sampler_state
{
    Texture = <LastFrameVelocityTexture>;
    MinFilter = POINT;
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler MeshTextureSampler = 
sampler_state
{
    Texture = <MeshTexture>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};


//-----------------------------------------------------------------------------
// Vertex shader output structure
//-----------------------------------------------------------------------------
struct VS_OUTPUT
{
    float4 Position : POSITION;   // position of the vertex
    float4 Diffuse  : COLOR0;     // diffuse color of the vertex
    float2 TextureUV : TEXCOORD0;  // typical texture coords stored here
    float2 VelocityUV : TEXCOORD1;  // per-vertex velocity stored here
};


//-----------------------------------------------------------------------------
// Name: WorldVertexShader     
// Type: Vertex shader                                      
// Desc: In addition to standard transform and lighting, it calculates the velocity 
//       of the vertex and outputs this as a texture coord.
//-----------------------------------------------------------------------------
VS_OUTPUT WorldVertexShader( float4 vPos : POSITION, 
                             float3 vNormal : NORMAL,
                             float2 vTexCoord0 : TEXCOORD0 )
{
    VS_OUTPUT Output;
    float3 vNormalWorldSpace;
    float4 vPosProjSpaceCurrent; 
    float4 vPosProjSpaceLast; 
  
    vNormalWorldSpace = normalize(mul(vNormal, (float3x3)mWorld)); // normal (world space)
    
    // Transform from object space to homogeneous projection space
    vPosProjSpaceCurrent = mul(vPos, mWorldViewProjection);
    vPosProjSpaceLast = mul(vPos, mWorldViewProjectionLast);
    
    // Output the vetrex position in projection space
    Output.Position = vPosProjSpaceCurrent;

    // Convert to non-homogeneous points [-1,1] by dividing by w 
    vPosProjSpaceCurrent /= vPosProjSpaceCurrent.w;
    vPosProjSpaceLast /= vPosProjSpaceLast.w;
    
    // Vertex's velocity (in non-homogeneous projection space) is the position this frame minus 
    // its position last frame.  This information is stored in a texture coord.  The pixel shader 
    // will read the texture coordinate with a sampler and use it to output each pixel's velocity.
    float2 velocity = vPosProjSpaceCurrent - vPosProjSpaceLast;    
    
    // The velocity is now between (-2,2) so divide by 2 to get it to (-1,1)
    velocity /= 2.0f;   

    // Store the velocity in a texture coord
    Output.VelocityUV = velocity;
        
    // Compute simple lighting equation
    Output.Diffuse.rgb = MaterialDiffuseColor * LightDiffuse * max(0,dot(vNormalWorldSpace, LightDir)) + 
                         MaterialAmbientColor * LightAmbient;   
    Output.Diffuse.a = 1.0f; 
    
    // Just copy the texture coordinate through
    Output.TextureUV = vTexCoord0; 
    
    return Output;    
}


//-----------------------------------------------------------------------------
// Pixel shader output structure
//-----------------------------------------------------------------------------
struct PS_OUTPUT
{
    // The pixel shader can output 2+ values simulatanously if 
    // d3dcaps.NumSimultaneousRTs > 1
    
    float4 RGBColor      : COLOR0;  // Pixel color    
    float4 PixelVelocity : COLOR1;  // Pixel velocity 
};


//-----------------------------------------------------------------------------
// Name: WorldPixelShader                                        
// Type: Pixel shader
// Desc: Uses multiple render targets (MRT) to output 2 values at once from a 
//       pixel shader.  This shader outputs the pixel's color and velocity.
//-----------------------------------------------------------------------------
PS_OUTPUT WorldPixelShader( VS_OUTPUT In )
{ 
    PS_OUTPUT Output;

    // Lookup mesh texture and modulate it with diffuse
    Output.RGBColor = tex2D(MeshTextureSampler, In.TextureUV) * In.Diffuse;

    // Velocity of this pixel simply equals the linear interpolation of the 
    // velocity of this triangle's vertices.  The interpolation is done
    // automatically since the velocity is stored in a texture coord.
    // We're storing the velocity in .R & .G channels and the app creates 
    // a D3DFMT_G16R16F texture to store this info in high precison.
    Output.PixelVelocity = float4(In.VelocityUV,1.0f,1.0f);
    
    // Using MRT, output 2 values in the pixel shader.    
    return Output;
}


float4 WorldPixelShaderColor( float4 Diffuse : COLOR0,
                              float2 TextureUV : TEXCOORD0 ) : COLOR0
{ 
    // Lookup mesh texture and modulate it with diffuse
    return tex2D( MeshTextureSampler, TextureUV ) * Diffuse;
}


float4 WorldPixelShaderVelocity( float2 VelocityUV : TEXCOORD1 ) : COLOR0
{ 
    // Velocity of this pixel simply equals the linear interpolation of the 
    // velocity of this triangle's vertices.  The interpolation is done
    // automatically since the velocity is stored in a texture coord.
    // We're storing the velocity in .R & .G channels and the app creates 
    // a D3DFMT_G16R16F texture to store this info in high precison.
    return float4( VelocityUV, 1.0f, 1.0f );
}


//-----------------------------------------------------------------------------
// Name: PostProcessMotionBlurPS 
// Type: Pixel shader                                      
// Desc: Uses the pixel's velocity to sum up and average pixel in that direction
//       to create a blur effect based on the velocity in a fullscreen
//       post process pass.
//-----------------------------------------------------------------------------
float4 PostProcessMotionBlurPS( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
    float2 pixelVelocity;
    
    // Get this pixel's current velocity and this pixel's last frame velocity
    // The velocity is stored in .r & .g channels
    float4 curFramePixelVelocity = tex2D(CurFramePixelVelSampler, OriginalUV);
    float4 lastFramePixelVelocity = tex2D(LastFramePixelVelSampler, OriginalUV);

    // If this pixel's current velocity is zero, then use its last frame velocity
    // otherwise use its current velocity.  We don't want to add them because then 
    // you would get double the current velocity in the center.  
    // If you just use the current velocity, then it won't blur where the object 
    // was last frame because the current velocity at that point would be 0.  Instead 
    // you could do a filter to find if any neighbors are non-zero, but that requires a lot 
    // of texture lookups which are limited and also may not work if the object moved too 
    // far, but could be done multi-pass.
    float curVelocitySqMag = curFramePixelVelocity.r * curFramePixelVelocity.r +
                             curFramePixelVelocity.g * curFramePixelVelocity.g;
    float lastVelocitySqMag = lastFramePixelVelocity.r * lastFramePixelVelocity.r +
                              lastFramePixelVelocity.g * lastFramePixelVelocity.g;
                                   
    if( lastVelocitySqMag > curVelocitySqMag )
    {
        pixelVelocity.x =  lastFramePixelVelocity.r * PixelBlurConst;   
        pixelVelocity.y = -lastFramePixelVelocity.g * PixelBlurConst;
    }
    else
    {
        pixelVelocity.x =  curFramePixelVelocity.r * PixelBlurConst;   
        pixelVelocity.y = -curFramePixelVelocity.g * PixelBlurConst;    
    }
    
    // For each sample, sum up each sample's color in "Blurred" and then divide
    // to average the color after all the samples are added.
    float3 Blurred = 0;    
    for(float i = 0; i < NumberOfPostProcessSamples; i++)
    {   
        // Sample texture in a new spot based on pixelVelocity vector 
        // and average it with the other samples        
        float2 lookup = pixelVelocity * i / NumberOfPostProcessSamples + OriginalUV;
        
        // Lookup the color at this new spot
        float4 Current = tex2D(RenderTargetSampler, lookup);
        
        // Add it with the other samples
        Blurred += Current.rgb;
    }
    
    // Return the average color of all the samples
    return float4(Blurred / NumberOfPostProcessSamples, 1.0f);
}


//-----------------------------------------------------------------------------
// Name: WorldWithVelocityMRT
// Type: Technique                                     
// Desc: Renders the scene's color to render target 0 and simultaneously writes 
//       pixel velocity to render target 1.
//-----------------------------------------------------------------------------
technique WorldWithVelocityMRT
{
    pass P0
    {          
        VertexShader = compile vs_2_0 WorldVertexShader();
        PixelShader  = compile ps_2_0 WorldPixelShader();
    }
}


technique WorldWithVelocityTwoPasses
{
    pass P0
    {
        VertexShader = compile vs_2_0 WorldVertexShader();
        PixelShader  = compile ps_2_0 WorldPixelShaderColor();
    }
    pass P1
    {
        VertexShader = compile vs_2_0 WorldVertexShader();
        PixelShader  = compile ps_2_0 WorldPixelShaderVelocity();
    }
}


//-----------------------------------------------------------------------------
// Name: PostProcessMotionBlur
// Type: Technique                                     
// Desc: Renders a full screen quad and uses velocity information stored in 
//       the textures to blur image.
//-----------------------------------------------------------------------------
technique PostProcessMotionBlur
{
    pass P0
    {        
        PixelShader = compile ps_2_0 PostProcessMotionBlurPS();
    }
}




how make it works for Lite-c?
Posted By: zSteam

Re: motion blur shader - 06/11/08 16:16

First of all thanks for the code. I try to use it with lite c.
Posted By: Core

Re: motion blur shader - 06/13/08 11:43

This is not working for me, I just become a black screen and when I change the Render Taget Map in Target map it works but just in the upper site of the screen.
Posted By: VeT

Re: motion blur shader - 06/16/08 07:46

so, where are The Great Fathers Of The Shadering In Gamestudio? laugh
Posted By: Joey

Re: motion blur shader - 06/16/08 09:35

there are two techniques, one for the rendering of a screen space velocity map and a postprocess technique for blurring a world render target accordingly. you have to split it into two effect files and set up a render chain.

edit: this effect will only work for view movement, not for entity movement.
Posted By: Nowherebrain

Re: motion blur shader - 06/16/08 10:55

render your target map using proc_late...or something like that, and set it to be semi transparent....just a thought, I'm no shader guru
Posted By: not_me

Re: motion blur shader - 06/24/08 04:53

will this work with 3dgs comm a6 with r2t plugin?
Posted By: lostclimate

Re: motion blur shader - 06/25/08 17:27

i dont see why it wouldnt
Posted By: Slin

Re: motion blur shader - 06/25/08 18:02

Does anyone know of a really good looking, fast and as much as possible fps independant way for motion blur?
I would like to hear some ideas and/or links to some papers about it (I havenīt looked for something yet).
I gave switching some bmap pointers a try and blending the camera images of 5 frames with some weighting a try. My idea was to make the weighting and the distance between each bitmap frames which are used dependant of the fps. But I guess that the quality wouldnīt be very convincing and that it is impossible in this way to make the blur to seem fps independant.

What could be done and that is what the code posted above seem to do is that it first renders a texture with the movementspeed and direction of each pixel and then to blur the original image via postprocessing depending on the texture containing the movement information. What I donīt understand about the posted code is, why it takes the "speedmap" of two frames and not only of the current frame.
Okay no, I understand it but I think that there should be a better way to do it like applying the blur several times to the "speedmap" before using it. Otherwise it should get very fps dependant as well.

I would just like to hear some ideas about it smile
Posted By: xXxGuitar511

Re: motion blur shader - 06/26/08 03:36

The "cheapest" way to do motionblur is to simply blur the image of the screen (based on a focal point).

I used this method for a racing game not too long ago, it worked perfectly. I guess it depends on your situation...
© 2024 lite-C Forums