NightVision Tutorial: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(New Page - YAY!)
 
m (Fixed double redirect.)
 
(24 intermediate revisions by 6 users not shown)
Line 1: Line 1:
[[Category:Programming]]
#REDIRECT [[Vision Nocturna]]
[[Category:Tutorials]]
[[Image:garry_motionblur.jpg|thumb]]
== 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 );
 
 
  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.
 
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:
 
<pre>
void CViewRender::DoMotionBlur( void );
</pre>
 
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.
 
<pre>
if ( fNextDrawTime - gpGlobals->curtime > 1.0f)
{
  fNextDrawTime = 0.0f;
}
</pre>
 
This code sits above this line
 
<pre>if( gpGlobals->curtime >= fNextDrawTime ) </pre>
 
== 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

Latest revision as of 09:42, 6 March 2010

Redirect to: