Sign in to follow this  

Need some help w/ motion blur junk

Recommended Posts

I was going through my big pile o' graphics papers again today, and rediscovered this underappreciated gem. I got to thinking, (and although they don't explicitly mention this usage) it turns out you can use the same trick for the post-processing variant pretty easily. Or so I thought. Seeing as my personal framework is currently down for the count, I did my best to hack together an implementation in the DirectX SDK. It worked, sorta. The quality of the blur is *great* at 16x-level aniso, and it performs slightly faster too (around ~550-600FPS using new method, ~480-500FPS using naive sampling) The downside is that for some unexplained reason, the tex2Dgrad appears to selectively reinterpret the derivatives as (AFAIK) {1.0, -1.0} with no apparent rhyme or reason. I've goofed with the math w/ no useful results, same problem. I remember reading somewhere that if the derivatives grow too high, it screws over the filtering. I distantly suspect this is the problem, though I can't imagine why values in the range [-1...1] would screw it up so. Here's a pitcher. Note the slick blurring. Does anyone have any ideas? EDIT: I just realized how enormously useless this is without code. Here. Have lots.
// 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;
        pixelVelocity.x =  curFramePixelVelocity.r * PixelBlurConst;   
        pixelVelocity.y = -curFramePixelVelocity.g * PixelBlurConst;    

    // META-COMMENT: The old code
    // 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);
    // META-COMMENT: My new stuff.
    float2 finalGrads = abs(pixelVelocity);
    float3 Blurred = tex2Dgrad(RenderTargetSampler, OriginalUV, finalGrads.x, finalGrads.y).xyz;
    return float4(Blurred, 1.0f);

Extra bits:
// 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_3_0 PostProcessMotionBlurPS();

and sampler junk:
sampler RenderTargetSampler = 
    Texture = <RenderTargetTexture>;
    MipFilter = LINEAR;
    MinFilter = ANISOTROPIC;  // was point
    MagFilter = ANISOTROPIC;
    MaxAnisotropy = 16;

    AddressU = Clamp;
    AddressV = Clamp;

[Edited by - InvalidPointer on June 8, 2009 8:27:56 PM]

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this