Game Development Community

Full Screen Motion Blur

by Viren Thambidorai · in Torque Game Engine Advanced · 09/11/2007 (11:55 pm) · 15 replies

Hi Guys,

Is there anyone who has ever worked on Full Screen Motion Blur effect?
I found few resources which deals with Full screen static blur effect..

http://www.garagegames.com/mg/forums/result.thread.php?qt=21464

but nothing really related with Motion blur, though there is a resource for Motion blur but its related to TGE
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5686

but not for TGEA.

OK, to be precise, anything close to motion blur in San Andreas will also do :)
or smthing close to motion blur in NFS most wanted!

Does anyone has ever worked on it? any sort of help will be appriciable :)

Thanks.

#1
09/16/2007 (2:29 pm)
I would start with this resource

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=13430

in order to get the ability to more easily do full screen effects and then get on nVidia's site, and dig up post radialBlur from their shader library. Or you could just hunt down any information on radial blur and come up with your own original shader.
#2
09/17/2007 (6:15 pm)
Full screen procedural that we can customize would be nice to have as a part of the official build.
#3
09/17/2007 (8:35 pm)
@Vashner

"...contemplate this on the tree of woe." <-- as said by James Earl Jones

Rave:
So now is it mandatory to add kuwahara, edge detection, thermal, invert, blur, radialBlur, boxBlur, horiztonalStreak, VCR, 50 million noise effects, gravity maps for fluids on the screen surface, and after image capabilities to the procedural material generator?

Point:
The nature of full screen effects keeps them from being agnostic, in that they're generally unique to a project. A method of exposure to the screen surface is a must (and that exists), but the procedural shader setup doesn't need to bogged down with dozens of things that many projects will never use.
#4
10/25/2007 (10:20 pm)
HI guys!
I finally got full screen radial motion blur working in TGEA!

i used this resource for TGE,
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5686

converted code from OGL to D3D... some adjustments & it worked for me!

here am posting the code for the same...cheers! :)

#ifndef _MOTIONBLUR_H_
#define _MOTIONBLUR_H_

#ifndef LLIST_H
#include "core/llist.h"
#endif
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#endif
#ifndef _GFXTEXTUREHANDLE_H_
#include "gfx/gfxTextureHandle.h"
#endif
#ifndef _GFX_Texture_Object_H_
#include "gfx/gfxTextureObject.h"
#endif

class MotionBlur
{
protected:
	F32 mElapsedTime;
	F32 mDuration;

public:
	MotionBlur();

	bool isExpired(){ return mElapsedTime >= mDuration; }
	void setDuration( F32 duration ){ mDuration = duration; }

	virtual void advanceTime(F32 dt);
	virtual void preRender(GFXTextureObject* texture, const RectI &updateRect);		// render b4 screen copy
	virtual void render(GFXTextureObject* texture, const RectI &updateRect);			// render after screen copy
};

class FXMotionBlur : public MotionBlur
{
public:
	FXMotionBlur();

	F32 mAlpha;
	F32 mElapsedTimeToFade;
	F32 mFade;

	void setAlpha(F32 alpha){ mAlpha = alpha; }
	void setElapsedTimeToFade(F32 timeToFade){ mElapsedTimeToFade = timeToFade; }
	void setFade(F32 fade){ mFade = fade; }

	virtual void advanceTime(F32 dt);
	virtual void preRender(GFXTextureObject* texture, const RectI &updateRect);
};

class FXManager
{
	typedef MotionBlur* MotionBlurPtr;

	LList< MotionBlurPtr > mFxList;

	GFXTexHandle mTexHandle;
	GFXFormat mFormat;
	
	S32 mLastWidth;

	U32 mLastTimeTick;
	bool mRefreshTexture;

public:
	FXManager();
	~FXManager();

	void addFx(MotionBlur* newMotionBlur);
	void clear();

	GFXTexHandle getTextureHandle(){ return mTexHandle; }

	void advanceTime(F32 dt);
	void render(const RectI &updateRect);
};

extern FXManager* gScreenBlurMgr;

#endif

------------------------------

#include "d3d9.h"
#include "d3dx9core.h"
#include "d3dx9tex.h"

#include "gfx\D3D\gfxD3DDevice.h"

#include "platform/platform.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "core/color.h"
#include "math/mRandom.h"
#include "math/mMatrix.h"
#include "game/fx/MotionBlur.h"
#include "gfx/gfxEnums.h"
#include "core/stl_fix.h"

// global Screen Motion Blur
FXManager* gScreenBlurMgr;

// Clientside function to test motion blur
ConsoleFunction(testMotionBlur, void, 3, 5, "testMotionBlur(alpha, lifetime [, timeToFade, Fade])") {

	F32 alpha = dAtof(argv[1]);
	S32 lifetime = dAtoi(argv[2]);
	F32 timeToFade = lifetime - (lifetime/4);
	F32 Fade = alpha / (lifetime - timeToFade);

	if(argc > 3)
		timeToFade = dAtof(argv[3]);
	if(argc > 4)
		Fade = dAtof(argv[4]);


	FXMotionBlur *newfx = new FXMotionBlur;

	newfx->setDuration(lifetime);
	newfx->setAlpha(alpha);
	newfx->setElapsedTimeToFade(timeToFade);
	newfx->setFade(Fade);

	gScreenBlurMgr->addFx(newfx);
}

MotionBlur::MotionBlur()
{
	mElapsedTime = 0.0;
	mDuration = 8.0;
}

void MotionBlur::advanceTime(F32 dt)
{
	mElapsedTime += dt;
}

void MotionBlur::preRender(GFXTextureObject* texture, const RectI &updateRect){};
void MotionBlur::render(GFXTextureObject* texture, const RectI &updateRect){};

FXMotionBlur::FXMotionBlur()
{
	mAlpha = 0.5;
	mElapsedTimeToFade = mDuration;
	mFade = mAlpha / (mDuration - mElapsedTimeToFade);
}

void FXMotionBlur::advanceTime(F32 dt)
{
	MotionBlur::advanceTime(dt);

	// Fade out alpha?
	if(mElapsedTime >= mElapsedTimeToFade) {
		mAlpha -= mFade * dt;
	}
}

// called b4 we copy screen
void FXMotionBlur::preRender(GFXTextureObject* texture, const RectI &updateRect)
{
	if(mAlpha > 0.001f) 
	{
		GFX->setBitmapModulation(ColorF(1, 1, 1, mAlpha));

		U32 newWidth = updateRect.extent.x * 0.99;
		U32 newHeight = updateRect.extent.y * 0.99;
		U32 deltaX = updateRect.extent.x - newWidth;
		U32 deltaY = updateRect.extent.y - newHeight;

		//center it and zoom
		RectI srcRect(updateRect.point.x + deltaX*0.5 , updateRect.point.y + deltaY*0.5 , newWidth,newHeight );

		// Draw our last frame over current frame
		// NO need to flip the texture 
		GFX->drawBitmapStretchSR(texture, RectI(updateRect.point, updateRect.extent), RectI(updateRect.point, updateRect.extent),GFXBitmapFlip_None);
	}
	else 
	{
		// No alpha left, Kill effect
		mElapsedTime = mDuration;
	}
}

FXManager::FXManager()
{
	mTexHandle = NULL;
	mLastTimeTick = 0;
	mFormat = GFXFormatR8G8B8A8;
}

FXManager::~FXManager()
{
	mTexHandle = NULL;
	clear();
}

// add new fx to currently running list
void FXManager::addFx(MotionBlur* newMotionBlur)
{
	if (mFxList.size() == 0)
	{
		mRefreshTexture = true;
	}
	mFxList.link(newMotionBlur);
}

// Clear all currently running screen effects
void FXManager::clear() 
{
	mFxList.free();
}

// Update screen effects
void FXManager::advanceTime(F32 dt) {

	MotionBlurPtr *cur = NULL;

	while((cur = mFxList.next(cur))) {

		(*cur)->advanceTime(dt);

		if((*cur)->isExpired()) {

			MotionBlurPtr *prev = mFxList.prev(cur);
			mFxList.free(cur);
			cur = prev;
		}
	}
}

// Render effects
void FXManager::render(const RectI &updateRect) 
{

	LPDIRECT3DDEVICE9 D3DDevice = dynamic_cast<GFXD3DDevice *>(GFX)->getDevice();
	IDirect3DSurface9* backBuffer;
	IDirect3DSurface9 *surf;

	if(mTexHandle) 
	{
		// Check if we changed resolution
		if(mLastWidth != updateRect.extent.x) 
		{

			// Update next time
			mTexHandle = NULL;
			mLastWidth = updateRect.extent.x;
			return;
		}

		// Set our texture active
		GFXTextureObject* texture = (GFXTextureObject *) mTexHandle;
		GFX->setTexture(0,texture);
		
		if(mRefreshTexture) 
		{			
 			
 			D3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
			 			
 			GFXD3DTextureObject *texObj = (GFXD3DTextureObject*)texture;
			texObj->get2DTex()->GetSurfaceLevel( 0, &surf );
			D3DDevice->StretchRect( backBuffer, NULL, surf, NULL, D3DTEXF_NONE );

			mRefreshTexture = false;
			return;
		}

		mLastWidth = updateRect.extent.x;

		// Advance effects
		U32 curTime = Platform::getRealMilliseconds();

		advanceTime(((F32)(curTime - mLastTimeTick)) * 0.001f);

		mLastTimeTick = curTime;

		if(mFxList.size() == 0)
			return;

		MotionBlurPtr *cur = NULL;

		// preRender (before we copy screen)
		while((cur = mFxList.next(cur)))
			(*cur)->preRender(texture, updateRect);

 		D3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);

 		GFXD3DTextureObject *texObj = (GFXD3DTextureObject*)texture;
 		texObj->get2DTex()->GetSurfaceLevel( 0, &surf );
 		D3DDevice->StretchRect( backBuffer, NULL, surf, NULL, D3DTEXF_NONE );

		// render (after we copy screen)
		while((cur = mFxList.next(cur)))
			(*cur)->render(texture, updateRect);

	}
	else 
	{
		GBitmap *bitmap = new GBitmap(updateRect.extent.x, updateRect.extent.y, false, mFormat);

		if(bitmap) 
		{
			dMemset(bitmap->pBits, 0x00, bitmap->byteSize);   
			mTexHandle = GFXTexHandle(bitmap, &GFXDefaultRenderTargetProfile, true);
		}
	}
}
------------------------------

Once u r done with these new class ... in ..\game\main.cpp

add our MotionBlur.h into headers!
then in initGame()
add
gScreenBlurMgr = new FXManager();

in shutdownGame() add
delete gScreenBlurMgr;
gScreenBlurMgr = NULL;

once this is done...move into guiTSControl.cpp
inside GuiTSCtrl::onRender() right after line
drlSystem.sgRenderSystem();

add these lines...
if (mUpdateScreenEffects)
    {
 	   gScreenBlurMgr->render(updateRect);
    }

& u r done! :)

cheers!
#5
10/26/2007 (1:57 am)
Excellent work Viren and thanks for sharing! Can't wait to try this later!
#6
10/26/2007 (2:37 am)
Ya i almost forgot to mention one thing...

to see ur motion blur in action...open up console screen...type...
testMotionBlur( 0.8, 50);

where 0.8 is alpha value & 5o is duration for which effect is active in seconds :)

thanks :)
#7
10/26/2007 (3:27 am)
Hmm. I'm having a problem with this. At first it wouldn't even compile, but I added a few lines from the comments in the original resource:
Quote:
Open gui/guiTSControl.h

find: F32 mForceFOV;
add after

bool mUpdateScreenEffects;



Save & close.

Open gui/guiTSControl.cc

find: mForceFOV = 0;
add after

mUpdateScreenEffects = false;



find: addField("forceFOV"
add after

addField("UpdateScreenEffects", TypeBool, Offset(mUpdateScreenEffects, GuiTSCtrl));

I also needed to #include "game/fx/MotionBlur.h" in guiTSControl.cpp.

Now it compiles and I am able to use use the testMotionBlur() function in the console. However, when I do use that function nothing happens!
#8
10/26/2007 (6:07 am)
Duh! I set mUpdateScreenEffects = true in guiTSControl.cc which made it work.

Then I realised that it's actually created a flag in the gui editor (with the addField() function above) which lets me turn it on and off.

Working now - great resource! Thanks!
#9
10/26/2007 (1:08 pm)
What files do you put this code into?
#10
10/28/2007 (7:27 am)
The two large entries from Viren's post are 2 new files: First, game/fx/MotionBlur.h and the second should be game/fx/MotionBlur.cpp.

Then make the smaller changes listed in Viren's post. After that I needed to make a few more chages (see my post above). I also needed to remove the #include "core/stl_fix.h" from MotionBlur.cpp as it is no longer present in TGEA 1.0.3.

After that it all compiled fine and runs a treat! Good luck!
#11
11/09/2007 (10:45 am)
- This is a good starting block for some people...it does need a few tweaks/fixes.
...screen resolution and window resize issues
www.fragstudios.com/gg_images/blurpost.jpg
#12
11/13/2007 (10:42 pm)
Ohhh hell yeahh...
sorry guys tht i literally missed out on those changes as well to mention here :)

thx eikon!
btw, screen res isssues, i have not checked them yet...lemme me have my hand on it once again n c to it tht i can fix it or not :)

srry for miscommunication :)
#13
01/18/2008 (1:55 pm)
It compiles, but when i get into my mission, i can see the skybox and thats it. My player and all objects are invisible. What is the problem? Could someone possibly send me their motionblur.cpp/h and guiTSControl.cpp/h?
#14
01/18/2008 (4:05 pm)
Ok I tryed it on a fresh build and it compiles and loads. Only problem now is that it doest work. I have used all the changes above and I am using TGEA 1.02. Any help?
#15
01/18/2008 (5:18 pm)
Sorry for the triple post but when i put in testMotionBlur( 0.8, 50); in the console, and push F10, the display goes all weird in there but when i get out of the gui editor, it will go back to normal. It seems to be working but it isnt rendered infront of everything else. Ill keep looking.