NightVision Tutorial: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(New Page - YAY!)
 
mNo edit summary
Line 15: Line 15:
Open the file '''src/cl_dll/view_scene.cpp''', and jump to the end (ctrl+end)
Open the file '''src/cl_dll/view_scene.cpp''', and jump to the end (ctrl+end)


<pre>
//nightfall - amckern - amckern@yahoo.com
//nightfall - amckern - amckern@yahoo.com
//NightVision
//NightVision
Line 46: Line 47:


static ConCommand r_screenover( "r_screenover", ScreenOver_f );
static ConCommand r_screenover( "r_screenover", ScreenOver_f );
 
</pre>
 
  static CTextureReference s_pMoBlurTex0;
 
  ITexture *GetMoBlurTex0( void )
  {
  if( !s_pMoBlurTex0 )
  {
  s_pMoBlurTex0.InitRenderTarget( 256, 256, [[RT_SIZE_FULL_FRAME_BUFFER]],
[[IMAGE_FORMAT_ARGB8888]], [[MATERIAL_RT_DEPTH_NONE]] );
  Assert( !IsErrorTexture( s_pMoBlurTex0 ) );
  }
 
  return s_pMoBlurTex0;
  }


This is the function we will use to get a pointer to the render target. The '256' numbers are meaningless, they get overridden by [[RT_SIZE_FULL_FRAME_BUFFER]] which forces the texture to be the size of the frame buffer.
This is the function we will use to get a pointer to the render target. The '256' numbers are meaningless, they get overridden by [[RT_SIZE_FULL_FRAME_BUFFER]] which forces the texture to be the size of the frame buffer.

Revision as of 07:48, 9 November 2005

Garry motionblur.jpg

Adding Nightvision To your Source Single Player Mod

Here's something that is part of Nightfall nightfall, and many people have been stumpled on - Night Vision.

Summary

Before i start, this is only one, and a very early attempt (It works), of one way to get the Night Vision Mode to work with your mod.

Before i start, i would like to credit Gnolfo from hl2coding.com and user:ts2do

Seting up the convar, and the Meat and Spuds

Open the file src/cl_dll/view_scene.cpp, and jump to the end (ctrl+end)

//nightfall - amckern - amckern@yahoo.com
//NightVision
static void ScreenOver_f( void )
{
	IMaterial *pMaterial = materials->FindMaterial( "HUDoverlays/nightvision", TEXTURE_GROUP_OTHER, true );

	{
		static bool bDisplayed = false;
		
		if( bDisplayed )
		{
			// turn it off
            view->SetScreenOverlayMaterial( NULL );
			engine->ClientCmd( "mat_fullbright 0\n" );//turn full bright off again
			CLocalPlayerFilter filter;
			C_BaseEntity::EmitSound( filter, 0, "Nightfall.NightVisOff" );
		}
		else
		{
			// turn it on
			view->SetScreenOverlayMaterial( pMaterial );
			engine->ClientCmd( "mat_fullbright 1\n" );//light up the world
			CLocalPlayerFilter filter;
			C_BaseEntity::EmitSound( filter, 0, "Nightfall.NightVisOn" );
		}
		
		bDisplayed = !bDisplayed;
	}
}

static ConCommand r_screenover( "r_screenover", ScreenOver_f );

This is the function we will use to get a pointer to the render target. The '256' numbers are meaningless, they get overridden by RT_SIZE_FULL_FRAME_BUFFER which forces the texture to be the size of the frame buffer.

So now in the file src/cl_dll/rendertexture.h add:

 ITexture *GetMoBlurTex0( void );

This will allow us to use this function.

Rendering the Motion Blur

First of all lets add some console commands that we're going to use. I make this console commands because people will want to change them in Garry's Mod. This code can go pretty much anywhere that it can be seen from CViewRender::RenderView( const CViewSetup &view, bool drawViewModel ) in view_scene.cpp.

 // To toggle the blur on and off
 ConVar pp_motionblur("pp_motionblur", "1", 0, "Motion Blur"); 
 // The amount of alpha to use when adding the FB to our custom buffer
 ConVar pp_motionblur_addalpha("pp_motionblur_addalpha", "0.1", 0, "Motion Blur Alpha");
 // The amount of alpha to use when adding our custom buffer to the FB
 ConVar pp_motionblur_drawalpha("pp_motionblur_drawalpha", "1", 0, "Motion Blur Draw Alpha");
 // Delay to add between capturing the FB
 ConVar pp_motionblur_time("pp_motionblur_time", "0.05", 0, "The amount of time to wait until updating the FB");

All pretty self explanatory.

 void CViewRender::DoMotionBlur( void )
 {
 	if ( pp_motionblur.GetInt() == 0 ) return;
 
 	static float fNextDrawTime = 0.0f;
 
 	bool found;
 	IMaterialVar* mv = NULL;
 	IMaterial *pMatScreen = NULL;
 	ITexture *pMoBlur = NULL;
 	ITexture *pOriginalTexture = NULL; 
 
 	// Get the front buffer material
 	pMatScreen = materials->FindMaterial( "frontbuffer", TEXTURE_GROUP_OTHER, true );
 	// Get our custom render target
 	pMoBlur = GetMoBlurTex0();
 	// Store the current render target	
 	ITexture *pOriginalRenderTarget = materials->GetRenderTarget();
 
 	// Set the camera up so we can draw the overlay
 	int oldX, oldY, oldW, oldH;
 	materials->GetViewport( oldX, oldY, oldW, oldH );
 
 	materials->MatrixMode( MATERIAL_PROJECTION );
 	materials->PushMatrix();
 	materials->LoadIdentity();	
 
 	materials->MatrixMode( MATERIAL_VIEW );
 	materials->PushMatrix();
 	materials->LoadIdentity();	
 
 
 	if( gpGlobals->curtime >= fNextDrawTime ) 
 	{
 		UpdateScreenEffectTexture( 0 );
 
 		// Set the alpha to whatever our console variable is
 		mv = pMatScreen->FindVar( "$alpha", &found, false );
 		if (found)
 		{
 			if ( fNextDrawTime == 0 )
 			{
 				mv->SetFloatValue( 1.0f );
 			}
 			else
 			{
 				mv->SetFloatValue( pp_motionblur_addalpha.GetFloat() );
 			}
 		}
 
 		materials->SetRenderTarget( pMoBlur );
 		materials->DrawScreenSpaceQuad( pMatScreen );
 
 		// Set the next draw time according to the convar
 		fNextDrawTime = gpGlobals->curtime + pp_motionblur_time.GetFloat();
 	}
 
 	// Set the alpha
 	mv = pMatScreen->FindVar( "$alpha", &found, false );
 	if (found)
 	{
 		mv->SetFloatValue( pp_motionblur_drawalpha.GetFloat() );
 	}
 
 	// Set the texture to our buffer
 	mv = pMatScreen->FindVar( "$basetexture", &found, false );
 	if (found)
 	{
 		pOriginalTexture = mv->GetTextureValue();
 		mv->SetTextureValue( pMoBlur );
 	}
 
 	// Pretend we were never here, set everything back
 	materials->SetRenderTarget( pOriginalRenderTarget );
 	materials->DrawScreenSpaceQuad( pMatScreen );
 	
       // Set our texture back to _rt_FullFrameFB
 	if (found)
 	{
 		mv->SetTextureValue( pOriginalTexture );
 	}
 
 	materials->DepthRange( 0.0f, 1.0f );
 	materials->MatrixMode( MATERIAL_PROJECTION );
 	materials->PopMatrix();
 	materials->MatrixMode( MATERIAL_VIEW );
 	materials->PopMatrix();
 }

I hope that all makes sense.

Now in the CViewRender::RenderView( const CViewSetup &view, bool drawViewModel ) function which is located in view_scene.cpp, add this:

 DoMotionBlur();

Just before

 // Draw the 2D graphics

Lastly Add the line:

void CViewRender::DoMotionBlur( void );

Before the end in the viewrender.h file.

Single Player

If your working on a Single Player Mod, you may have found that the front buffer wont update on a map change, or player death, this is because when you change the map, the gpGlobals->curtime variable resets to 0.0 seconds, but your fNextDrawTime retains its value.

So when the blur performs the check:

if ( fNextDrawTime < gpGlobals->curtime )

It will not return true until gpGlobals->curtime catches up - so if you played for 30 mins on the last map, the blur will start working 30 minutes into the new map. To do this you need to reset your fNextDrawTime on a map change by using the hack below, or don't use this check at all.

if ( fNextDrawTime - gpGlobals->curtime > 1.0f)
{
  	fNextDrawTime = 0.0f;
}

This code sits above this line

if( gpGlobals->curtime >= fNextDrawTime ) 

Material Files

That should do it. You need to add a material file called frontbuffer.vmt in your materials folder - although you could probably use an existing one. Here's what mine looks like:

 "UnlitGeneric"
 {
 	"$basetexture" "_rt_FullFrameFB"
 	"$ignorez"		1
 }

Finished

I chose this tutorial to do because it covered a few things that people continually ask me about. I hope it helps someone.

Garry Newman