From 4d9b257bf9effb103f36611847e6eca3afc3fd95 Mon Sep 17 00:00:00 2001 From: Nooodles Date: Thu, 9 Oct 2025 19:46:03 +1100 Subject: [PATCH 1/3] Initial implementation of transparent viewmodels --- src/game/client/baseclientrendertargets.cpp | 15 ++++ src/game/client/baseclientrendertargets.h | 4 + src/game/client/client_mapbase_hl2.vpc | 3 + src/game/client/hl2/rendertargets.cpp | 29 +++++++ src/game/client/hl2/rendertargets.h | 24 ++++++ src/game/client/view.cpp | 7 ++ src/game/client/viewrender.cpp | 88 +++++++++++++++++++++ src/game/client/viewrender.h | 2 + 8 files changed, 172 insertions(+) create mode 100644 src/game/client/hl2/rendertargets.cpp create mode 100644 src/game/client/hl2/rendertargets.h diff --git a/src/game/client/baseclientrendertargets.cpp b/src/game/client/baseclientrendertargets.cpp index 3aa642cf0ba..2cd16c3929f 100644 --- a/src/game/client/baseclientrendertargets.cpp +++ b/src/game/client/baseclientrendertargets.cpp @@ -45,6 +45,17 @@ ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMater CREATERENDERTARGETFLAGS_HDR ); } +ITexture *CBaseClientRenderTargets::CreateViewmodelTexture( IMaterialSystem *pMaterialSystem ) +{ + return pMaterialSystem->CreateNamedRenderTargetTextureEx2( + "_rt_viewmodel", + 1, 1, RT_SIZE_FULL_FRAME_BUFFER, + IMAGE_FORMAT_BGRA8888, + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_EIGHTBITALPHA, + CREATERENDERTARGETFLAGS_HDR ); +} + //----------------------------------------------------------------------------- // Purpose: Called by the engine in material system init and shutdown. // Clients should override this in their inherited version, but the base @@ -60,6 +71,8 @@ void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMateri // Monitors m_CameraTexture.Init( CreateCameraTexture( pMaterialSystem, iCameraTextureSize ) ); + + m_ViewmodelTexture.Init( CreateViewmodelTexture( pMaterialSystem ) ); } //----------------------------------------------------------------------------- @@ -75,4 +88,6 @@ void CBaseClientRenderTargets::ShutdownClientRenderTargets() // Monitors m_CameraTexture.Shutdown(); + + m_ViewmodelTexture.Shutdown(); } \ No newline at end of file diff --git a/src/game/client/baseclientrendertargets.h b/src/game/client/baseclientrendertargets.h index a1aad1ca59e..3b91a10fed7 100644 --- a/src/game/client/baseclientrendertargets.h +++ b/src/game/client/baseclientrendertargets.h @@ -54,10 +54,14 @@ class CBaseClientRenderTargets : public IClientRenderTargets // Used for the HUD in stereo and head tracking mode CTextureReference m_UITexture; + // Used for transparent viewmodels + CTextureReference m_ViewmodelTexture; + // Init functions for the common render targets ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); ITexture* CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize = 256 ); + ITexture *CreateViewmodelTexture( IMaterialSystem *pMaterialSystem ); }; diff --git a/src/game/client/client_mapbase_hl2.vpc b/src/game/client/client_mapbase_hl2.vpc index a4cc20ff5e0..5d2f110e6a1 100644 --- a/src/game/client/client_mapbase_hl2.vpc +++ b/src/game/client/client_mapbase_hl2.vpc @@ -24,6 +24,9 @@ $Project // Original stunstick files are conditional'd out in the HL2 VPCs $File "$SRCDIR\game\shared\hl2mp\weapon_stunstick.cpp" $File "$SRCDIR\game\shared\hl2mp\weapon_stunstick.h" + // Rendertargets implementation for HL2 + $File "hl2\rendertargets.cpp" + $File "hl2\rendertargets.h" } $Folder "HL2MP" diff --git a/src/game/client/hl2/rendertargets.cpp b/src/game/client/hl2/rendertargets.cpp new file mode 100644 index 00000000000..74ff55ecb6f --- /dev/null +++ b/src/game/client/hl2/rendertargets.cpp @@ -0,0 +1,29 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Implements IClientRenderTargets +// +// Author: Nooodles +// +//=============================================================================// +#include "cbase.h" +#include "rendertargets.h" + +ConVar mapbase_water_resolution( "mapbase_water_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); +ConVar mapbase_monitor_resolution( "mapbase_monitor_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); + +void CRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ) +{ + BaseClass::InitClientRenderTargets( pMaterialSystem, pHardwareConfig, + mapbase_water_resolution.GetInt(), mapbase_monitor_resolution.GetInt() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Shutdown client render targets. This gets called during shutdown in the engine +// Input : - +//----------------------------------------------------------------------------- +void CRenderTargets::ShutdownClientRenderTargets() +{ + BaseClass::ShutdownClientRenderTargets(); +} + +EXPOSE_INTERFACE( CRenderTargets, IClientRenderTargets, CLIENTRENDERTARGETS_INTERFACE_VERSION ); \ No newline at end of file diff --git a/src/game/client/hl2/rendertargets.h b/src/game/client/hl2/rendertargets.h new file mode 100644 index 00000000000..e8cb58f3ee8 --- /dev/null +++ b/src/game/client/hl2/rendertargets.h @@ -0,0 +1,24 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Implements IClientRenderTargets +// +// Author: Nooodles +// +//=============================================================================// + +#ifndef RENDERTARGETS_H +#define RENDERTARGETS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseclientrendertargets.h" + +class CRenderTargets : public CBaseClientRenderTargets +{ + DECLARE_CLASS_GAMEROOT( CRenderTargets, CBaseClientRenderTargets ); +public: + virtual void InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ); + virtual void ShutdownClientRenderTargets(); +}; +#endif diff --git a/src/game/client/view.cpp b/src/game/client/view.cpp index e84101c83cc..c1f03b8570b 100644 --- a/src/game/client/view.cpp +++ b/src/game/client/view.cpp @@ -323,6 +323,13 @@ void CViewRender::Init( void ) m_flLastFOV = default_fov.GetFloat(); #endif + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", "_rt_viewmodel" ); + pVMTKeyValues->SetInt( "$vertexcolor", 0 ); + pVMTKeyValues->SetInt( "$vertexalpha", 0 ); + pVMTKeyValues->SetInt( "$translucent", 1 ); + pVMTKeyValues->SetInt( "$additive", 0 ); + m_transparentVMMaterial.Init( "__viewmodel", TEXTURE_GROUP_RENDER_TARGET, pVMTKeyValues ); } //----------------------------------------------------------------------------- diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index b9fba9f8a07..3b15559817c 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -189,6 +189,8 @@ extern ConVar localplayer_visionflags; static ConVar r_nearz_skybox( "r_nearz_skybox", "2.0", FCVAR_CHEAT ); #endif +ConVar r_viewmodel_opacity( "r_viewmodel_opacity", "1", FCVAR_ARCHIVE, "", true, 0.f, true, 1.f ); + //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- @@ -1137,6 +1139,8 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod // Force clipped down range if( bUseDepthHack ) pRenderContext->DepthRange( 0.0f, 0.1f ); + + CUtlVector< IClientRenderable * > transparentVMList( 16 ); if ( bShouldDrawPlayerViewModel || bShouldDrawToolViewModels ) { @@ -1171,6 +1175,34 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod } } + // if we have viewmodel opacity move our vm model's to a different list + if ( r_viewmodel_opacity.GetFloat() < 1.f ) + { + int nOpaque = opaqueViewModelList.Count(); + for ( int i = nOpaque - 1; i >= 0; --i ) + { + IClientRenderable *pRenderable = opaqueViewModelList[i]; + CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( dynamic_cast( pEntity ) ) + { + transparentVMList.AddToTail( pRenderable ); + opaqueViewModelList.FastRemove( i ); + } + } + + int nTranslucent = translucentViewModelList.Count(); + for ( int i = nTranslucent - 1; i >= 0; --i ) + { + IClientRenderable *pRenderable = translucentViewModelList[i]; + CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( dynamic_cast( pEntity ) ) + { + transparentVMList.AddToTail( pRenderable ); + translucentViewModelList.FastRemove( i ); + } + } + } + if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) { UpdateRefractIfNeededByList( translucentViewModelList ); @@ -1180,6 +1212,40 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY ); } + if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + { + ITexture *pRenderTarget = materials->FindTexture( "_rt_viewmodel", TEXTURE_GROUP_RENDER_TARGET ); + pRenderContext->PushRenderTargetAndViewport( pRenderTarget, viewRender.x, viewRender.y, viewRender.width, viewRender.height ); + pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true, true ); + + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilTestMask( 0xFF ); + pRenderContext->SetStencilWriteMask( 0xFF ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_LESS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); + + DrawRenderablesInList( transparentVMList, STUDIO_TRANSPARENCY ); + + // clear based on our desired opacity + float opacity = r_viewmodel_opacity.GetFloat() * 255.f ; + pRenderContext->ClearColor4ub( 0, 0, 0, static_cast( opacity ) ); + pRenderContext->SetStencilReferenceValue( 0 ); + pRenderContext->ClearBuffersObeyStencilEx( false, true, true ); + pRenderContext->SetStencilEnable( false ); + + // redraw renderables without updating the depth buffer + pRenderContext->OverrideAlphaWriteEnable( true, false ); + DrawRenderablesInList( transparentVMList, STUDIO_TRANSPARENCY ); + pRenderContext->OverrideAlphaWriteEnable( false, true ); + + pRenderContext->PopRenderTargetAndViewport(); + } + + // Reset the depth range to the original values if( bUseDepthHack ) pRenderContext->DepthRange( depthmin, depthmax ); @@ -2484,8 +2550,30 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int DownscaleRect.x, DownscaleRect.y, DownscaleRect.x+DownscaleRect.width-1, DownscaleRect.y+DownscaleRect.height-1, pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + { + m_transparentVMMaterial->IncrementReferenceCount(); + + pRenderContextUpscale->DrawScreenSpaceRectangle( m_transparentVMMaterial, UpscaleRect.x, UpscaleRect.y, UpscaleRect.width, UpscaleRect.height, + DownscaleRect.x, DownscaleRect.y, DownscaleRect.x + DownscaleRect.width - 1, DownscaleRect.y + DownscaleRect.height - 1, + pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + + m_transparentVMMaterial->DecrementReferenceCount(); + } + pCopyMaterial->DecrementReferenceCount(); } + else if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + { + CMatRenderContextPtr pRenderContextVM( materials ); + m_transparentVMMaterial->IncrementReferenceCount(); + + ITexture *pFullFrameFB1 = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET ); + pRenderContextVM->DrawScreenSpaceRectangle( m_transparentVMMaterial, viewRender.x, viewRender.y, viewRender.width, viewRender.height, + viewRender.x, viewRender.y, viewRender.x + viewRender.width - 1, viewRender.y + viewRender.height - 1, + pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + m_transparentVMMaterial->DecrementReferenceCount(); + } // if we're in VR mode we might need to override the render target if( UseVR() ) diff --git a/src/game/client/viewrender.h b/src/game/client/viewrender.h index f732914f027..7eebd984282 100644 --- a/src/game/client/viewrender.h +++ b/src/game/client/viewrender.h @@ -527,6 +527,8 @@ class CViewRender : public IViewRender, CMaterialReference m_ScriptOverlayMaterial; char m_szCurrentScriptMaterialName[ MAX_PATH ]; + CMaterialReference m_transparentVMMaterial; + Vector m_vecLastFacing; float m_flCheapWaterStartDistance; float m_flCheapWaterEndDistance; From 6cf30e9a8c79acaada0f7af648b55486a0cf968f Mon Sep 17 00:00:00 2001 From: Nooodles Date: Thu, 9 Oct 2025 22:02:10 +1100 Subject: [PATCH 2/3] Repurposed STUDIO_DRAWTRANSLUCENTSUBMODELS flag for use in stenciling behaviour --- src/game/client/c_baseviewmodel.cpp | 29 +++++++------ src/game/client/viewrender.cpp | 67 +++++++++++++++++++---------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/game/client/c_baseviewmodel.cpp b/src/game/client/c_baseviewmodel.cpp index bcf609c5e40..39a908ec0c6 100644 --- a/src/game/client/c_baseviewmodel.cpp +++ b/src/game/client/c_baseviewmodel.cpp @@ -316,19 +316,22 @@ int C_BaseViewModel::DrawModel( int flags ) } #endif - int ret; - // If the local player's overriding the viewmodel rendering, let him do it - if ( pPlayer && pPlayer->IsOverridingViewmodel() ) - { - ret = pPlayer->DrawOverriddenViewmodel( this, flags ); - } - else if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + int ret = 0; + if ( !(flags & STUDIO_DRAWTRANSLUCENTSUBMODELS) ) { - ret = pWeapon->DrawOverriddenViewmodel( this, flags ); - } - else - { - ret = BaseClass::DrawModel( flags ); + // If the local player's overriding the viewmodel rendering, let him do it + if ( pPlayer && pPlayer->IsOverridingViewmodel() ) + { + ret = pPlayer->DrawOverriddenViewmodel( this, flags ); + } + else if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + { + ret = pWeapon->DrawOverriddenViewmodel( this, flags ); + } + else + { + ret = BaseClass::DrawModel( flags ); + } } // Now that we've rendered, reset the animation restart flag @@ -339,7 +342,7 @@ int C_BaseViewModel::DrawModel( int flags ) m_nOldAnimationParity = m_nAnimationParity; } // Tell the weapon itself that we've rendered, in case it wants to do something - if ( pWeapon ) + if ( (flags & STUDIO_DRAWTRANSLUCENTSUBMODELS) && pWeapon ) { pWeapon->ViewModelDrawn( this ); } diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index 3b15559817c..dd7e0274850 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -1183,7 +1183,7 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod { IClientRenderable *pRenderable = opaqueViewModelList[i]; CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( dynamic_cast( pEntity ) ) + if ( pEntity ) { transparentVMList.AddToTail( pRenderable ); opaqueViewModelList.FastRemove( i ); @@ -1195,7 +1195,7 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod { IClientRenderable *pRenderable = translucentViewModelList[i]; CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( dynamic_cast( pEntity ) ) + if ( pEntity ) { transparentVMList.AddToTail( pRenderable ); translucentViewModelList.FastRemove( i ); @@ -1209,40 +1209,63 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod } DrawRenderablesInList( opaqueViewModelList ); + DrawRenderablesInList( opaqueViewModelList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY ); + DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY | STUDIO_DRAWTRANSLUCENTSUBMODELS ); } - if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() >= 0.f ) { ITexture *pRenderTarget = materials->FindTexture( "_rt_viewmodel", TEXTURE_GROUP_RENDER_TARGET ); pRenderContext->PushRenderTargetAndViewport( pRenderTarget, viewRender.x, viewRender.y, viewRender.width, viewRender.height ); pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); pRenderContext->ClearBuffers( true, true, true ); - pRenderContext->SetStencilEnable( true ); - pRenderContext->SetStencilReferenceValue( 1 ); - pRenderContext->SetStencilTestMask( 0xFF ); - pRenderContext->SetStencilWriteMask( 0xFF ); - pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_LESS ); - pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); - pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); - pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); - - DrawRenderablesInList( transparentVMList, STUDIO_TRANSPARENCY ); + // write the stencil and draw the viewmodel for the vm render target + { + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilWriteMask( 0xFF ); + pRenderContext->SetStencilTestMask( 0xFF ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); + DrawRenderablesInList( transparentVMList, STUDIO_TRANSPARENCY ); + } - // clear based on our desired opacity - float opacity = r_viewmodel_opacity.GetFloat() * 255.f ; + // clear the alpha channel based on what we just drew + float opacity = r_viewmodel_opacity.GetFloat() * 255.f; pRenderContext->ClearColor4ub( 0, 0, 0, static_cast( opacity ) ); - pRenderContext->SetStencilReferenceValue( 0 ); + + pRenderContext->SetStencilWriteMask( 0 ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); pRenderContext->ClearBuffersObeyStencilEx( false, true, true ); - pRenderContext->SetStencilEnable( false ); + pRenderContext->PopRenderTargetAndViewport(); - // redraw renderables without updating the depth buffer - pRenderContext->OverrideAlphaWriteEnable( true, false ); - DrawRenderablesInList( transparentVMList, STUDIO_TRANSPARENCY ); - pRenderContext->OverrideAlphaWriteEnable( false, true ); + // write our stencil for the main render target + { + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilWriteMask( 0xFF ); + pRenderContext->SetStencilTestMask( 0xFF ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_LESS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); + DrawRenderablesInList( transparentVMList ); + } - pRenderContext->PopRenderTargetAndViewport(); + // draw what should just be the sprites + { + pRenderContext->SetStencilWriteMask( 0 ); + pRenderContext->SetStencilReferenceValue( 0 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); + DrawRenderablesInList( transparentVMList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); + } + + pRenderContext->SetStencilEnable( false ); } From 244cec9ac41af8ddc6afed4c07a6a248d91613b9 Mon Sep 17 00:00:00 2001 From: Nooodles Date: Sat, 11 Oct 2025 09:46:21 +1100 Subject: [PATCH 3/3] Refactor and added r_viewmodel_opacity_occlude_effects --- src/game/client/hl2/rendertargets.cpp | 7 +- src/game/client/viewrender.cpp | 142 ++++++++++++++------------ 2 files changed, 81 insertions(+), 68 deletions(-) diff --git a/src/game/client/hl2/rendertargets.cpp b/src/game/client/hl2/rendertargets.cpp index 74ff55ecb6f..906145621dc 100644 --- a/src/game/client/hl2/rendertargets.cpp +++ b/src/game/client/hl2/rendertargets.cpp @@ -8,13 +8,14 @@ #include "cbase.h" #include "rendertargets.h" -ConVar mapbase_water_resolution( "mapbase_water_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); -ConVar mapbase_monitor_resolution( "mapbase_monitor_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); +// shamelessly copied from TF2's rendertargets impl +ConVar hl2_water_resolution( "hl2_water_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); +ConVar hl2_monitor_resolution( "hl2_monitor_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); void CRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ) { BaseClass::InitClientRenderTargets( pMaterialSystem, pHardwareConfig, - mapbase_water_resolution.GetInt(), mapbase_monitor_resolution.GetInt() ); + hl2_water_resolution.GetInt(), hl2_monitor_resolution.GetInt() ); } //----------------------------------------------------------------------------- diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index dd7e0274850..7f8e12574ee 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -190,6 +190,13 @@ static ConVar r_nearz_skybox( "r_nearz_skybox", "2.0", FCVAR_CHEAT ); #endif ConVar r_viewmodel_opacity( "r_viewmodel_opacity", "1", FCVAR_ARCHIVE, "", true, 0.f, true, 1.f ); +// personal preference to have occlusion disable on TF2 by default +#ifdef TF_CLIENT_DLL +ConVar r_viewmodel_opacity_occlude_effects( "r_viewmodel_opacity_occlude_effects", "0", +#else +ConVar r_viewmodel_opacity_occlude_effects( "r_viewmodel_opacity_occlude_effects", "1", +#endif + FCVAR_ARCHIVE, "When the opacity is less than 1 should it occlude effects rendered with the viewmodel such as particles" ); //----------------------------------------------------------------------------- // Globals @@ -1139,14 +1146,13 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod // Force clipped down range if( bUseDepthHack ) pRenderContext->DepthRange( 0.0f, 0.1f ); - - CUtlVector< IClientRenderable * > transparentVMList( 16 ); if ( bShouldDrawPlayerViewModel || bShouldDrawToolViewModels ) { CUtlVector< IClientRenderable * > opaqueViewModelList( 32 ); CUtlVector< IClientRenderable * > translucentViewModelList( 32 ); + CUtlVector< IClientRenderable * > transparentList( 64 ); ClientLeafSystem()->CollateViewModelRenderables( opaqueViewModelList, translucentViewModelList ); @@ -1175,9 +1181,16 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod } } - // if we have viewmodel opacity move our vm model's to a different list - if ( r_viewmodel_opacity.GetFloat() < 1.f ) + if ( r_viewmodel_opacity.GetFloat() >= 1.f ) + { + if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) + { + UpdateRefractIfNeededByList( translucentViewModelList ); + } + } + else { + // move our vm models to a different list int nOpaque = opaqueViewModelList.Count(); for ( int i = nOpaque - 1; i >= 0; --i ) { @@ -1185,7 +1198,7 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); if ( pEntity ) { - transparentVMList.AddToTail( pRenderable ); + transparentList.AddToTail( pRenderable ); opaqueViewModelList.FastRemove( i ); } } @@ -1197,74 +1210,73 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); if ( pEntity ) { - transparentVMList.AddToTail( pRenderable ); + transparentList.AddToTail( pRenderable ); translucentViewModelList.FastRemove( i ); } } - } - if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) - { - UpdateRefractIfNeededByList( translucentViewModelList ); + if ( transparentList.Count() ) + { + ITexture *pRenderTarget = materials->FindTexture( "_rt_viewmodel", TEXTURE_GROUP_RENDER_TARGET ); + pRenderContext->PushRenderTargetAndViewport( pRenderTarget, viewRender.x, viewRender.y, viewRender.width, viewRender.height ); + pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true, true ); + + // write the stencil and draw the viewmodel for the vm render target + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilWriteMask( 0xFF ); + pRenderContext->SetStencilTestMask( 0xFF ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); + DrawRenderablesInList( transparentList, STUDIO_TRANSPARENCY ); + + // clear the alpha channel based on what we just drew + float opacity = r_viewmodel_opacity.GetFloat() * 255.f; + pRenderContext->ClearColor4ub( 0, 0, 0, static_cast( opacity ) ); + + pRenderContext->SetStencilWriteMask( 0 ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); + pRenderContext->ClearBuffersObeyStencilEx( false, true, true ); + pRenderContext->PopRenderTargetAndViewport(); + + // Do we want to occlude rendered effects and particles? + if ( !r_viewmodel_opacity_occlude_effects.GetBool() ) + pRenderContext->SetStencilEnable( false ); + else + { + // write our stencil for the main render target + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilWriteMask( 0x3 ); + pRenderContext->SetStencilTestMask( 0x3 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_LESS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); + + // something about drawing the ItemModelPanel render target ruins everything + // so just don't write colour which mostly works + pRenderContext->OverrideColorWriteEnable( true, false ); + DrawRenderablesInList( transparentList, STUDIO_TRANSPARENCY ); + pRenderContext->OverrideColorWriteEnable( false, true ); + + // setup for occlusion + pRenderContext->SetStencilWriteMask( 0 ); + pRenderContext->SetStencilReferenceValue( 0 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); + } + DrawRenderablesInList( transparentList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); + } } DrawRenderablesInList( opaqueViewModelList ); DrawRenderablesInList( opaqueViewModelList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY ); DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY | STUDIO_DRAWTRANSLUCENTSUBMODELS ); - } - - if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() >= 0.f ) - { - ITexture *pRenderTarget = materials->FindTexture( "_rt_viewmodel", TEXTURE_GROUP_RENDER_TARGET ); - pRenderContext->PushRenderTargetAndViewport( pRenderTarget, viewRender.x, viewRender.y, viewRender.width, viewRender.height ); - pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); - pRenderContext->ClearBuffers( true, true, true ); - - // write the stencil and draw the viewmodel for the vm render target - { - pRenderContext->SetStencilEnable( true ); - pRenderContext->SetStencilReferenceValue( 1 ); - pRenderContext->SetStencilWriteMask( 0xFF ); - pRenderContext->SetStencilTestMask( 0xFF ); - pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); - pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); - pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); - pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); - DrawRenderablesInList( transparentVMList, STUDIO_TRANSPARENCY ); - } - - // clear the alpha channel based on what we just drew - float opacity = r_viewmodel_opacity.GetFloat() * 255.f; - pRenderContext->ClearColor4ub( 0, 0, 0, static_cast( opacity ) ); - - pRenderContext->SetStencilWriteMask( 0 ); - pRenderContext->SetStencilReferenceValue( 1 ); - pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); - pRenderContext->ClearBuffersObeyStencilEx( false, true, true ); - pRenderContext->PopRenderTargetAndViewport(); - - // write our stencil for the main render target - { - pRenderContext->SetStencilEnable( true ); - pRenderContext->SetStencilReferenceValue( 1 ); - pRenderContext->SetStencilWriteMask( 0xFF ); - pRenderContext->SetStencilTestMask( 0xFF ); - pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_LESS ); - pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); - pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); - pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); - DrawRenderablesInList( transparentVMList ); - } - - // draw what should just be the sprites - { - pRenderContext->SetStencilWriteMask( 0 ); - pRenderContext->SetStencilReferenceValue( 0 ); - pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); - DrawRenderablesInList( transparentVMList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); - } - pRenderContext->SetStencilEnable( false ); } @@ -2573,7 +2585,7 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int DownscaleRect.x, DownscaleRect.y, DownscaleRect.x+DownscaleRect.width-1, DownscaleRect.y+DownscaleRect.height-1, pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); - if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + if ( r_drawviewmodel.GetBool() && r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) { m_transparentVMMaterial->IncrementReferenceCount(); @@ -2586,7 +2598,7 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int pCopyMaterial->DecrementReferenceCount(); } - else if ( r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + else if ( r_drawviewmodel.GetBool() && r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) { CMatRenderContextPtr pRenderContextVM( materials ); m_transparentVMMaterial->IncrementReferenceCount();