311 lines
12 KiB
C++
311 lines
12 KiB
C++
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
|
|
|
|
#include "BaseVSShader.h"
|
|
#include "mathlib/VMatrix.h"
|
|
#include "lightshafts_helper.h"
|
|
#include "convar.h"
|
|
|
|
// Auto generated inc files
|
|
#include "lightshafts_vs30.inc"
|
|
#include "lightshafts_ps30.inc"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
void InitParamsLightShafts( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, LightShaftsVars_t &info )
|
|
{
|
|
// Set material flags
|
|
SET_FLAGS( MATERIAL_VAR_TRANSLUCENT );
|
|
SET_FLAGS( MATERIAL_VAR_NOCULL );
|
|
SET_PARAM_INT_IF_NOT_DEFINED( info.m_nCookieFrameNum, 0 );
|
|
SET_PARAM_FLOAT_IF_NOT_DEFINED( info.m_nTime, 0.0f );
|
|
}
|
|
|
|
void InitLightShafts( CBaseVSShader *pShader, IMaterialVar** params, LightShaftsVars_t &info )
|
|
{
|
|
// Load textures
|
|
if ( (info.m_nCookieTexture != -1) && params[info.m_nCookieTexture]->IsDefined() )
|
|
{
|
|
pShader->LoadTexture( info.m_nCookieTexture );
|
|
}
|
|
|
|
if ( (info.m_nShadowDepthTexture != -1) && params[info.m_nShadowDepthTexture]->IsDefined() )
|
|
{
|
|
pShader->LoadTexture( info.m_nShadowDepthTexture );
|
|
}
|
|
|
|
if ( (info.m_nNoiseTexture != -1) && params[info.m_nNoiseTexture]->IsDefined() )
|
|
{
|
|
pShader->LoadTexture( info.m_nNoiseTexture );
|
|
}
|
|
}
|
|
|
|
void DrawLightShafts( CBaseVSShader *pShader, IMaterialVar** params, IShaderDynamicAPI *pShaderAPI,
|
|
IShaderShadow* pShaderShadow, LightShaftsVars_t &info, VertexCompressionType_t vertexCompression )
|
|
{
|
|
SHADOW_STATE
|
|
{
|
|
// Set stream format (note that this shader supports compression)
|
|
unsigned int flags = VERTEX_POSITION;
|
|
pShaderShadow->VertexShaderVertexFormat( flags, 0, NULL, 0 ); // no texture coordinates needed
|
|
|
|
DECLARE_STATIC_VERTEX_SHADER( lightshafts_vs30 );
|
|
SET_STATIC_VERTEX_SHADER( lightshafts_vs30 );
|
|
|
|
DECLARE_STATIC_PIXEL_SHADER( lightshafts_ps30 );
|
|
SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, IsPC() ? g_pHardwareConfig->GetShadowFilterMode() : 0 );
|
|
SET_STATIC_PIXEL_SHADER( lightshafts_ps30 );
|
|
|
|
pShaderShadow->EnableTexture( SHADER_SAMPLER0, true ); // Cookie texture
|
|
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, true );
|
|
|
|
pShaderShadow->EnableTexture( SHADER_SAMPLER1, true ); // Shadow depth texture
|
|
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, false );
|
|
pShaderShadow->SetShadowDepthFiltering( SHADER_SAMPLER1 );
|
|
|
|
pShaderShadow->EnableTexture( SHADER_SAMPLER2, true ); // Screen-space noise map for shadow filtering
|
|
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER2, false );
|
|
|
|
pShaderShadow->EnableTexture( SHADER_SAMPLER3, true ); // Projective noise map used for non-uniform atmospherics
|
|
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER3, false );
|
|
|
|
pShaderShadow->EnableSRGBWrite( true );
|
|
|
|
pShader->EnableAlphaBlending( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); // Additive blending
|
|
pShaderShadow->EnableAlphaWrites( false );
|
|
}
|
|
DYNAMIC_STATE
|
|
{
|
|
DECLARE_DYNAMIC_VERTEX_SHADER( lightshafts_vs30 );
|
|
SET_DYNAMIC_VERTEX_SHADER( lightshafts_vs30 );
|
|
|
|
//
|
|
// Read material vars into relevant members of flashlightState...kinda icky and verbose...
|
|
//
|
|
VMatrix worldToTexture;
|
|
FlashlightState_t flashlightState;
|
|
|
|
if ( (info.m_nWorldToTexture != -1) && params[info.m_nWorldToTexture]->IsDefined() )
|
|
{
|
|
const VMatrix &mat = params[info.m_nWorldToTexture]->GetMatrixValue();
|
|
worldToTexture = mat;
|
|
}
|
|
|
|
if ( (info.m_nFlashlightColor != -1) && params[info.m_nFlashlightColor]->IsDefined() )
|
|
{
|
|
params[info.m_nFlashlightColor]->GetVecValue( &(flashlightState.m_Color[0]), 4 );
|
|
}
|
|
else
|
|
{
|
|
flashlightState.m_Color[0] = flashlightState.m_Color[1] = flashlightState.m_Color[2] = flashlightState.m_Color[3] = 1.0f;
|
|
}
|
|
|
|
// Pre-modulate with intensity factor
|
|
if ( (info.m_nVolumetricIntensity != -1) && params[info.m_nVolumetricIntensity]->IsDefined() )
|
|
{
|
|
float flVolumetricIntensity = params[info.m_nVolumetricIntensity]->GetFloatValue();
|
|
flashlightState.m_Color[0] *= flVolumetricIntensity;
|
|
flashlightState.m_Color[1] *= flVolumetricIntensity;
|
|
flashlightState.m_Color[2] *= flVolumetricIntensity;
|
|
}
|
|
|
|
SetFlashLightColorFromState( flashlightState, pShaderAPI, false, PSREG_FLASHLIGHT_COLOR );
|
|
|
|
if ( (info.m_nAttenFactors != -1) && params[info.m_nAttenFactors]->IsDefined() )
|
|
{
|
|
float v[4];
|
|
params[info.m_nAttenFactors]->GetVecValue( v, 4 );
|
|
flashlightState.m_fConstantAtten = v[0];
|
|
flashlightState.m_fLinearAtten = v[1];
|
|
flashlightState.m_fQuadraticAtten = v[2];
|
|
flashlightState.m_FarZAtten = v[3];
|
|
}
|
|
|
|
if ( (info.m_nOriginFarZ != -1) && params[info.m_nOriginFarZ]->IsDefined() )
|
|
{
|
|
float v[4];
|
|
params[info.m_nOriginFarZ]->GetVecValue( v, 4 );
|
|
flashlightState.m_vecLightOrigin[0] = v[0];
|
|
flashlightState.m_vecLightOrigin[1] = v[1];
|
|
flashlightState.m_vecLightOrigin[2] = v[2];
|
|
flashlightState.m_FarZ = v[3];
|
|
}
|
|
|
|
if ( (info.m_nQuatOrientation != -1) && params[info.m_nQuatOrientation]->IsDefined() )
|
|
{
|
|
params[info.m_nQuatOrientation]->GetVecValue( flashlightState.m_quatOrientation.Base(), 4 );
|
|
}
|
|
|
|
if ( (info.m_nShadowFilterSize != -1) && params[info.m_nShadowFilterSize]->IsDefined() )
|
|
{
|
|
flashlightState.m_flShadowFilterSize = params[info.m_nShadowFilterSize]->GetFloatValue();
|
|
}
|
|
|
|
if ( (info.m_nShadowAtten != -1) && params[info.m_nShadowAtten]->IsDefined() )
|
|
{
|
|
flashlightState.m_flShadowAtten = params[info.m_nShadowAtten]->GetFloatValue();
|
|
}
|
|
|
|
if ( (info.m_nShadowJitterSeed != -1) && params[info.m_nShadowJitterSeed]->IsDefined() )
|
|
{
|
|
flashlightState.m_flShadowJitterSeed = params[info.m_nShadowJitterSeed]->GetFloatValue();
|
|
}
|
|
|
|
if ( (info.m_nFlashlightTime != -1) && params[info.m_nFlashlightTime]->IsDefined() )
|
|
{
|
|
flashlightState.m_flFlashlightTime = params[info.m_nFlashlightTime]->GetFloatValue();
|
|
}
|
|
|
|
if ( (info.m_nNumPlanes != -1) && params[info.m_nNumPlanes]->IsDefined() )
|
|
{
|
|
flashlightState.m_nNumPlanes = params[info.m_nNumPlanes]->GetIntValue();
|
|
}
|
|
|
|
if ( (info.m_nUberlight != -1) && params[info.m_nUberlight]->IsDefined() )
|
|
{
|
|
flashlightState.m_bUberlight = ( params[info.m_nUberlight]->GetIntValue() != 0 );
|
|
}
|
|
|
|
if ( (info.m_nEnableShadows != -1) && params[info.m_nEnableShadows]->IsDefined() )
|
|
{
|
|
flashlightState.m_bEnableShadows = ( params[info.m_nEnableShadows]->GetIntValue() != 0 );
|
|
}
|
|
|
|
if ( (info.m_nNoiseStrength != -1) && params[info.m_nNoiseStrength]->IsDefined() )
|
|
{
|
|
flashlightState.m_flNoiseStrength = params[info.m_nNoiseStrength]->GetFloatValue();
|
|
}
|
|
|
|
if ( (info.m_nCookieTexture != -1) && params[info.m_nCookieTexture]->IsDefined() )
|
|
{
|
|
ITexture *pCookieTexture = params[info.m_nCookieTexture]->GetTextureValue();
|
|
int nFrameNumber = params[info.m_nCookieFrameNum]->GetIntValue();
|
|
pShader->BindTexture( SHADER_SAMPLER0, pCookieTexture, nFrameNumber );
|
|
}
|
|
|
|
if( (info.m_nShadowDepthTexture != -1) && params[info.m_nShadowDepthTexture]->IsDefined() &&
|
|
g_pConfig->ShadowDepthTexture() && flashlightState.m_bEnableShadows )
|
|
{
|
|
ITexture *pFlashlightDepthTexture = params[info.m_nShadowDepthTexture]->GetTextureValue();
|
|
pShader->BindTexture( SHADER_SAMPLER1, pFlashlightDepthTexture );
|
|
|
|
pShaderAPI->BindStandardTexture( SHADER_SAMPLER2, TEXTURE_SHADOW_NOISE_2D );
|
|
}
|
|
|
|
if( (info.m_nNoiseTexture != -1) && params[info.m_nNoiseTexture]->IsDefined() )
|
|
{
|
|
ITexture *pNoiseTexture = params[info.m_nNoiseTexture]->GetTextureValue();
|
|
pShader->BindTexture( SHADER_SAMPLER3, pNoiseTexture );
|
|
}
|
|
|
|
//
|
|
// Now that we've packed the flashlightState structure from our material vars, we can set constants and draw as normal
|
|
//
|
|
|
|
float atten[4], pos[4], tweaks[4], packedParams[4], noiseScroll[4];
|
|
atten[0] = flashlightState.m_fConstantAtten; // Set the flashlight attenuation factors
|
|
atten[1] = flashlightState.m_fLinearAtten;
|
|
atten[2] = flashlightState.m_fQuadraticAtten;
|
|
atten[3] = flashlightState.m_FarZAtten;
|
|
pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_ATTENUATION, atten, 1 );
|
|
|
|
pos[0] = flashlightState.m_vecLightOrigin[0]; // Set the flashlight origin
|
|
pos[1] = flashlightState.m_vecLightOrigin[1];
|
|
pos[2] = flashlightState.m_vecLightOrigin[2];
|
|
pos[3] = flashlightState.m_FarZ;
|
|
pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_POSITION_RIM_BOOST, pos, 1 ); // steps on rim boost
|
|
|
|
// Coefficient for projective noise
|
|
packedParams[0] = flashlightState.m_flNoiseStrength;
|
|
packedParams[1] = 64.0f / (float) flashlightState.m_nNumPlanes;
|
|
packedParams[2] = 0.0f;
|
|
packedParams[3] = 0.0f;
|
|
pShaderAPI->SetPixelShaderConstant( 0, packedParams, 1 );
|
|
|
|
// Directions for projective noise
|
|
noiseScroll[0] = fmodf( flashlightState.m_flFlashlightTime * 0.043f * 0.394, 1.0f); // UV offset for noise in red
|
|
noiseScroll[1] = fmodf( flashlightState.m_flFlashlightTime * 0.043f * 0.919, 1.0f);
|
|
noiseScroll[2] = fmodf( flashlightState.m_flFlashlightTime * 0.039f * -0.781, 1.0f); // UV offset for noise in green
|
|
noiseScroll[3] = fmodf( flashlightState.m_flFlashlightTime * 0.039f * 0.625, 1.0f);
|
|
pShaderAPI->SetPixelShaderConstant( 1, noiseScroll, 1 );
|
|
|
|
// Tweaks associated with a given flashlight
|
|
tweaks[0] = ShadowFilterFromState( flashlightState );
|
|
tweaks[1] = ShadowAttenFromState( flashlightState );
|
|
pShader->HashShadow2DJitter( flashlightState.m_flShadowJitterSeed, &tweaks[2], &tweaks[3] );
|
|
pShaderAPI->SetPixelShaderConstant( PSREG_ENVMAP_TINT__SHADOW_TWEAKS, tweaks, 1 );
|
|
|
|
pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, worldToTexture.Base(), 4 );
|
|
|
|
if ( flashlightState.m_bUberlight )
|
|
{
|
|
// No shear supported at present
|
|
flashlightState.m_uberlightState.m_fShearx = 0.0f;
|
|
flashlightState.m_uberlightState.m_fSheary = 0.0f;
|
|
|
|
if ( (info.m_nUberNearFar != -1) && params[info.m_nUberNearFar]->IsDefined() )
|
|
{
|
|
float v[4];
|
|
params[info.m_nUberNearFar]->GetVecValue( v, 4 );
|
|
flashlightState.m_uberlightState.m_fNearEdge = v[0];
|
|
flashlightState.m_uberlightState.m_fFarEdge = v[1];
|
|
flashlightState.m_uberlightState.m_fCutOn = v[2];
|
|
flashlightState.m_uberlightState.m_fCutOff = v[3];
|
|
}
|
|
|
|
if ( (info.m_nUberHeightWidth != -1) && params[info.m_nUberHeightWidth]->IsDefined() )
|
|
{
|
|
float v[4];
|
|
params[info.m_nUberHeightWidth]->GetVecValue( v, 4 );
|
|
flashlightState.m_uberlightState.m_fWidth = v[0];
|
|
flashlightState.m_uberlightState.m_fWedge = v[1];
|
|
flashlightState.m_uberlightState.m_fHeight = v[2];
|
|
flashlightState.m_uberlightState.m_fHedge = v[3];
|
|
}
|
|
|
|
if ( (info.m_nUberRoundness != -1) && params[info.m_nUberRoundness]->IsDefined() )
|
|
{
|
|
flashlightState.m_uberlightState.m_fRoundness = params[info.m_nUberRoundness]->GetFloatValue();
|
|
}
|
|
|
|
SetupUberlightFromState( pShaderAPI, flashlightState );
|
|
|
|
|
|
QAngle angles;
|
|
QuaternionAngles( flashlightState.m_quatOrientation, angles );
|
|
|
|
// World to Light's View matrix
|
|
matrix3x4_t viewMatrix, viewMatrixInverse;
|
|
AngleMatrix( angles, flashlightState.m_vecLightOrigin, viewMatrixInverse );
|
|
MatrixInvert( viewMatrixInverse, viewMatrix );
|
|
pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_4, worldToTexture.Base(), 4 );
|
|
}
|
|
else
|
|
{
|
|
matrix3x4_t identityMatrix;
|
|
SetIdentityMatrix( identityMatrix );
|
|
pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_4, identityMatrix.Base(), 4 );
|
|
}
|
|
|
|
// Dimensions of screen, used for screen-space noise map sampling
|
|
float vScreenScale[4] = {1280.0f / 32.0f, 720.0f / 32.0f, 0, 0};
|
|
int nWidth, nHeight;
|
|
pShaderAPI->GetBackBufferDimensions( nWidth, nHeight );
|
|
|
|
int nTexWidth, nTexHeight;
|
|
pShaderAPI->GetStandardTextureDimensions( &nTexWidth, &nTexHeight, TEXTURE_SHADOW_NOISE_2D );
|
|
|
|
vScreenScale[0] = (float) nWidth / nTexWidth;
|
|
vScreenScale[1] = (float) nHeight / nTexHeight;
|
|
|
|
pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_SCREEN_SCALE, vScreenScale, 1 );
|
|
|
|
DECLARE_DYNAMIC_PIXEL_SHADER( lightshafts_ps30 );
|
|
SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, flashlightState.m_bEnableShadows );
|
|
SET_DYNAMIC_PIXEL_SHADER_COMBO( UBERLIGHT, flashlightState.m_bUberlight );
|
|
SET_DYNAMIC_PIXEL_SHADER( lightshafts_ps30 );
|
|
}
|
|
pShader->Draw();
|
|
}
|