I'm trying to create a real motion blur pixel shader effect in glsl, following the GPU gems III book (chapter 27) as a post process effect using depth buffer.
However, I can't get what I would like to.
I first draw into an RTT the mesh depth map with a black/white gradient.
Then I draw the standart scene (no shader) into another RTT.
Then with the motion blur shader I calculate each pixel position, and velocity.
With the same shader, I blur the scene with directionnal bluring.
The depth RTT is OK, but the final result is bad, here is the result :
thumbnails : standart and depth RTTs:
I don't know where is the problem
Here is the code I created to [try to] make this effect:
depth_vs.vert:
Code: Select all
uniform mat4 mWorldViewProj;
uniform float MaxD;
void main() {
vec4 tPos = ftransform();
gl_Position = tPos;
gl_TexCoord[0] = vec4(MaxD, tPos.y, tPos.z, tPos.w);
gl_TexCoord[1].xy = gl_MultiTexCoord0.xy;
}
Code: Select all
void main() {
vec4 vInfo = gl_TexCoord[0];
float depth = vInfo.z / vInfo.x;
gl_FragColor = vec4(depth, depth, depth, 0.0);
}
Code: Select all
varying vec2 vTexCoord;
void main() {
vTexCoord = gl_MultiTexCoord0.xy;
gl_Position = ftransform();
}
Code: Select all
uniform sampler2D depthTexture;
uniform sampler2D sceneTexture;
uniform mat4 mPreviousWorldViewProj;
uniform mat4 mWorldViewProjInversed;
varying vec2 vTexCoord;
void main() {
//calculate pixel position
float zOverW=texture2D(depthTexture, vTexCoord);
vec4 H=float4(vTexCoord.x*2-1,(1-vTexCoord.y)*2-1, zOverW,1);
vec4 D=H*mWorldViewProjInversed;
vec4 worldPos=D/D.w;
//calculate pixel velocity
vec4 currentPos=H;
vec4 previousPos=worldPos*mPreviousWorldViewProj;
previousPos/=previousPos.w;
vec2 velocity=(currentPos-previousPos)/2.f;
float n=sqrt(pow(velocity.x,2)+pow(velocity.y,2));
//gl_FragColor=vec4(H,H,H,H);
//performing motion blur
vec4 color=texture2D(sceneTexture, vTexCoord);
vTexCoord.xy+=velocity;
for(int i=1; i<4; ++i, vTexCoord.xy+=velocity) {
vec4 currentColor=texture2D(sceneTexture, vTexCoord);
color+=currentColor;
}
vec4 finalColor=color/4.f;
//update the data
gl_FragColor = texture2D(depthTexture,vTexCoord);
}
(you will need a mesh.3df and tex.png to run this exemple...)
main.cpp:
Code: Select all
/*
Name: Real motion blur pixel shader
Author: Stefbuet
Date: 12/03/10
*/
#include <cstdlib>
#include <iostream>
#include <IRR/irrlicht.h>
using namespace irr;
using namespace scene;
using namespace video;
IrrlichtDevice *device;
IVideoDriver *driver;
ISceneManager *smgr;
IGPUProgrammingServices *gpu;
s32 depthShader;
s32 motionBlurShader;
IMeshSceneNode *node;
ICameraSceneNode *cam;
core::matrix4 worldViewProj, lastWorldViewProj, worldViewProjInv;
f32 FarLink;
ITexture *depthBufferRTT, *sceneRTT;
class depthShaderCB : public IShaderConstantSetCallBack {
public:
virtual void OnSetConstants(IMaterialRendererServices *services, s32 userData) {
services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
FarLink=500.0;
services->setVertexShaderConstant("MaxD", &FarLink, 1);
}
};
class motionBlurShaderCB : public IShaderConstantSetCallBack {
public:
virtual void OnSetConstants(IMaterialRendererServices *services, s32 userData) {
FarLink=500.0;
services->setVertexShaderConstant("MaxD", &FarLink, 1);
services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
worldViewProjInv=worldViewProj;
worldViewProjInv.makeInverse();
services->setPixelShaderConstant("mWorldViewProjInversed", worldViewProjInv.pointer(), 16);
services->setPixelShaderConstant("mPreviousWorldViewProj", lastWorldViewProj.pointer(), 16);
int depthAddress=1, sceneAddress=2;
services->setPixelShaderConstant("depthTexture", (float*)(&depthAddress),1);
services->setPixelShaderConstant("sceneTexture", (float*)(&sceneAddress),1);
}
};
void updateMatrix() {
//update the world matrix projection view for depth shader pass:
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
}
depthShaderCB *depthCB;
motionBlurShaderCB *motionBlurCB;
int main(int argc, char *argv[]) {
IrrlichtDevice *device =createDevice( video::EDT_OPENGL, core::dimension2d<u32>(512,512), 16,false, false, false, 0);
driver = device->getVideoDriver();
smgr = device->getSceneManager();
gpu=driver->getGPUProgrammingServices();
cam=smgr->addCameraSceneNodeFPS();
cam->setPosition(core::vector3df(400,200,400));
node=smgr->addMeshSceneNode(smgr->getMesh("mesh.3ds"));
node->setMaterialFlag(EMF_LIGHTING, false);
node->setMaterialTexture(0, driver->getTexture("tex.png"));
depthBufferRTT=driver->addRenderTargetTexture(core::dimension2d<u32>(512,512),"test", ECF_A8R8G8B8);
sceneRTT=driver->addRenderTargetTexture(core::dimension2d<u32>(512,512),"test2", ECF_A8R8G8B8);
depthCB=new depthShaderCB();
depthShader=gpu->addHighLevelShaderMaterialFromFiles("depth_vs.vert", "vertexMain", EVST_VS_1_1,"depth_ps.frag", "pixelMain", EPST_PS_1_1,depthCB, EMT_SOLID);
motionBlurCB=new motionBlurShaderCB();
motionBlurShader=gpu->addHighLevelShaderMaterialFromFiles("motionBlur_vs.vert", "vertexMain", EVST_VS_1_1,"motionBlur_ps.frag", "pixelMain", EPST_PS_1_1,depthCB, EMT_SOLID);
while(device->run()) {
driver->beginScene(true, true, SColor(0xff999999));
//update the world matrix projection view for depth shader pass and keep the old one to process motion blur:
lastWorldViewProj=worldViewProj;
updateMatrix();
//render a depth texture from the object:
driver->setRenderTarget(depthBufferRTT, true, true, SColor(0xffffffff));
node->setMaterialType((E_MATERIAL_TYPE)depthShader);
smgr->drawAll();
driver->setRenderTarget(0, false, false);
//render the normal scene to an RTT texture to get its pixels in motion blur shader:
node->setMaterialType(EMT_SOLID);
//node->setMaterialTexture(0, driver->getTexture("tex.png"));
driver->setRenderTarget(sceneRTT, true, true, SColor(0xffffffff));
smgr->drawAll();
driver->setRenderTarget(0, false, false, SColor(0xffffffff));
//render the object with motion blur:
node->setMaterialTexture(1, depthBufferRTT);
node->setMaterialTexture(2, sceneRTT);
node->setMaterialType((E_MATERIAL_TYPE)motionBlurShader);
smgr->drawAll();
driver->draw2DImage(sceneRTT, core::rect<s32>(0,0,128,128), core::rect<s32>(0,0,512,512));
driver->draw2DImage(depthBufferRTT, core::rect<s32>(128+1,0,128+128+1,128), core::rect<s32>(0,0,512,512));
driver->endScene();
}
return EXIT_SUCCESS;
}
Stef.