//========= 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( false /* bForceLowQuality */, true /* bPS30 */ ) : SHADOWFILTERMODE_DEFAULT ); 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, TEXTURE_BINDFLAGS_SRGBREAD, pCookieTexture, nFrameNumber ); } ITexture *pFlashlightDepthTexture = NULL; if( (info.m_nShadowDepthTexture != -1) && params[info.m_nShadowDepthTexture]->IsDefined() && g_pConfig->ShadowDepthTexture() && flashlightState.m_bEnableShadows ) { pFlashlightDepthTexture = params[info.m_nShadowDepthTexture]->GetTextureValue(); pShader->BindTexture( SHADER_SAMPLER1, TEXTURE_BINDFLAGS_SHADOWDEPTH, pFlashlightDepthTexture ); pShaderAPI->BindStandardTexture( SHADER_SAMPLER2, TEXTURE_BINDFLAGS_NONE, 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, TEXTURE_BINDFLAGS_NONE, 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 && ( pFlashlightDepthTexture != NULL ) ); SET_DYNAMIC_PIXEL_SHADER_COMBO( UBERLIGHT, flashlightState.m_bUberlight ); SET_DYNAMIC_PIXEL_SHADER( lightshafts_ps30 ); } pShader->Draw(); }