Motion Blur and previous viewProjection Matrix
-
Crashy
- Google Summer of Code Student

- Posts: 1005
- Joined: Wed Jan 08, 2003 9:15 pm
- Location: Lyon, France
- x 49
- Contact:
Re: Motion Blur and previous viewProjection Matrix
You're welcome 
- lordsme
- Gremlin
- Posts: 167
- Joined: Sun Mar 11, 2007 1:11 pm
- Location: Turin, Italy
- x 10
- Contact:
Re: Motion Blur and previous viewProjection Matrix
Hi razi, I'm going to implement the same effect, would you post some code from your final working version?razi wrote:It works, too bad that I still see a little choppiness every now and then, Ill play with the values. Thank you.
Thank you!
My Portfolio
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
- lordsme
- Gremlin
- Posts: 167
- Joined: Sun Mar 11, 2007 1:11 pm
- Location: Turin, Italy
- x 10
- Contact:
Re: Motion Blur and previous viewProjection Matrix
I found a way to make this MotionBlur compositor work, but I still have the "choppiness problem", I don't know how to properly set the previous view-projection matrix in order to avoid this artifact. Hope someone will help to find a solution. I think the problem relies in my application non-constant frame-rate.
I'd like to contribute posting my compositor and CG shaders code. I had to flip some multiplications with matrices in order to match OGRE standard (the previous posts did not mention about it). I'm using Ogre 1.6.
Here's the compositor:
Here are the materials:
And here are the CG shaders:
Could anyone help with "choppiness problem"?
I'd like to contribute posting my compositor and CG shaders code. I had to flip some multiplications with matrices in order to match OGRE standard (the previous posts did not mention about it). I'm using Ogre 1.6.
Here's the compositor:
Code: Select all
// Motion Blur
// inspired by GPU Gems3. Chapter 27. Motion Blur as a Post-Processing Effect
// and used ideas from OGRE implementation found at:
// http://www.ogre3d.org/forums/viewtopic.php?f=2&t=35980#p432181
compositor EPFC_MotionBlur
{
technique
{
// Depth: try to use a single channel floating point texture to save memory (instead of PF_FLOAT32_RGB or PF_FLOAT32_RGBA)
// (we must use float32 instead of float16 in order to avoid precision artifacts)
texture depth target_width target_height PF_FLOAT32_R
// Scene
texture scene target_width target_height PF_R8G8B8A8
// the scene we want to apply MotionBlur to
target scene
{
input previous
}
target depth
// target_output
{
input none
// use a material scheme to tell each object to render its depth
material_scheme MS_MOTION_BLUR_DEPTH
pass clear
{
}
pass render_scene
{
}
}
target_output
{
input none
pass render_quad
{
material EPF_MotionBlur
input 0 scene
input 1 depth
// ID this pass in order to find it
// in compositor listeners
identifier 999
}
}
}
}
}Code: Select all
fragment_program EPF_MotionBlur_PS cg
{
source MotionBlur.cg
entry_point EPF_MotionBlur_PS
profiles ps_3_0 arbfp1
}
material EPF_MotionBlur
{
technique
{
pass
{
cull_hardware none
cull_software none
depth_func always_pass
fog_override true
vertex_program_ref EPF_StdQuad_VS
{
}
fragment_program_ref EPF_MotionBlur_PS
{
}
texture_unit scene
{
tex_coord_set 0
tex_address_mode clamp
filtering bilinear
}
texture_unit depth
{
tex_coord_set 0
tex_address_mode clamp
filtering bilinear
}
}
}
}
//
// Geometry Depth Shaders
//
vertex_program EPF_MotionBlur_Depth_VS cg
{
source MotionBlur.cg
profiles vs_1_1 arbvp1
entry_point EPF_MotionBlur_Depth_VS
default_params
{
param_named_auto wmat worldviewproj_matrix
}
}
fragment_program EPF_MotionBlur_Depth_PS cg
{
source MotionBlur.cg
entry_point EPF_MotionBlur_Depth_PS
// cannot use ps_1_1 because compiler complains about zero-division
profiles ps_2_0 arbfp1
}
Code: Select all
#define NUM_SAMPLES 8
float4 EPF_MotionBlur_PS(
float2 texCoord: TEXCOORD0,
sampler2D SceneSampler : TEXUNIT0,
sampler2D DepthSampler : TEXUNIT1,
uniform float4x4 EPF_ViewProjectionInverseMatrix,
uniform float4x4 EPF_PreviousViewProjectionMatrix
) : COLOR
{
// First, compute current pixel world-space position
//
// Get the depth buffer value at this pixel
float zOverW = tex2D(DepthSampler, texCoord).r;
// H is the viewport position at this pixel in the range -1 to 1
float4 H = float4(texCoord.x * 2 - 1, (1 - texCoord.y) * 2 - 1, zOverW, 1);
// Transform by the view-projection inverse
// float4 D = mul(H, EPF_ViewProjectionInverseMatrix);
// Use matrix - column vector multiplication (because OGRE works this way and provides xforms this way!)
float4 D = mul(EPF_ViewProjectionInverseMatrix, H);
// Divide by w to get the world position
float4 worldPos = D / D.w;
// Then compute the per-pixel velocity vectors that determine the direction to blur the image
//
// Current viewport position
float4 currentPos = H;
// Use the world position, and transform by the previous view-projection matrix
// float4 previousPos = mul(worldPos, EPF_PreviousViewProjectionMatrix);
// Use matrix - column vector multiplication (because OGRE works this way and provides xforms this way!)
float4 previousPos = mul(EPF_PreviousViewProjectionMatrix, worldPos);
// Convert to nonhomogeneous points [-1,1] by dividing by w.
previousPos /= previousPos.w;
// Use this frame's position and last frame's to compute the pixel velocity
float2 velocity = (currentPos - previousPos)/2.f;
// Then use the velocity vector at the current pixel to sample the color buffer multiple times to achieve the motion blur effect
//
// Get the initial color at this pixel
float4 base = tex2D(SceneSampler, texCoord);
float4 color = base;
texCoord += velocity;
for(int i = 1; i < NUM_SAMPLES; ++i, texCoord += velocity)
{
// Sample the color buffer along the velocity vector
float4 currentColor = tex2D(SceneSampler, texCoord);
// Add the current color to our color sum
color += currentColor;
}
// Average all of the samples to get the final blur color.
float4 finalColor = color / NUM_SAMPLES;
return finalColor;
}
//
// Geometry Depth Shaders
//
void EPF_MotionBlur_Depth_VS
(
uniform float4x4 wmat, // world view projection xf
in float4 pos : POSITION,
out float4 oPos : POSITION,
out float4 oDepth: TEXCOORD0
)
{
oPos = mul(wmat,pos);
oDepth = oPos;
}
float4 EPF_MotionBlur_Depth_PS
(
in float4 depth : TEXCOORD0
): COLOR0
{
float d = depth.z/depth.w;
return float4(d, d, d, 1);
}
Last edited by lordsme on Mon Jan 02, 2012 12:43 pm, edited 1 time in total.
My Portfolio
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
- razi
- Greenskin
- Posts: 130
- Joined: Tue Oct 14, 2008 5:54 pm
- Location: Slovakia
- x 17
Re: Motion Blur and previous viewProjection Matrix
Its been some time since I finished version which I declared as final and integrated to my pipeline, but Ill help with what I can. I remember, after achieving real motion blur effect I had long time playing and analyzing problems with it. One time i seriously had to take break cause my eyes hurt from all the motion blurs
.
For the obvious question how to smooth projections, I use this code in my application to get them, pVP and iVP are then sent to shader:
One problem which was obvious for me was, that although blurring seemed working, when the camera was spinning very fast (doing 360 in fps camera) and suddenly stopped the screen jumped (there was obvious change of objects from being moved by blurring to zero blurring). Im not sure if it helped much, but I changed coordinates translation from simply moving to one side to move it to both sides (so I take half samples with +velocity and half samples with -velocity).
Another problem, which I actually felt the whole time but never could actually explain was, that I eventually found out that x coordinate of velocity was opposite to what I wanted (*-1). (I found it out once again by doing 360 in fps camera while looking at my feet, the ground was not blurred in circle with center below me as expected, but rather in circles around me, you could say star shape blur under my feet) Was it bad projections or something else, I dont know. This might have helped the first problem too, dont remember.
For the obvious question how to smooth projections, I use this code in my application to get them, pVP and iVP are then sent to shader:
Code: Select all
float interpolationFactor = mPreviousFPS*0.03f; //blur size constant
Ogre::Quaternion estimatedOrientation = Ogre::Quaternion::Slerp(interpolationFactor,camnode->_getDerivedOrientation(),prevOr);
Ogre::Vector3 estimatedPosition = (1-interpolationFactor)*camnode->_getDerivedPosition()+interpolationFactor*prevPos;
Ogre::Matrix4 viewMatrix =Ogre::Math::makeViewMatrix(estimatedPosition,estimatedOrientation);
Ogre::Matrix4 projectionMatrix = mCamera->getProjectionMatrix();
*pVP = projectionMatrix*viewMatrix;
*iVP=(projectionMatrix*mCamera->getViewMatrix()).inverse();
//for next frame
mPreviousFPS=1/timeSinceLastFrame;
prevPos=camnode->_getDerivedPosition();
prevOr=camnode->_getDerivedOrientation();
Another problem, which I actually felt the whole time but never could actually explain was, that I eventually found out that x coordinate of velocity was opposite to what I wanted (*-1). (I found it out once again by doing 360 in fps camera while looking at my feet, the ground was not blurred in circle with center below me as expected, but rather in circles around me, you could say star shape blur under my feet) Was it bad projections or something else, I dont know. This might have helped the first problem too, dont remember.
- lordsme
- Gremlin
- Posts: 167
- Joined: Sun Mar 11, 2007 1:11 pm
- Location: Turin, Italy
- x 10
- Contact:
Re: Motion Blur and previous viewProjection Matrix
Thank you very much razi,
I still have some choppiness problem but it's my fault, I have some problem with my view matrix that changes very quickly because of my navigation engine.
By the way, here I post the code from my framework that updates the shader uniform parameters from my previous post.
There are some calls from my framework API, but I think that it's readable anyway.
Everything is very close to razi's solution, I just added a time multiplier to gain more control on MotionBlur.
I still have some choppiness problem but it's my fault, I have some problem with my view matrix that changes very quickly because of my navigation engine.
By the way, here I post the code from my framework that updates the shader uniform parameters from my previous post.
There are some calls from my framework API, but I think that it's readable anyway.
Everything is very close to razi's solution, I just added a time multiplier to gain more control on MotionBlur.
Code: Select all
void updateMotionBlur()
{
// get Ogre camera
Ogre::Camera* mCamera = m_pViewer->getActiveCamera()->_getOgreCamera();
// get current time (seconds)
float current_time = m_pViewer->getSimulationTime();
// compute view projection inverse matrix
Ogre::Matrix4 projectionMatrix = mCamera->getProjectionMatrix();
Ogre::Matrix4 iVP = (projectionMatrix * mCamera->getViewMatrix()).inverse();
float interpolationFactor = m_lastFPS * 0.03f * m_timeScale; // m_timeScale is a multiplier to control motion blur interactively
Ogre::Quaternion current_orientation = mCamera->getDerivedOrientation();
Ogre::Vector3 current_position = mCamera->getDerivedPosition();
Ogre::Quaternion estimatedOrientation = Ogre::Quaternion::Slerp(interpolationFactor, current_orientation, (*m_pPreviousOrientation));
Ogre::Vector3 estimatedPosition = (1-interpolationFactor) * current_position + interpolationFactor * (*m_pPreviousPosition);
Ogre::Matrix4 prev_viewMatrix = Ogre::Math::makeViewMatrix(estimatedPosition, estimatedOrientation);
// compute final matrix
*m_pPreviousViewProjectionMatrix = projectionMatrix * prev_viewMatrix;
// update position and orientation for next update time
*m_pPreviousOrientation = current_orientation;
*m_pPreviousPosition = current_position;
m_lastFPS = 1.0f /(current_time - m_lastTime);
m_lastTime = current_time;
// update shader
Ogre::GpuProgramParametersSharedPtr fp_params = m_pListener->getBlendMaterial()->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
// update view projection inverse matrix
fp_params->setNamedConstant("EPF_ViewProjectionInverseMatrix", iVP);
// update previous view projection matrix
fp_params->setNamedConstant("EPF_PreviousViewProjectionMatrix", *m_pPreviousViewProjectionMatrix);
}
My Portfolio
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
- lordsme
- Gremlin
- Posts: 167
- Joined: Sun Mar 11, 2007 1:11 pm
- Location: Turin, Italy
- x 10
- Contact:
Re: Motion Blur and previous viewProjection Matrix
I posted a demo of this MotionBlur implementation here:
http://www.ogre3d.org/forums/viewtopic.php?f=11&t=68303
Enjoy
http://www.ogre3d.org/forums/viewtopic.php?f=11&t=68303
Enjoy
My Portfolio
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
http://davidedigiannantonio.weebly.com
MESH - Mise-en-scene Helper
http://www.mesh-project.org/
ASALab @ Virtual Reality & Multimedia Park
http://www.vrmmp.it
- TheGameMaker
- Kobold
- Posts: 26
- Joined: Fri Jun 18, 2010 4:19 pm
Re: Motion Blur and previous viewProjection Matrix
Hello. I seem to be bringing up a slightly old thread but I wanted to test this with the latest OGRE (1.8.1 right now)
I have implemented the above code but I am having a problem with one aspect of this motion blur - getting the ViewProjectionInverseMatrix and the PreviousViewProjectionMatrix. I used the code above but changed one line:
This
to this
That just seemed to work better for me. My code now looks like this:
Now the motion blur seems to work but as I move the camera further away from the center of the scene, it starts to shake and get unstable.
So does anyone know why this happens? Can it be fixed or is it some kind of limitation of floats or something?
I have implemented the above code but I am having a problem with one aspect of this motion blur - getting the ViewProjectionInverseMatrix and the PreviousViewProjectionMatrix. I used the code above but changed one line:
This
Code: Select all
m_lastFPS = 1.0f /(current_time - m_lastTime);Code: Select all
m_lastFPS = mWindow->getStatistics().lastFPS;Code: Select all
// compute view projection inverse matrix
Ogre::Matrix4 projectionMatrix = mCamera->getProjectionMatrix();
Ogre::Matrix4 iVP = (projectionMatrix * mCamera->getViewMatrix()).inverse();
float interpolationFactor = m_lastFPS * 0.03f * motionBlurTimeScale; // m_timeScale is a multiplier to control motion blur interactively
Ogre::Quaternion current_orientation = mCamera->getDerivedOrientation();
Ogre::Vector3 current_position = mCamera->getDerivedPosition();
Ogre::Quaternion estimatedOrientation = Ogre::Quaternion::Slerp(interpolationFactor, current_orientation, m_pPreviousOrientation);
Ogre::Vector3 estimatedPosition = (1-interpolationFactor) * current_position + interpolationFactor * m_pPreviousPosition;
Ogre::Matrix4 prev_viewMatrix = Ogre::Math::makeViewMatrix(estimatedPosition, estimatedOrientation);
// compute final matrix
m_pPreviousViewProjectionMatrix = projectionMatrix * prev_viewMatrix;
// update position and orientation for next update time
m_pPreviousOrientation = current_orientation;
m_pPreviousPosition = current_position;
m_lastFPS = mWindow->getStatistics().lastFPS;
m_lastTime = current_time;
// update shader
Ogre::GpuProgramParametersSharedPtr fp_params = mBlurListener->getBlendMaterial()->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
// update view projection inverse matrix
fp_params->setNamedConstant("hardcoded_ViewProjectionInverseMatrix", iVP);
// update previous view projection matrix
fp_params->setNamedConstant("hardcoded_PreviousViewProjectionMatrix", m_pPreviousViewProjectionMatrix);So does anyone know why this happens? Can it be fixed or is it some kind of limitation of floats or something?
