Game Development Community

dev|Pro Game Development Curriculum

TSE Simple Full Screen Shader Effect

by decryptoid · 11/15/2005 (2:49 pm) · 61 comments

Download Code File

Remember to back up your files before using this example code!

Files... You may also download the files here:
Code Files

Download the code file and unzip the files as follows:


-- Unzip fullscreenEffects.cs into example/[yourmod directory]/client/scripts/
where [yourmod directory] is the name of your mod directory

-- Unzip all four .hlsl files to the /example/shaders/

-- Unzip both gameTSCtrl files to /engine/game/

Now Compile!...

Script Changes...

-- Open example/[yourmod directory]/client/init.cs and add the following code right after the IdleTimeout line...
// full screen effects
   exec("./scripts/fullscreenEffects.cs");
It is important that you place it immediately after the IdleTimeout line because the fullscreenEffects file must be loaded before the PlayGui is loaded or it will not work.

-- Open example/[yourmod directory]/client/scripts/default.bind.cs and add the following code to the end:
//---------------------------------------
//  fullscreen shader effects
//---------------------------------------
moveMap.bind(keyboard, "v", toggleEffectMode);

function toggleEffectMode(%val)
{

	if(%val)
	{

		PlayGui.toggleEffectMode(0);

	}
}

Now Delete all your dso files... if you don't know how to do this just do a search on your mod directory for "*.dso" and delete all the files.

Run the game... you should be done!
Pressing "v" on the keyboard should toggle between heatvision, nightvision and regular vision.

About the shaders...
The shaders (hlsl files) are very simple. You can open them up in a text editor and see how they work. All they really do is convert the image to black and white then invert for heatvision and add all color channels to green for nightvision.

About the engine changes
Look at the new gameRenderEffect function in gameTSCtrl.cpp file for most of the changes. It's basically a copy of the regular GameRender function, but it renders to a surface then back to the screen with the shader.

What else you can do...
-- Add Bitmap "static" to the shaders
-- Write a cool custom screen shader!!
-- Look at the other shaders in the shaders directory to see how they work
-- Look in other parts of the engine code to see how to pass additional values to a custom shader. All the glowbuffer stuff is good for this
-- Modify this example code to be more dynamic. The two shaders are kinda hardcoded in there and it would be better to pass shader names in a script... that way you wouldn't have to re-compile for every shader change

NOTE: Since every one was waiting I made this example fairly quick. There may be unused variables or errors I didn't catch. Hopefully I included all the right files!

Problems:
-- The game will crash if the two shaders do not get loaded. This will happen if you put the exec line for the fullscreenEffect.cs file in the wrong place.

About the author

Recent Blogs

#41
05/21/2007 (10:44 am)
Can someone share this resource for TGEA Please?
#43
10/07/2007 (6:57 am)
hey hi, what if i want only particular area of the screen to have same effect ... say only lower half of the screen ??

Kindly help :)
#44
06/09/2008 (1:47 pm)
I have gotten this to work with TGEA 1.7, here are the code changes. You will need to implement the orginal, just need to be aware of my changes to get it to work. There maybe header includes of the standard stuff, but I figure you can find them out easily.

Edit: Bolding does not show up, so added comments instead

// TGEA 1.7 MOD - Begin
// TGEA 1.7 MOD - End



//---------------------------------------
//  fullscreen shader effects
//---------------------------------------
   ShaderData			* mNightEffectShader;
   ShaderData			* mHeatEffectShader;
   Point2F				offsetConsts[4];
   Point4F				offsets;
   ColorF				mFilterColor;
   GFXTexHandle			mSurface[3];
// TGEA 1.7 MOD - Begin
   GFXTextureTargetRef                     mRenderTarget;
// TGEA 1.7 MOD - End
   GFXTexHandle			mBitmapObject;
   StringTableEntry		mBitmapName;
//---------------------------------------



In the GameTSCtrl.cpp

Do NOT add the following code as it will not work.

//GFXVideoMode mode = GFX->getVideoMode();
   //mSurface[0].set( mode.resolution.x, mode.resolution.y, GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, 1 );


Here is my replacement renderWorldEffect, I have BOLDED the lines I added

void GameTSCtrl::renderWorldEffect(const RectI &updateRect, ShaderData *mEffectShader, U32 objMask, GFXFillMode fMode)
{

   FrameAllocator::setWaterMark(0);
 
// TGEA 1.7 MOD - Begin
   if (mRenderTarget == NULL)
	 mRenderTarget = GFX->allocRenderToTextureTarget();

   Point2I cursize = gClientSceneGraph->getDisplayTargetResolution();
   for (int i =0; i < 3; i++)
   {
      if (mSurface[i].isNull())
	 mSurface[i] = GFX->getTextureManager()->createTexture(cursize.x, cursize.y, GFXFormatR8G8B8X8, &GFXDefaultRenderTargetProfile);
   }
// TGEA 1.7 MOD - End
 
   // rectangle points for calcs later
   Point2I a = updateRect.point;
   Point2I b = updateRect.point + updateRect.extent;
 
   GFX->setZEnable( true ); //glEnable(GL_DEPTH_TEST);
   GFX->setZFunc( GFXCmpLessEqual ); //glDepthFunc(GL_LEQUAL);
 
   // Update the dynamic cubemaps on reflective objects
   SimSet *reflectSet = dynamic_cast<SimSet*>( Sim::findObject( "reflectiveSet" ) );
 
   for( SimSetIterator itr(reflectSet); *itr; ++itr )
   {
      if( *itr )
      {
         SceneObject *obj = (SceneObject*) *itr;
         obj->updateReflection();
      }
   }
 

   // Need to consoldate to one clear call // glClear(GL_DEPTH_BUFFER_BIT);
   GFX->setCullMode( GFXCullNone );//glDisable(GL_CULL_FACE);
 
   //************************************
   //************************************
   //************************************
   GFX->setFillMode(fMode);
 
// TGEA 1.7 MOD - Begin
   GFX->pushActiveRenderTarget();

	// Set a starting texture so we can bind w/o any nulls.
   mRenderTarget->attachTexture(GFXTextureTarget::Color0, mSurface[0]);
 
   GFX->setActiveRenderTarget(mRenderTarget);
// TGEA 1.7 MOD - End
 
   // if it's wireframe we have to clear every frame
   if (fMode == GFXFillWireframe)
   {
        GFX->clear( GFXClearTarget, ColorI(0.5,0.5,0.5,0.5), 1.0f, 0 );
   }
 

   // assign the render mask if one came in
   if (objMask)
   {
        gClientSceneGraph->renderScene(  objMask  );
   } else {
        gClientSceneGraph->renderScene( );
   }
 

    GFX->setFillMode(GFXFillSolid);
 
// TGEA 1.7 MOD - Begin
     mRenderTarget->attachTexture(GFXTextureTarget::Color0, NULL);
     GFX->popActiveRenderTarget();
// TGEA 1.7 MOD - End
 
   //************************************
   //************************************
   //************************************
 
    // set the clip
    GFX->setClipRect(updateRect);
 
    // turn off  z clipping
    GFX->setZEnable( false );
 

   //************************************
   //************************************
   //************************************
 

//after this is all surfaces
//**************************************
 
    // set ortho projection matrix
	// this makes ur view of the effect appears as directly above
    MatrixF proj = GFX->getProjectionMatrix();
    MatrixF newMat(true);
    GFX->setProjectionMatrix( newMat );
    GFX->pushWorldMatrix();
    GFX->setWorldMatrix( newMat );   
    GFX->setVertexShaderConstF( 0, (float*)&newMat, 4 );  // send the matrix to the shader
       


// 
//**********************************
 
	// ortho geometry
    GFXVertexBuffer *vb=NULL;
    PrimBuild::color4f( mFilterColor.red , mFilterColor.green , mFilterColor.blue, mFilterColor.alpha );
    PrimBuild::beginToBuffer( GFXTriangleFan, 4 );
      PrimBuild::texCoord2f( 0.0, 1.0 );
      PrimBuild::vertex3f( -1.0 , -1.0 , 0.0 );
      
      PrimBuild::texCoord2f( 0.0, 0.0 );
      PrimBuild::vertex3f( -1.0 ,  1.0 , 0.0 );
      
      PrimBuild::texCoord2f( 1.0, 0.0 );
      PrimBuild::vertex3f(  1.0 ,  1.0 , 0.0 );
      
      PrimBuild::texCoord2f( 1.0, 1.0 );
      PrimBuild::vertex3f(  1.0 , -1.0 , 0.0 );
    U32 numPrims;
    vb =  PrimBuild::endToBuffer( numPrims );
   

   mEffectShader->shader->process();
 
   GFX->setTexture( 0, mSurface[0] );
 
   GFX->setVertexBuffer( vb );
   GFX->drawPrimitive( GFXTriangleFan, 0, 2 );
 
   GFX->disableShaders();
 

//**********************************************

 
   // render state cleanup
   GFX->setAlphaBlendEnable( false );
   GFX->setCullMode( GFXCullNone );
   GFX->setLightingEnable( false );
   GFX->setZWriteEnable( true );
   GFX->setTextureStageColorOp( 0, GFXTOPDisable );  
   GFX->disableShaders();
 
   GFX->popWorldMatrix();
 
   FrameAllocator::setWaterMark(0);
}
#45
06/26/2008 (5:08 am)
Thanks for the fix, but I'm getting a lot of Z-buffer issues. Some stuff appear inside out, while other things aren't rendered at all.

*Edited a Typo*
#46
07/21/2008 (12:41 pm)
I have an issue with this in pre-TGEA 1.7. I haven't integrated to 1.7 yet.

Anyway, we're using this resource for full-screen fade in/from black and we noticed that when the filter is on, the image shifts down and right one pixel. This can sometimes leave a visible border on the top and left of the screen.

I can eliminate the border by increasing the vertex coordinates to say 1.01 but that creates it's own shifting problem. Is there something not being set or is it perhaps not accounting for the DirectX 0.5 pixel shift?
#47
09/23/2008 (5:47 am)
Anyone found a way to fix this z-buffer issue? I tried to look through the code but didn't get any results, I guess I'm pretty rusty. Looks like some of the terrain is rendered somehow back to front order? It's weird since it doesn't seem to draw everything in this wrong order... could it also have something to do with the non-rendered object flags?
#48
11/03/2008 (3:39 am)
hi ,
any one can pls explain why vertex normals for all objects gets reversed when using the above code for torque 1.7.

the effects are working pretty nice but their is a serious texture issues that gets flipped due to vertex normals...
#49
11/06/2008 (9:18 pm)
hi guys,

I found the fix for it .

after the line

mRenderTarget->attachTexture(GFXTextureTarget::Color0, mSurface[0]);

you need to add

mRenderTarget->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);

this will fix the z-buffer issue.

enjoy full screen effects :)
#50
11/11/2008 (7:42 am)
nevermind... missed where it said to ADD the above line... thought it was a replace. compiled and working in AFX + TGEA 1.7.x
#51
11/21/2008 (10:12 am)
Hi All,

I'm an artist but only a budding programmer, so bear with me. I've implimented all of the things shown above into my 1.7.1 project with no compile errors and the scripts all seem fine. When I boot up the game, right after the startup GUI, I get a solid magenta color. The weird thing is that it seems to be behind one part of my GUI layer, but in front of everything else. The "v" key doesn't do anything of note, I don't get any errors in my log but nor do I get any output saying that the shaders loaded. Any ideas? Any thoughts on how I should try to debug it?

Thanks
#52
11/21/2008 (2:59 pm)
OK, I understand why the full screen magenta is behind a part of GUI, because it's rendered on the PlayGui layer. The rest still evades me.
#53
11/21/2008 (3:40 pm)
I found that I had missed putting in the initShader call in my scripts. Put it in and now got the "...LOADED!!" messages, but still magenta.
#54
11/23/2008 (1:01 pm)
I get the same result. No compile or script errors, just a magenta background to my PlayGui.
#55
11/24/2008 (9:53 am)
Oh good! It's not just me. Are you also finding that GameTSCtrl::renderWorld isn't being called by anything? I'm trying to figure out where it should be.

Edit: Ooops. renderWorld is being called just fine. N/M

Edit: Or is it? Break points don't stop there.
#56
11/24/2008 (11:41 am)
I'm finding that other "renderWorld"s (guiTSControl.cpp and an example from this link http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5686) are being called in onRender. None of the above instructions list that, and when I put it in it gives me an error "Out of bounds viewport bounds". Am I getting close? Who knows.
#57
04/22/2009 (5:06 am)
IS there anyone who has this working for 1.8? I have applied all 1.7 changes mentioned by Simon but they don't work for 1.8. It appears that the GFX device has changed heavily since 1.7, these are the types of errors I'm getting:
error C2027: use of undefined type 'GFXTextureManager'
error C2227: left of '->createTexture' must point to class/struct/union/generic type
error C2039: 'setZEnable' : is not a member of 'GFXDevice'
error C2039: 'setZFunc' : is not a member of 'GFXDevice'
error C2039: 'setCullMode' : is not a member of 'GFXDevice'
Etc, etc :(
It's the "GFX->xxxxx" that gives the problems.

Anyone with a solution? Thanks! :)
#58
04/27/2009 (3:36 pm)
One of the major features of 1.8 is that they now pass commands to GFX as a structure...

http://www.garagegames.com/community/blogs/view/15436

I'll try it this way, but let me know if you have any progress! I suppose they're all working on Torque 3D.
#59
04/30/2009 (2:06 am)
I made a thread on the forum about it, linking to this resource. I hope to find an answer this way. Thanks for the clarification anyway Tobyn!

http://www.garagegames.com/community/forums/viewthread/90299
#60
05/08/2009 (1:43 pm)
you need something like this GFX state block:
GFXStateBlockDesc desc;
desc.setCullMode( GFXCullNone );
desc.setZEnable(false);
desc.zWriteEnable = false;
desc.samplersDefined = true;
desc.samplers[0].textureColorOp = GFXTOPModulate;
desc.samplers[1].textureColorOp = GFXTOPDisable;
desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);

... and so on