diff --git a/materialsystem/stdshaders/VertexlitPBR_dx9.cpp b/materialsystem/stdshaders/VertexlitPBR_dx9.cpp new file mode 100644 index 0000000..1500958 --- /dev/null +++ b/materialsystem/stdshaders/VertexlitPBR_dx9.cpp @@ -0,0 +1,84 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// Example shader that can be applied to models +// +//================================================================================================== + +#include "BaseVSShader.h" +#include "convar.h" +#include "vertexlitpbr_dx9_helper.h" + +#ifdef STDSHADER +BEGIN_VS_SHADER(VertexLitPBR, + "Help for VertexLitPBR") +#else +BEGIN_VS_SHADER(VertexLitPBR, + "Help for VertexLitPBR") +#endif + +BEGIN_SHADER_PARAMS +SHADER_PARAM(ALPHATESTREFERENCE, SHADER_PARAM_TYPE_FLOAT, "0.0", "") +SHADER_PARAM(ENVMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/shadertest_env", "envmap") +SHADER_PARAM(BUMPMAP, SHADER_PARAM_TYPE_TEXTURE, "models/shadertest/shader1_normal", "bump map") + +SHADER_PARAM(BRDF, SHADER_PARAM_TYPE_TEXTURE, "models/PBRTest/BRDF", "") +SHADER_PARAM(NOISE, SHADER_PARAM_TYPE_TEXTURE, "shaders/bluenoise", "") +SHADER_PARAM(ROUGHNESS, SHADER_PARAM_TYPE_TEXTURE, "", "") +SHADER_PARAM(METALLIC, SHADER_PARAM_TYPE_TEXTURE, "", "") +SHADER_PARAM(AO, SHADER_PARAM_TYPE_TEXTURE, "", "") +SHADER_PARAM(EMISSIVE, SHADER_PARAM_TYPE_TEXTURE, "", "") +SHADER_PARAM(LIGHTMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/BaseTexture", "lightmap texture--will be bound by the engine") + +SHADER_PARAM(USESMOOTHNESS, SHADER_PARAM_TYPE_BOOL, "0", "Invert roughness") +END_SHADER_PARAMS + +void SetupVars(VertexLitPBR_DX9_Vars_t& info) +{ + info.m_nBaseTexture = BASETEXTURE; + info.m_nBaseTextureFrame = FRAME; + info.m_nBaseTextureTransform = BASETEXTURETRANSFORM; + info.m_nAlphaTestReference = ALPHATESTREFERENCE; + info.m_nRoughness = ROUGHNESS; + info.m_nMetallic = METALLIC; + info.m_nAO = AO; + info.m_nEmissive = EMISSIVE; + info.m_nEnvmap = ENVMAP; + info.m_nBumpmap = BUMPMAP; + info.m_nFlashlightTexture = FLASHLIGHTTEXTURE; + info.m_nFlashlightTextureFrame = FLASHLIGHTTEXTUREFRAME; + info.m_nBRDF = BRDF; + info.m_nUseSmoothness = USESMOOTHNESS; + info.m_nLightmap = LIGHTMAP; +} + +SHADER_INIT_PARAMS() +{ + VertexLitPBR_DX9_Vars_t info; + SetupVars(info); + InitParamsVertexLitPBR_DX9(this, params, pMaterialName, info); +} + +SHADER_FALLBACK +{ + return 0; +} + +SHADER_INIT +{ + VertexLitPBR_DX9_Vars_t info; + SetupVars(info); + InitVertexLitPBR_DX9(this, params, info); +} + +SHADER_DRAW +{ + bool hasFlashlight = UsingFlashlight(params); + + VertexLitPBR_DX9_Vars_t info; + SetupVars(info); + DrawVertexLitPBR_DX9(this, params, pShaderAPI, pShaderShadow, hasFlashlight, info, vertexCompression, pContextDataPtr); + +} + +END_SHADER + diff --git a/materialsystem/stdshaders/VertexlitPBR_dx9_helper.cpp b/materialsystem/stdshaders/VertexlitPBR_dx9_helper.cpp new file mode 100644 index 0000000..3a64204 --- /dev/null +++ b/materialsystem/stdshaders/VertexlitPBR_dx9_helper.cpp @@ -0,0 +1,477 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "BaseVSShader.h" +#include "vertexlitPBR_dx9_helper.h" +#include "convar.h" +#include "cpp_shader_constant_register_map.h" +#include "vertexlitPBR_vs30.inc" +#include "vertexlitPBR_ps30.inc" +#include "commandbuilder.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static ConVar mat_fullbright( "mat_fullbright", "0", FCVAR_CHEAT ); +static ConVar r_rimlight( "r_rimlight", "1", FCVAR_CHEAT ); + +//----------------------------------------------------------------------------- +// Initialize shader parameters +//----------------------------------------------------------------------------- +void InitParamsVertexLitPBR_DX9( CBaseVSShader *pShader, IMaterialVar** params, const char *pMaterialName, VertexLitPBR_DX9_Vars_t &info ) +{ + // FLASHLIGHTFIXME: Do ShaderAPI::BindFlashlightTexture + Assert( info.m_nFlashlightTexture >= 0 ); + + params[info.m_nBRDF]->SetStringValue("models/PBRTest/BRDF"); + + if ( g_pHardwareConfig->SupportsBorderColor() ) + { + params[FLASHLIGHTTEXTURE]->SetStringValue( "effects/flashlight_border" ); + } + else + { + params[FLASHLIGHTTEXTURE]->SetStringValue( "effects/flashlight001" ); + } + + if (((info.m_nBumpmap != -1) && g_pConfig->UseBumpmapping() && params[info.m_nBumpmap]->IsDefined()) + // we don't need a tangent space if we have envmap without bumpmap + // || ( info.m_nEnvmap != -1 && params[info.m_nEnvmap]->IsDefined() ) + ) + { + SET_FLAGS2(MATERIAL_VAR2_NEEDS_TANGENT_SPACES); + } + + + // This shader can be used with hw skinning + SET_FLAGS2( MATERIAL_VAR2_SUPPORTS_HW_SKINNING ); + SET_FLAGS2( MATERIAL_VAR2_LIGHTING_VERTEX_LIT ); +} + +//----------------------------------------------------------------------------- +// Initialize shader +//----------------------------------------------------------------------------- +void InitVertexLitPBR_DX9( CBaseVSShader *pShader, IMaterialVar** params, VertexLitPBR_DX9_Vars_t &info ) +{ + Assert( info.m_nFlashlightTexture >= 0 ); + pShader->LoadTexture(info.m_nFlashlightTexture, TEXTUREFLAGS_SRGB); + + bool bIsBaseTextureTranslucent = false; + if ( params[info.m_nBaseTexture]->IsDefined() ) + { + pShader->LoadTexture( info.m_nBaseTexture, TEXTUREFLAGS_SRGB ); + + if ( params[info.m_nBaseTexture]->GetTextureValue()->IsTranslucent() ) + { + bIsBaseTextureTranslucent = true; + } + } + + if (info.m_nRoughness != -1 && params[info.m_nRoughness]->IsDefined()) + { + pShader->LoadTexture(info.m_nRoughness); + } + if (info.m_nMetallic != -1 && params[info.m_nMetallic]->IsDefined()) + { + pShader->LoadTexture(info.m_nMetallic); + } + if (info.m_nAO != -1 && params[info.m_nAO]->IsDefined()) + { + pShader->LoadTexture(info.m_nAO); + } + if (info.m_nEmissive != -1 && params[info.m_nEmissive]->IsDefined()) + { + pShader->LoadTexture(info.m_nEmissive); + } + if (info.m_nBRDF != -1 && params[info.m_nBRDF]->IsDefined()) + { + pShader->LoadTexture(info.m_nBRDF); + } + if (info.m_nLightmap != -1 && params[info.m_nLightmap]->IsDefined()) + { + pShader->LoadTexture(info.m_nLightmap); + } + + if (info.m_nEnvmap != -1 && params[info.m_nEnvmap]->IsDefined()) + { + if (!IS_FLAG_SET(MATERIAL_VAR_ENVMAPSPHERE)) + { + int flags = g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ? TEXTUREFLAGS_SRGB : 0; + flags |= TEXTUREFLAGS_ALL_MIPS; + pShader->LoadCubeMap(info.m_nEnvmap, flags); + } + else + { + pShader->LoadTexture(info.m_nEnvmap, g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ? TEXTUREFLAGS_SRGB : 0); + } + + if (!g_pHardwareConfig->SupportsCubeMaps()) + { + SET_FLAGS(MATERIAL_VAR_ENVMAPSPHERE); + } + } + + if (g_pConfig->UseBumpmapping()) + { + if ((info.m_nBumpmap != -1) && params[info.m_nBumpmap]->IsDefined()) + { + pShader->LoadBumpMap(info.m_nBumpmap); + SET_FLAGS2(MATERIAL_VAR2_DIFFUSE_BUMPMAPPED_MODEL); + } + } +} + +class CVertexLitPBR_DX9_Context : public CBasePerMaterialContextData +{ +public: + CCommandBufferBuilder< CFixedCommandStorageBuffer< 800 > > m_SemiStaticCmdsOut; + bool m_bFastPath; + +}; + +//----------------------------------------------------------------------------- +// Draws the shader +//----------------------------------------------------------------------------- +static void DrawVertexLitPBR_DX9_Internal( CBaseVSShader *pShader, IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow, + bool bHasFlashlight, VertexLitPBR_DX9_Vars_t &info, VertexCompressionType_t vertexCompression, + CBasePerMaterialContextData **pContextDataPtr ) +{ + bool bHasBaseTexture = (info.m_nBaseTexture != -1) && params[info.m_nBaseTexture]->IsTexture(); + bool bHasRoughness = (info.m_nRoughness != -1) && params[info.m_nRoughness]->IsTexture(); + bool bHasMetallic = (info.m_nMetallic != -1) && params[info.m_nMetallic]->IsTexture(); + bool bHasAO = (info.m_nAO != -1) && params[info.m_nAO]->IsTexture(); + bool bHasEmissive = (info.m_nEmissive != -1) && params[info.m_nEmissive]->IsTexture(); + bool bIsAlphaTested = IS_FLAG_SET( MATERIAL_VAR_ALPHATEST ) != 0; + bool bHasEnvmap =(info.m_nEnvmap != -1) && params[info.m_nEnvmap]->IsTexture(); + bool bHasLegacyEnvSphereMap = bHasEnvmap && IS_FLAG_SET(MATERIAL_VAR_ENVMAPSPHERE); + bool bHasBump = IsTextureSet(info.m_nBumpmap, params); + bool bUseSmoothness = info.m_nUseSmoothness != -1 && params[info.m_nUseSmoothness]->GetIntValue() == 1; + bool bHasLightmap = (info.m_nLightmap != -1) && params[info.m_nLightmap]->IsTexture(); + + bool bHasVertexColor = IS_FLAG_SET(MATERIAL_VAR_VERTEXCOLOR); + bool bHasVertexAlpha = IS_FLAG_SET(MATERIAL_VAR_VERTEXALPHA); + + BlendType_t nBlendType= pShader->EvaluateBlendRequirements( info.m_nBaseTexture, true ); + bool bFullyOpaque = ( nBlendType != BT_BLENDADD ) && ( nBlendType != BT_BLEND ) && !bIsAlphaTested && !bHasFlashlight; + + CVertexLitPBR_DX9_Context *pContextData = reinterpret_cast< CVertexLitPBR_DX9_Context *> ( *pContextDataPtr ); + if ( !pContextData ) + { + pContextData = new CVertexLitPBR_DX9_Context; + *pContextDataPtr = pContextData; + } + + if( pShader->IsSnapshotting() ) + { + pShaderShadow->EnableAlphaTest( bIsAlphaTested ); + + if( info.m_nAlphaTestReference != -1 && params[info.m_nAlphaTestReference]->GetFloatValue() > 0.0f ) + { + pShaderShadow->AlphaFunc( SHADER_ALPHAFUNC_GEQUAL, params[info.m_nAlphaTestReference]->GetFloatValue() ); + } + + int nShadowFilterMode = 0; + if( bHasFlashlight ) + { + if (params[info.m_nBaseTexture]->IsTexture()) + { + pShader->SetAdditiveBlendingShadowState( info.m_nBaseTexture, true ); + } + + if( bIsAlphaTested ) + { + // disable alpha test and use the zfunc zequals since alpha isn't guaranteed to + // be the same on both the regular pass and the flashlight pass. + pShaderShadow->EnableAlphaTest( false ); + pShaderShadow->DepthFunc( SHADER_DEPTHFUNC_EQUAL ); + } + pShaderShadow->EnableBlending( true ); + pShaderShadow->EnableDepthWrites( false ); + + // Be sure not to write to dest alpha + pShaderShadow->EnableAlphaWrites( false ); + + nShadowFilterMode = g_pHardwareConfig->GetShadowFilterMode(); // Based upon vendor and device dependent formats + } + else // not flashlight pass + { + if (params[info.m_nBaseTexture]->IsTexture()) + { + pShader->SetDefaultBlendingShadowState( info.m_nBaseTexture, true ); + } + } + + unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL; + int userDataSize = 0; + + // Always enable...will bind white if nothing specified... + pShaderShadow->EnableTexture( SHADER_SAMPLER0, true ); // Base (albedo) map + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, true ); + + pShaderShadow->EnableTexture(SHADER_SAMPLER1, true); // Roughness map + pShaderShadow->EnableTexture(SHADER_SAMPLER2, true); // Metallic map + + if (bHasEnvmap) + { + pShaderShadow->EnableTexture(SHADER_SAMPLER7, true); + if (g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE) + { + pShaderShadow->EnableSRGBRead(SHADER_SAMPLER7, true); + } + } + + + if (bHasVertexColor || bHasVertexAlpha) + { + flags |= VERTEX_COLOR; + } + + pShaderShadow->EnableTexture( SHADER_SAMPLER4, true ); // Shadow depth map + pShaderShadow->SetShadowDepthFiltering( SHADER_SAMPLER4 ); + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER4, false ); + + if( bHasFlashlight ) + { + pShaderShadow->EnableTexture( SHADER_SAMPLER5, true ); // Noise map + pShaderShadow->EnableTexture( SHADER_SAMPLER6, true ); // Flashlight cookie + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER6, true ); + } + + pShaderShadow->EnableTexture(SHADER_SAMPLER8, true); // BRDF for IBL + + pShaderShadow->EnableTexture(SHADER_SAMPLER9, true); // Ambient Occlusion + pShaderShadow->EnableTexture(SHADER_SAMPLER10, true); // Emissive map + pShaderShadow->EnableTexture(SHADER_SAMPLER11, true); // Lightmap + + // Always enable, since flat normal will be bound + pShaderShadow->EnableTexture( SHADER_SAMPLER3, true ); // Normal map + userDataSize = 4; // tangent S + pShaderShadow->EnableTexture( SHADER_SAMPLER5, true ); // Normalizing cube map + pShaderShadow->EnableSRGBWrite( true ); + + // texcoord0 : base texcoord + int pTexCoordDim[3] = { 2, 2, 3 }; + int nTexCoordCount = 1; + + // This shader supports compressed vertices, so OR in that flag: + flags |= VERTEX_FORMAT_COMPRESSED; + + pShaderShadow->VertexShaderVertexFormat( flags, nTexCoordCount, pTexCoordDim, userDataSize ); + + DECLARE_STATIC_VERTEX_SHADER(vertexlitpbr_vs30); + SET_STATIC_VERTEX_SHADER_COMBO(VERTEXCOLOR, bHasVertexColor || bHasVertexAlpha); + SET_STATIC_VERTEX_SHADER_COMBO(CUBEMAP, bHasEnvmap); + SET_STATIC_VERTEX_SHADER_COMBO(DONT_GAMMA_CONVERT_VERTEX_COLOR, bHasVertexColor); + SET_STATIC_VERTEX_SHADER(vertexlitpbr_vs30); + + // Assume we're only going to get in here if we support 2b + DECLARE_STATIC_PIXEL_SHADER(vertexlitpbr_ps30); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap && !bHasFlashlight); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP_SPHERE_LEGACY, bHasLegacyEnvSphereMap); + SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, bHasFlashlight ? 1 : 0 ); + SET_STATIC_PIXEL_SHADER_COMBO( CONVERT_TO_SRGB, 0 ); + SET_STATIC_PIXEL_SHADER_COMBO(SMOOTHNESS, bUseSmoothness ? 1 : 0); + SET_STATIC_PIXEL_SHADER(vertexlitpbr_ps30); + + if( bHasFlashlight ) + { + pShader->FogToBlack(); + } + else + { + pShader->DefaultFog(); + } + + // HACK HACK HACK - enable alpha writes all the time so that we have them for underwater stuff + pShaderShadow->EnableAlphaWrites( bFullyOpaque ); + } + else // not snapshotting -- begin dynamic state + { + bool bLightingOnly = mat_fullbright.GetInt() == 2 && !IS_FLAG_SET( MATERIAL_VAR_NO_DEBUG_OVERRIDE ); + + if( bHasBaseTexture ) + pShader->BindTexture( SHADER_SAMPLER0, info.m_nBaseTexture, info.m_nBaseTextureFrame ); + else + pShaderAPI->BindStandardTexture( SHADER_SAMPLER0, TEXTURE_WHITE ); + + if (bHasRoughness) + pShader->BindTexture(SHADER_SAMPLER1, info.m_nRoughness); + else + pShaderAPI->BindStandardTexture(SHADER_SAMPLER1, TEXTURE_WHITE); + + if (bHasMetallic) + pShader->BindTexture(SHADER_SAMPLER2, info.m_nMetallic); + else + pShaderAPI->BindStandardTexture(SHADER_SAMPLER2, TEXTURE_BLACK); + + if (bHasEnvmap) + pShader->BindTexture(SHADER_SAMPLER7, info.m_nEnvmap); + + if (bHasAO) + pShader->BindTexture(SHADER_SAMPLER9, info.m_nAO); + else + pShaderAPI->BindStandardTexture(SHADER_SAMPLER9, TEXTURE_WHITE); + + if (bHasEmissive) + pShader->BindTexture(SHADER_SAMPLER10, info.m_nEmissive); + else + pShaderAPI->BindStandardTexture(SHADER_SAMPLER10, TEXTURE_BLACK); + + if (bHasLightmap) + pShader->BindTexture(SHADER_SAMPLER11, info.m_nLightmap); + else + pShaderAPI->BindStandardTexture(SHADER_SAMPLER11, TEXTURE_WHITE); + + if (!g_pConfig->m_bFastNoBump) + { + if (bHasBump) + { + pShader->BindTexture(SHADER_SAMPLER3, info.m_nBumpmap); + } + else + { + pShaderAPI->BindStandardTexture(SHADER_SAMPLER3, TEXTURE_NORMALMAP_FLAT); + } + } + else + { + if (bHasBump) + { + pShaderAPI->BindStandardTexture(SHADER_SAMPLER3, TEXTURE_NORMALMAP_FLAT); + } + } + + pShader->BindTexture(SHADER_SAMPLER8, info.m_nBRDF); + + LightState_t lightState = { 0, false, false }; + bool bFlashlightShadows = false; + if( bHasFlashlight ) + { + Assert( info.m_nFlashlightTexture >= 0 && info.m_nFlashlightTextureFrame >= 0 ); + pShader->BindTexture( SHADER_SAMPLER6, info.m_nFlashlightTexture, info.m_nFlashlightTextureFrame ); + VMatrix worldToTexture; + ITexture *pFlashlightDepthTexture; + FlashlightState_t state = pShaderAPI->GetFlashlightStateEx( worldToTexture, &pFlashlightDepthTexture ); + bFlashlightShadows = state.m_bEnableShadows && ( pFlashlightDepthTexture != NULL ); + + SetFlashLightColorFromState( state, pShaderAPI, PSREG_FLASHLIGHT_COLOR ); + + if( pFlashlightDepthTexture && g_pConfig->ShadowDepthTexture() && state.m_bEnableShadows ) + { + pShader->BindTexture( SHADER_SAMPLER4, pFlashlightDepthTexture, 0 ); + pShaderAPI->BindStandardTexture( SHADER_SAMPLER5, TEXTURE_SHADOW_NOISE_2D ); + } + } + else // no flashlight + { + pShaderAPI->GetDX9LightState( &lightState ); + } + + MaterialFogMode_t fogType = pShaderAPI->GetSceneFogMode(); + int fogIndex = ( fogType == MATERIAL_FOG_LINEAR_BELOW_FOG_Z ) ? 1 : 0; + int numBones = pShaderAPI->GetCurrentNumBones(); + + bool bWriteDepthToAlpha = false; + bool bWriteWaterFogToAlpha = false; + if( bFullyOpaque ) + { + bWriteDepthToAlpha = pShaderAPI->ShouldWriteDepthToDestAlpha(); + bWriteWaterFogToAlpha = (fogType == MATERIAL_FOG_LINEAR_BELOW_FOG_Z); + AssertMsg( !(bWriteDepthToAlpha && bWriteWaterFogToAlpha), "Can't write two values to alpha at the same time." ); + } + + DECLARE_DYNAMIC_VERTEX_SHADER(vertexlitpbr_vs30); + SET_DYNAMIC_VERTEX_SHADER_COMBO( DOWATERFOG, fogIndex ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( SKINNING, numBones > 0 ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( LIGHTING_PREVIEW, pShaderAPI->GetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING)!=0); + SET_DYNAMIC_VERTEX_SHADER_COMBO( COMPRESSED_VERTS, (int)vertexCompression ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights ); + SET_DYNAMIC_VERTEX_SHADER_COMBO(DYNAMIC_LIGHT, lightState.HasDynamicLight()); + SET_DYNAMIC_VERTEX_SHADER_COMBO(STATIC_LIGHT, lightState.m_bStaticLightVertex ? 1 : 0); + SET_DYNAMIC_VERTEX_SHADER(vertexlitpbr_vs30); + + DECLARE_DYNAMIC_PIXEL_SHADER(vertexlitpbr_ps30); + SET_DYNAMIC_PIXEL_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITEWATERFOGTODESTALPHA, bWriteWaterFogToAlpha ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITE_DEPTH_TO_DESTALPHA, bWriteDepthToAlpha ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, bFlashlightShadows ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( LIGHTMAP, bHasLightmap); + SET_DYNAMIC_PIXEL_SHADER_COMBO(LIGHT_PREVIEW, + pShaderAPI->GetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING)); + SET_DYNAMIC_PIXEL_SHADER(vertexlitpbr_ps30); + + pShader->SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, info.m_nBaseTextureTransform ); + pShader->SetModulationPixelShaderDynamicState_LinearColorSpace( 1 ); + pShader->SetAmbientCubeDynamicStateVertexShader(); + + // handle mat_fullbright 2 (diffuse lighting only) + if( bLightingOnly ) + { + pShaderAPI->BindStandardTexture( SHADER_SAMPLER0, TEXTURE_GREY ); + } + + pShaderAPI->SetPixelShaderFogParams( PSREG_FOG_PARAMS ); + + if (!bHasFlashlight) + { + pShaderAPI->BindStandardTexture(SHADER_SAMPLER5, TEXTURE_NORMALIZATION_CUBEMAP_SIGNED); + pShaderAPI->CommitPixelShaderLighting(PSREG_LIGHT_INFO_ARRAY); + pShaderAPI->SetPixelShaderStateAmbientLightCube(PSREG_AMBIENT_CUBE); // Force to black if not bAmbientLight + } + + float vEyePos_SpecExponent[4]; + pShaderAPI->GetWorldSpaceCameraPosition(vEyePos_SpecExponent); + vEyePos_SpecExponent[3] = 0.0f; + pShaderAPI->SetPixelShaderConstant(PSREG_EYEPOS_SPEC_EXPONENT, vEyePos_SpecExponent, 1); + + if( bHasFlashlight ) + { + VMatrix worldToTexture; + float atten[4], pos[4], tweaks[4]; + + const FlashlightState_t &flashlightState = pShaderAPI->GetFlashlightState( worldToTexture ); + + float const* pFlashlightColor = flashlightState.m_Color; + float vPsConst[4] = { pFlashlightColor[0], pFlashlightColor[1], pFlashlightColor[2], 4.5f }; + pShaderAPI->SetPixelShaderConstant(PSREG_FLASHLIGHT_COLOR, vPsConst, 1); + + pShader->BindTexture( SHADER_SAMPLER6, flashlightState.m_pSpotlightTexture, flashlightState.m_nSpotlightTextureFrame ); + + atten[0] = flashlightState.m_fConstantAtten; // Set the flashlight attenuation factors + atten[1] = flashlightState.m_fLinearAtten; + atten[2] = flashlightState.m_fQuadraticAtten; + atten[3] = flashlightState.m_FarZ; + 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]; + pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_POSITION_RIM_BOOST, pos, 1 ); + + pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE, worldToTexture.Base(), 4 ); + + // 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 ); + } + } + pShader->Draw(); +} + + +//----------------------------------------------------------------------------- +// Draws the shader +//----------------------------------------------------------------------------- +void DrawVertexLitPBR_DX9( CBaseVSShader *pShader, IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow, bool bHasFlashlight, + VertexLitPBR_DX9_Vars_t &info, VertexCompressionType_t vertexCompression, CBasePerMaterialContextData **pContextDataPtr ) + +{ + DrawVertexLitPBR_DX9_Internal( pShader, params, pShaderAPI, pShaderShadow, bHasFlashlight, info, vertexCompression, pContextDataPtr ); +} diff --git a/materialsystem/stdshaders/VertexlitPBR_dx9_helper.h b/materialsystem/stdshaders/VertexlitPBR_dx9_helper.h new file mode 100644 index 0000000..af04625 --- /dev/null +++ b/materialsystem/stdshaders/VertexlitPBR_dx9_helper.h @@ -0,0 +1,55 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// Example shader that can be applied to models +// +//================================================================================================== + +#ifndef EXAMPLE_MODEL_DX9_HELPER_H +#define EXAMPLE_MODEL_DX9_HELPER_H + +#include + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CBaseVSShader; +class IMaterialVar; +class IShaderDynamicAPI; +class IShaderShadow; + +//----------------------------------------------------------------------------- +// Init params/ init/ draw methods +//----------------------------------------------------------------------------- +struct VertexLitPBR_DX9_Vars_t +{ + VertexLitPBR_DX9_Vars_t() { memset( this, 0xFF, sizeof(*this) ); } + + int m_nBaseTexture; + int m_nBaseTextureFrame; + int m_nBaseTextureTransform; + int m_nAlphaTestReference; + int m_nRoughness; + int m_nMetallic; + int m_nAO; + int m_nEmissive; + int m_nEnvmap; + int m_nBumpmap; + int m_nFlashlightTexture; + int m_nFlashlightTextureFrame; + int m_nBRDF; + int m_nUseSmoothness; + int m_nLightmap; +}; + +void InitParamsVertexLitPBR_DX9( CBaseVSShader *pShader, IMaterialVar** params, + const char *pMaterialName, VertexLitPBR_DX9_Vars_t &info ); + +void InitVertexLitPBR_DX9( CBaseVSShader *pShader, IMaterialVar** params, + VertexLitPBR_DX9_Vars_t &info ); + +void DrawVertexLitPBR_DX9( CBaseVSShader *pShader, IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, + IShaderShadow* pShaderShadow, bool bHasFlashlight, + VertexLitPBR_DX9_Vars_t &info, VertexCompressionType_t vertexCompression, + CBasePerMaterialContextData **pContextDataPtr ); + +#endif // EXAMPLE_MODEL_DX9_HELPER_H diff --git a/materialsystem/stdshaders/common_pbr.h b/materialsystem/stdshaders/common_pbr.h new file mode 100644 index 0000000..662c701 --- /dev/null +++ b/materialsystem/stdshaders/common_pbr.h @@ -0,0 +1,176 @@ +#define PI 3.1415926 +float luminance(float3 rgb) +{ + const float3 W = float3(0.5125, 0.7154, 0.7121); + return dot(rgb, W); +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float num = NdotV; + float denom = NdotV * (1.0 - roughness) + roughness; + + return num / denom; +} + +float GeometrySmith(float3 N, float3 V, float3 L, float roughness) +{ + float r = roughness + 1.0f; + r = (r * r) / 8.0f; + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, r); + float ggx1 = GeometrySchlickGGX(NdotL, r); + + return ggx1 * ggx2; +} + +float DistributionBlinnPhong(float3 N, float3 H, float roughness) +{ + float alphaprime = roughness * roughness; + float a = alphaprime * alphaprime; + + return (1.0f / (a * PI)) * pow(dot(N, H), 2 / a - 2); +} + +float DistributionGGX(float3 N, float3 H, float distL, float roughness) +{ + float alphaPrime = saturate(16.0f / (distL * 2.0) + roughness); + float a = roughness * alphaPrime; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float num = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float DistributionTrowbridgeReitz(float HN, float roughness, float aP) +{ + + float a2 = roughness * roughness; + + float ap2 = aP * aP; + + return (a2 * ap2) / pow(HN * HN * (a2 - 1.0) + 1.0, 2.0); + +} + +float3 fresnelSchlick(float cosTheta, float3 F0) +{ + return F0 + (1.0f.xxx - F0) * pow(1.0f - cosTheta, 5.0); +} + +float3 Diffuse_OrenNayar(float3 DiffuseColor, float Roughness, float NoV, float NoL, float VoH) +{ + float a = Roughness * Roughness; + float s = a;// / ( 1.29 + 0.5 * a ); + float s2 = s * s; + float VoL = 2 * VoH * VoH - 1; // double angle identity + float Cosri = VoL - NoV * NoL; + float C1 = 1 - 0.5 * s2 / (s2 + 0.33); + float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * (Cosri >= 0 ? 1 / (max(NoL, NoV)) : 1); + return DiffuseColor / PI * (C1 + C2) * (1 + Roughness * 0.5); +} + +float3 DoPBRLight(float3 vWorldPos, float3 vWorldNormal, float3 albedo, float3 vPosition, float3 vColor, float3 vEye, float atten_radius, float3 metallness, float3 rough) +{ + float3 Li = (vPosition - vWorldPos ); + //float3 L = normalize(vPosition - vWorldPos); + float3 V = normalize( vEye - vWorldPos ); + float3 N = normalize( vWorldNormal ); + + float3 r = reflect(-V, N); + float3 L = Li; + float3 centerToRay = (dot(L, r) * r) - L; + float3 closestPoint = L + centerToRay * saturate(4.0f / length(centerToRay)); + L = normalize(closestPoint); + + float3 metallic = clamp(metallness, 0.0f, 0.9f); + float3 roughness = clamp(rough, 0.015f, 1.0f); + + float distance = length(closestPoint); + float attenuation = atten_radius; + float3 radiance = vColor * attenuation; + + float3 H = normalize(V + L); + + if(luminance(radiance) < 0.01f) + { + return 0.0f; + } + + float HV = max(0.0, dot(H, V)); + float HL = max(0.0, dot(H, L)); + float HN = max(0.0, dot(H, N)); + float LN = max(0.0, dot(L, N)); + float NV = max(0.0, dot(N, V)); + + float3 F0 = 0.04f.xxx; + F0 = lerp(F0, albedo, metallic); + float3 F = fresnelSchlick(HL, F0); + float3 F2 = fresnelSchlick(HV, F0); + //float3 F = Diffuse_OrenNayar(F0, roughness, NV, LN, HV); + + // D - Calculate normal distribution for specular BRDF. + //float D = DistributionGGX(N, H, length(Li), roughness); + float D = DistributionBlinnPhong(N, H, roughness); + //float alpha = roughness * roughness; + //float alphaPrime = clamp(lightRadius / (lenL * 2.0) + alpha, 0.0, 1.0); + //float D = DistributionTrowbridgeReitz(HN, alpha, alphaPrime); + + // Calculate geometric attenuation for specular BRDF. + float G = GeometrySmith(N, V, L, roughness); + + // Diffuse scattering happens due to light being refracted multiple times by a dielectric medium. + // Metals on the other hand either reflect or absorb energy so diffuse contribution is always, zero. + // To be energy conserving we must scale diffuse BRDF contribution based on Fresnel factor & metalness. + //float3 kd = lerp((1.0f.xxx - F), 0.0f.xxx, metallic.x); + float3 kd = (1.0f.xxx - F) * (1.0f.xxx - F2) * (1.0f.xxx - metallic); + + float3 diffuseBRDF = (kd * albedo.rgb) / PI; + + // Cook-Torrance specular microfacet BRDF. + float3 specularBRDF = (F * D * G) / max(0.001, 4.0 * LN * NV); + + return (diffuseBRDF + specularBRDF) * LN * radiance; +} + +float random (float2 uv) { + return frac(sin(dot(uv.xy, + float2(12.9898,78.233)))* + 43758.5453123); +} + +float3 SampleAmbientReflection(float3 normal, in float3 Ambient, in float3 Ground) +{ + float NU = max(0.0, dot(normal, float3(0.0f, 0.0f, 1.0f)) * 0.5f +0.5f); + float reflectionTransition = step(NU, 0.5f); + float3 reflection = lerp(Ground, Ambient, reflectionTransition); + return reflection; +} + +float3 DoAmbient(float2 UV, float3 vWorldPos, float3 vWorldNormal, float3 vEye, in float roughness, in float3 albedo, in float3 Ambient, in float3 Ground) +{ + float3 V = normalize( vEye - vWorldPos ); + float NV = max(0.0, dot(vWorldNormal, V) * 0.5f +0.5f); + float NU = max(0.0, dot(vWorldNormal, float3(0.0f, 0.0f, 1.0f)) * 0.5f +0.5f); + + float diffuseTransition = NU; + float3 diffuse = lerp(Ground, Ambient, diffuseTransition); + + HALF3 reflectVect = 2.0 * NV * vWorldNormal - V; + float3 reflection = 0.0f.xxx; + for (unsigned int isample = 0; isample < 32; isample++) + { + float3 randomvec = float3(random(UV + isample), random(UV + isample + 1), random(UV + isample + 2)); + randomvec = randomvec * 2.0f - 1.0f; + reflection += SampleAmbientReflection(float4((reflectVect + (randomvec * roughness * roughness * 1.75f)), roughness * 4.0), Ground, Ambient).rgb / 32.0f; + } + + + return albedo.rgb * lerp(reflection, diffuse, roughness); +} \ No newline at end of file diff --git a/materialsystem/stdshaders/fxctmp9/vertexlitPBR_ps30.inc b/materialsystem/stdshaders/fxctmp9/vertexlitPBR_ps30.inc new file mode 100644 index 0000000..82fef82 --- /dev/null +++ b/materialsystem/stdshaders/fxctmp9/vertexlitPBR_ps30.inc @@ -0,0 +1,337 @@ +#include "shaderlib/cshader.h" +class vertexlitpbr_ps30_Static_Index +{ +private: + int m_nCONVERT_TO_SRGB; +#ifdef _DEBUG + bool m_bCONVERT_TO_SRGB; +#endif +public: + void SetCONVERT_TO_SRGB( int i ) + { + Assert( i >= 0 && i <= 0 ); + m_nCONVERT_TO_SRGB = i; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } + void SetCONVERT_TO_SRGB( bool i ) + { + m_nCONVERT_TO_SRGB = i ? 1 : 0; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } +private: + int m_nFLASHLIGHT; +#ifdef _DEBUG + bool m_bFLASHLIGHT; +#endif +public: + void SetFLASHLIGHT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLASHLIGHT = i; +#ifdef _DEBUG + m_bFLASHLIGHT = true; +#endif + } + void SetFLASHLIGHT( bool i ) + { + m_nFLASHLIGHT = i ? 1 : 0; +#ifdef _DEBUG + m_bFLASHLIGHT = true; +#endif + } +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nCUBEMAP_SPHERE_LEGACY; +#ifdef _DEBUG + bool m_bCUBEMAP_SPHERE_LEGACY; +#endif +public: + void SetCUBEMAP_SPHERE_LEGACY( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP_SPHERE_LEGACY = i; +#ifdef _DEBUG + m_bCUBEMAP_SPHERE_LEGACY = true; +#endif + } + void SetCUBEMAP_SPHERE_LEGACY( bool i ) + { + m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP_SPHERE_LEGACY = true; +#endif + } +private: + int m_nSMOOTHNESS; +#ifdef _DEBUG + bool m_bSMOOTHNESS; +#endif +public: + void SetSMOOTHNESS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSMOOTHNESS = i; +#ifdef _DEBUG + m_bSMOOTHNESS = true; +#endif + } + void SetSMOOTHNESS( bool i ) + { + m_nSMOOTHNESS = i ? 1 : 0; +#ifdef _DEBUG + m_bSMOOTHNESS = true; +#endif + } +public: + vertexlitpbr_ps30_Static_Index( ) + { +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = false; +#endif // _DEBUG + m_nCONVERT_TO_SRGB = 0; +#ifdef _DEBUG + m_bFLASHLIGHT = false; +#endif // _DEBUG + m_nFLASHLIGHT = 0; +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bCUBEMAP_SPHERE_LEGACY = false; +#endif // _DEBUG + m_nCUBEMAP_SPHERE_LEGACY = 0; +#ifdef _DEBUG + m_bSMOOTHNESS = false; +#endif // _DEBUG + m_nSMOOTHNESS = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCONVERT_TO_SRGB && m_bFLASHLIGHT && m_bCUBEMAP && m_bCUBEMAP_SPHERE_LEGACY && m_bSMOOTHNESS; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 480 * m_nCONVERT_TO_SRGB ) + ( 480 * m_nFLASHLIGHT ) + ( 960 * m_nCUBEMAP ) + ( 1920 * m_nCUBEMAP_SPHERE_LEGACY ) + ( 3840 * m_nSMOOTHNESS ) + 0; + } +}; +#define shaderStaticTest_vertexlitpbr_ps30 psh_forgot_to_set_static_CONVERT_TO_SRGB + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + psh_forgot_to_set_static_SMOOTHNESS + 0 +class vertexlitpbr_ps30_Dynamic_Index +{ +private: + int m_nWRITEWATERFOGTODESTALPHA; +#ifdef _DEBUG + bool m_bWRITEWATERFOGTODESTALPHA; +#endif +public: + void SetWRITEWATERFOGTODESTALPHA( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nWRITEWATERFOGTODESTALPHA = i; +#ifdef _DEBUG + m_bWRITEWATERFOGTODESTALPHA = true; +#endif + } + void SetWRITEWATERFOGTODESTALPHA( bool i ) + { + m_nWRITEWATERFOGTODESTALPHA = i ? 1 : 0; +#ifdef _DEBUG + m_bWRITEWATERFOGTODESTALPHA = true; +#endif + } +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +private: + int m_nNUM_LIGHTS; +#ifdef _DEBUG + bool m_bNUM_LIGHTS; +#endif +public: + void SetNUM_LIGHTS( int i ) + { + Assert( i >= 0 && i <= 4 ); + m_nNUM_LIGHTS = i; +#ifdef _DEBUG + m_bNUM_LIGHTS = true; +#endif + } + void SetNUM_LIGHTS( bool i ) + { + m_nNUM_LIGHTS = i ? 1 : 0; +#ifdef _DEBUG + m_bNUM_LIGHTS = true; +#endif + } +private: + int m_nWRITE_DEPTH_TO_DESTALPHA; +#ifdef _DEBUG + bool m_bWRITE_DEPTH_TO_DESTALPHA; +#endif +public: + void SetWRITE_DEPTH_TO_DESTALPHA( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nWRITE_DEPTH_TO_DESTALPHA = i; +#ifdef _DEBUG + m_bWRITE_DEPTH_TO_DESTALPHA = true; +#endif + } + void SetWRITE_DEPTH_TO_DESTALPHA( bool i ) + { + m_nWRITE_DEPTH_TO_DESTALPHA = i ? 1 : 0; +#ifdef _DEBUG + m_bWRITE_DEPTH_TO_DESTALPHA = true; +#endif + } +private: + int m_nFLASHLIGHTSHADOWS; +#ifdef _DEBUG + bool m_bFLASHLIGHTSHADOWS; +#endif +public: + void SetFLASHLIGHTSHADOWS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLASHLIGHTSHADOWS = i; +#ifdef _DEBUG + m_bFLASHLIGHTSHADOWS = true; +#endif + } + void SetFLASHLIGHTSHADOWS( bool i ) + { + m_nFLASHLIGHTSHADOWS = i ? 1 : 0; +#ifdef _DEBUG + m_bFLASHLIGHTSHADOWS = true; +#endif + } +private: + int m_nLIGHTMAP; +#ifdef _DEBUG + bool m_bLIGHTMAP; +#endif +public: + void SetLIGHTMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nLIGHTMAP = i; +#ifdef _DEBUG + m_bLIGHTMAP = true; +#endif + } + void SetLIGHTMAP( bool i ) + { + m_nLIGHTMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bLIGHTMAP = true; +#endif + } +private: + int m_nLIGHT_PREVIEW; +#ifdef _DEBUG + bool m_bLIGHT_PREVIEW; +#endif +public: + void SetLIGHT_PREVIEW( int i ) + { + Assert( i >= 0 && i <= 2 ); + m_nLIGHT_PREVIEW = i; +#ifdef _DEBUG + m_bLIGHT_PREVIEW = true; +#endif + } + void SetLIGHT_PREVIEW( bool i ) + { + m_nLIGHT_PREVIEW = i ? 1 : 0; +#ifdef _DEBUG + m_bLIGHT_PREVIEW = true; +#endif + } +public: + vertexlitpbr_ps30_Dynamic_Index() + { +#ifdef _DEBUG + m_bWRITEWATERFOGTODESTALPHA = false; +#endif // _DEBUG + m_nWRITEWATERFOGTODESTALPHA = 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; +#ifdef _DEBUG + m_bNUM_LIGHTS = false; +#endif // _DEBUG + m_nNUM_LIGHTS = 0; +#ifdef _DEBUG + m_bWRITE_DEPTH_TO_DESTALPHA = false; +#endif // _DEBUG + m_nWRITE_DEPTH_TO_DESTALPHA = 0; +#ifdef _DEBUG + m_bFLASHLIGHTSHADOWS = false; +#endif // _DEBUG + m_nFLASHLIGHTSHADOWS = 0; +#ifdef _DEBUG + m_bLIGHTMAP = false; +#endif // _DEBUG + m_nLIGHTMAP = 0; +#ifdef _DEBUG + m_bLIGHT_PREVIEW = false; +#endif // _DEBUG + m_nLIGHT_PREVIEW = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bWRITEWATERFOGTODESTALPHA && m_bPIXELFOGTYPE && m_bNUM_LIGHTS && m_bWRITE_DEPTH_TO_DESTALPHA && m_bFLASHLIGHTSHADOWS && m_bLIGHTMAP && m_bLIGHT_PREVIEW; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nWRITEWATERFOGTODESTALPHA ) + ( 2 * m_nPIXELFOGTYPE ) + ( 4 * m_nNUM_LIGHTS ) + ( 20 * m_nWRITE_DEPTH_TO_DESTALPHA ) + ( 40 * m_nFLASHLIGHTSHADOWS ) + ( 80 * m_nLIGHTMAP ) + ( 160 * m_nLIGHT_PREVIEW ) + 0; + } +}; +#define shaderDynamicTest_vertexlitpbr_ps30 psh_forgot_to_set_dynamic_WRITEWATERFOGTODESTALPHA + psh_forgot_to_set_dynamic_PIXELFOGTYPE + psh_forgot_to_set_dynamic_NUM_LIGHTS + psh_forgot_to_set_dynamic_WRITE_DEPTH_TO_DESTALPHA + psh_forgot_to_set_dynamic_FLASHLIGHTSHADOWS + psh_forgot_to_set_dynamic_LIGHTMAP + psh_forgot_to_set_dynamic_LIGHT_PREVIEW + 0 diff --git a/materialsystem/stdshaders/fxctmp9/vertexlitPBR_vs30.inc b/materialsystem/stdshaders/fxctmp9/vertexlitPBR_vs30.inc new file mode 100644 index 0000000..f73364a --- /dev/null +++ b/materialsystem/stdshaders/fxctmp9/vertexlitPBR_vs30.inc @@ -0,0 +1,287 @@ +#include "shaderlib/cshader.h" +class vertexlitpbr_vs30_Static_Index +{ +private: + int m_nVERTEXCOLOR; +#ifdef _DEBUG + bool m_bVERTEXCOLOR; +#endif +public: + void SetVERTEXCOLOR( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nVERTEXCOLOR = i; +#ifdef _DEBUG + m_bVERTEXCOLOR = true; +#endif + } + void SetVERTEXCOLOR( bool i ) + { + m_nVERTEXCOLOR = i ? 1 : 0; +#ifdef _DEBUG + m_bVERTEXCOLOR = true; +#endif + } +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nDONT_GAMMA_CONVERT_VERTEX_COLOR; +#ifdef _DEBUG + bool m_bDONT_GAMMA_CONVERT_VERTEX_COLOR; +#endif +public: + void SetDONT_GAMMA_CONVERT_VERTEX_COLOR( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDONT_GAMMA_CONVERT_VERTEX_COLOR = i; +#ifdef _DEBUG + m_bDONT_GAMMA_CONVERT_VERTEX_COLOR = true; +#endif + } + void SetDONT_GAMMA_CONVERT_VERTEX_COLOR( bool i ) + { + m_nDONT_GAMMA_CONVERT_VERTEX_COLOR = i ? 1 : 0; +#ifdef _DEBUG + m_bDONT_GAMMA_CONVERT_VERTEX_COLOR = true; +#endif + } +public: + vertexlitpbr_vs30_Static_Index( ) + { +#ifdef _DEBUG + m_bVERTEXCOLOR = false; +#endif // _DEBUG + m_nVERTEXCOLOR = 0; +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bDONT_GAMMA_CONVERT_VERTEX_COLOR = false; +#endif // _DEBUG + m_nDONT_GAMMA_CONVERT_VERTEX_COLOR = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bVERTEXCOLOR && m_bCUBEMAP && m_bDONT_GAMMA_CONVERT_VERTEX_COLOR; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 320 * m_nVERTEXCOLOR ) + ( 640 * m_nCUBEMAP ) + ( 1280 * m_nDONT_GAMMA_CONVERT_VERTEX_COLOR ) + 0; + } +}; +#define shaderStaticTest_vertexlitpbr_vs30 vsh_forgot_to_set_static_VERTEXCOLOR + vsh_forgot_to_set_static_CUBEMAP + vsh_forgot_to_set_static_DONT_GAMMA_CONVERT_VERTEX_COLOR + 0 +class vertexlitpbr_vs30_Dynamic_Index +{ +private: + int m_nCOMPRESSED_VERTS; +#ifdef _DEBUG + bool m_bCOMPRESSED_VERTS; +#endif +public: + void SetCOMPRESSED_VERTS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCOMPRESSED_VERTS = i; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } + void SetCOMPRESSED_VERTS( bool i ) + { + m_nCOMPRESSED_VERTS = i ? 1 : 0; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } +private: + int m_nDOWATERFOG; +#ifdef _DEBUG + bool m_bDOWATERFOG; +#endif +public: + void SetDOWATERFOG( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDOWATERFOG = i; +#ifdef _DEBUG + m_bDOWATERFOG = true; +#endif + } + void SetDOWATERFOG( bool i ) + { + m_nDOWATERFOG = i ? 1 : 0; +#ifdef _DEBUG + m_bDOWATERFOG = true; +#endif + } +private: + int m_nSKINNING; +#ifdef _DEBUG + bool m_bSKINNING; +#endif +public: + void SetSKINNING( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSKINNING = i; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } + void SetSKINNING( bool i ) + { + m_nSKINNING = i ? 1 : 0; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } +private: + int m_nLIGHTING_PREVIEW; +#ifdef _DEBUG + bool m_bLIGHTING_PREVIEW; +#endif +public: + void SetLIGHTING_PREVIEW( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nLIGHTING_PREVIEW = i; +#ifdef _DEBUG + m_bLIGHTING_PREVIEW = true; +#endif + } + void SetLIGHTING_PREVIEW( bool i ) + { + m_nLIGHTING_PREVIEW = i ? 1 : 0; +#ifdef _DEBUG + m_bLIGHTING_PREVIEW = true; +#endif + } +private: + int m_nNUM_LIGHTS; +#ifdef _DEBUG + bool m_bNUM_LIGHTS; +#endif +public: + void SetNUM_LIGHTS( int i ) + { + Assert( i >= 0 && i <= 4 ); + m_nNUM_LIGHTS = i; +#ifdef _DEBUG + m_bNUM_LIGHTS = true; +#endif + } + void SetNUM_LIGHTS( bool i ) + { + m_nNUM_LIGHTS = i ? 1 : 0; +#ifdef _DEBUG + m_bNUM_LIGHTS = true; +#endif + } +private: + int m_nDYNAMIC_LIGHT; +#ifdef _DEBUG + bool m_bDYNAMIC_LIGHT; +#endif +public: + void SetDYNAMIC_LIGHT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nDYNAMIC_LIGHT = i; +#ifdef _DEBUG + m_bDYNAMIC_LIGHT = true; +#endif + } + void SetDYNAMIC_LIGHT( bool i ) + { + m_nDYNAMIC_LIGHT = i ? 1 : 0; +#ifdef _DEBUG + m_bDYNAMIC_LIGHT = true; +#endif + } +private: + int m_nSTATIC_LIGHT; +#ifdef _DEBUG + bool m_bSTATIC_LIGHT; +#endif +public: + void SetSTATIC_LIGHT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSTATIC_LIGHT = i; +#ifdef _DEBUG + m_bSTATIC_LIGHT = true; +#endif + } + void SetSTATIC_LIGHT( bool i ) + { + m_nSTATIC_LIGHT = i ? 1 : 0; +#ifdef _DEBUG + m_bSTATIC_LIGHT = true; +#endif + } +public: + vertexlitpbr_vs30_Dynamic_Index() + { +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = false; +#endif // _DEBUG + m_nCOMPRESSED_VERTS = 0; +#ifdef _DEBUG + m_bDOWATERFOG = false; +#endif // _DEBUG + m_nDOWATERFOG = 0; +#ifdef _DEBUG + m_bSKINNING = false; +#endif // _DEBUG + m_nSKINNING = 0; +#ifdef _DEBUG + m_bLIGHTING_PREVIEW = false; +#endif // _DEBUG + m_nLIGHTING_PREVIEW = 0; +#ifdef _DEBUG + m_bNUM_LIGHTS = false; +#endif // _DEBUG + m_nNUM_LIGHTS = 0; +#ifdef _DEBUG + m_bDYNAMIC_LIGHT = false; +#endif // _DEBUG + m_nDYNAMIC_LIGHT = 0; +#ifdef _DEBUG + m_bSTATIC_LIGHT = false; +#endif // _DEBUG + m_nSTATIC_LIGHT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bCOMPRESSED_VERTS && m_bDOWATERFOG && m_bSKINNING && m_bLIGHTING_PREVIEW && m_bNUM_LIGHTS && m_bDYNAMIC_LIGHT && m_bSTATIC_LIGHT; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nCOMPRESSED_VERTS ) + ( 2 * m_nDOWATERFOG ) + ( 4 * m_nSKINNING ) + ( 8 * m_nLIGHTING_PREVIEW ) + ( 16 * m_nNUM_LIGHTS ) + ( 80 * m_nDYNAMIC_LIGHT ) + ( 160 * m_nSTATIC_LIGHT ) + 0; + } +}; +#define shaderDynamicTest_vertexlitpbr_vs30 vsh_forgot_to_set_dynamic_COMPRESSED_VERTS + vsh_forgot_to_set_dynamic_DOWATERFOG + vsh_forgot_to_set_dynamic_SKINNING + vsh_forgot_to_set_dynamic_LIGHTING_PREVIEW + vsh_forgot_to_set_dynamic_NUM_LIGHTS + vsh_forgot_to_set_dynamic_DYNAMIC_LIGHT + vsh_forgot_to_set_dynamic_STATIC_LIGHT + 0 diff --git a/materialsystem/stdshaders/stdshader_dx9.vpc b/materialsystem/stdshaders/stdshader_dx9.vpc index 9715976..b9cd2aa 100644 --- a/materialsystem/stdshaders/stdshader_dx9.vpc +++ b/materialsystem/stdshaders/stdshader_dx9.vpc @@ -167,6 +167,8 @@ $Project "stdshader_dx9" $File "worldvertextransition_dx8_helper.cpp" $File "writez_dx9.cpp" $File "writestencil_dx9.cpp" + $File "vertexlitPBR_dx9.cpp" + $File "vertexlitPBR_dx9_helper.cpp" $Folder "Remove me when VAC2 is out" [$WIN32] { diff --git a/materialsystem/stdshaders/stdshader_dx9_30.txt b/materialsystem/stdshaders/stdshader_dx9_30.txt index 0b9a0d4..8b9e2ca 100644 --- a/materialsystem/stdshaders/stdshader_dx9_30.txt +++ b/materialsystem/stdshaders/stdshader_dx9_30.txt @@ -51,4 +51,6 @@ warp_vs20.fxc weapon_sheen_pass_vs20.fxc weapon_sheen_pass_ps2x.fxc depthwrite_ps2x.fxc -depthwrite_vs20.fxc \ No newline at end of file +depthwrite_vs20.fxc +vertexlitPBR_ps30.fxc +vertexlitPBR_vs30.fxc \ No newline at end of file diff --git a/materialsystem/stdshaders/vertexlitPBR_ps30.fxc b/materialsystem/stdshaders/vertexlitPBR_ps30.fxc new file mode 100644 index 0000000..776c188 --- /dev/null +++ b/materialsystem/stdshaders/vertexlitPBR_ps30.fxc @@ -0,0 +1,350 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// Example pixel shader that can be applied to models +// +//================================================================================================== + + +// STATIC: "CONVERT_TO_SRGB" "0..0" +// STATIC: "FLASHLIGHT" "0..1" +// STATIC: "CUBEMAP" "0..1" +// STATIC: "CUBEMAP_SPHERE_LEGACY" "0..1" +// STATIC: "SMOOTHNESS" "0..1" + +// DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1" +// DYNAMIC: "PIXELFOGTYPE" "0..1" +// DYNAMIC: "NUM_LIGHTS" "0..4" +// DYNAMIC: "WRITE_DEPTH_TO_DESTALPHA" "0..1" +// DYNAMIC: "FLASHLIGHTSHADOWS" "0..1" +// DYNAMIC: "LIGHTMAP" "0..1" +// DYNAMIC: "LIGHT_PREVIEW" "0..2" + +// We don't care about those in the editor +// SKIP: ($CUBEMAP || FLASHLIGHT ) && $LIGHT_PREVIEW + +// SKIP: ($PIXELFOGTYPE == 0) && ($WRITEWATERFOGTODESTALPHA != 0) + +// We don't care about flashlight depth unless the flashlight is on +// SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) + +// SKIP: ( $CUBEMAP == 1 ) && ( $FLASHLIGHT == 1 ) + +// SKIP: $CUBEMAP_SPHERE_LEGACY && ($CUBEMAP == 0) + +// SKIP: ($CUBEMAP || FLASHLIGHT ) + +#include "common_flashlight_fxc.h" +#include "shader_constant_register_map.h" +#include "common_pbr.h" + +#ifdef NV3X + #define PSHADER_VECT_SCALE 20.0 + #define VSHADER_VECT_SCALE (1.0 / (PSHADER_VECT_SCALE) ) +#else + #define PSHADER_VECT_SCALE 1.0 + #define VSHADER_VECT_SCALE 1.0 +#endif + +const float4 g_DiffuseModulation : register( PSREG_DIFFUSE_MODULATION ); +const float4 g_ShadowTweaks : register( PSREG_ENVMAP_TINT__SHADOW_TWEAKS ); +const float3 cAmbientCube[6] : register( PSREG_AMBIENT_CUBE ); +const float4 g_EyePos : register( PSREG_EYEPOS_SPEC_EXPONENT ); +const float4 g_FogParams : register( PSREG_FOG_PARAMS ); +#if FLASHLIGHT == 1 +sampler ShadowDepthSampler : register( s4 ); // Flashlight shadow depth map sampler +sampler NormalizeRandRotSampler : register( s5 ); // Normalization / RandomRotation samplers +sampler FlashlightSampler : register( s6 ); // Flashlight cookie + +const float4 g_FlashlightAttenuationFactors : register( PSREG_FLASHLIGHT_ATTENUATION ); // On non-flashlight pass +const float4 g_FlashlightPos_RimBoost : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST ); +const float4 g_FlashlightColor : register( PSREG_FLASHLIGHT_COLOR ); +const float4x4 g_FlashlightWorldToTexture : register( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE ); +#endif +PixelShaderLightInfo cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // 2 registers each - 6 registers total (4th light spread across w's) + +#define g_FlashlightPos g_FlashlightPos_RimBoost.xyz + +sampler BaseTextureSampler : register( s0 ); // Base map, selfillum in alpha +sampler RoughnessSampler : register( s1 ); // Roughness +sampler MetallicSampler : register( s2 ); // Metallic +sampler BumpmapSampler : register( s3 ); // Bump map + + + +sampler EnvmapSampler : register( s7 ); // for IBL +sampler BRDFSampler : register( s8 ); // for IBL +sampler AOSampler : register( s9 ); // AO +sampler EmissiveSampler : register( s10 ); // Emissive map +sampler LightmapSampler : register( s11 ); // Lightmap texture from the engine + +//DoPBRLight(float3 vWorldPos, float3 vWorldNormal, float3 albedo, float3 vPosition, float3 vColor, float3 vEye, float atten_radius, float3 metallic, float3 roughness) +float3 DoPBRLights(float3 vEye, float3 vWorldNormal, float3 vWorldPos, float4 albedo, float4 atten, float3 lightmap, float metallic, float roughness) +{ + float3 linearColor = 0.0; + +#if LIGHTMAP ==0 + if ( NUM_LIGHTS > 0 ) + { + linearColor += DoPBRLight(vWorldPos, vWorldNormal, albedo, cLightInfo[0].pos, cLightInfo[0].color.rgb, vEye, atten.x, metallic, roughness); + if ( NUM_LIGHTS > 1 ) + { + linearColor += DoPBRLight( vWorldPos, vWorldNormal, albedo, cLightInfo[1].pos, cLightInfo[1].color.rgb, vEye, atten.x, metallic, roughness); + if ( NUM_LIGHTS > 2 ) + { + linearColor += DoPBRLight( vWorldPos, vWorldNormal, albedo, cLightInfo[2].pos, cLightInfo[2].color.rgb, vEye, atten.x, metallic, roughness); + if ( NUM_LIGHTS > 3 ) + { + // Unpack the 4th light's data from tight constant packing + float3 vLight3Color = float3( cLightInfo[0].color.w, cLightInfo[0].pos.w, cLightInfo[1].color.w ); + float3 vLight3Pos = float3( cLightInfo[1].pos.w, cLightInfo[2].color.w, cLightInfo[2].pos.w ); + linearColor += DoPBRLight( vWorldPos, vWorldNormal, albedo, vLight3Pos, vLight3Color, vEye, atten.x, metallic, roughness); + } + } + } + } + #else + if ( NUM_LIGHTS > 0 ) + { + float lightmap_atten = dot(lightmap, cLightInfo[0].color.rgb); + lightmap_atten = lightmap_atten * lightmap_atten * 2.0f; + linearColor += DoPBRLight(vWorldPos, vWorldNormal, albedo, cLightInfo[0].pos, cLightInfo[0].color.rgb, vEye, lightmap_atten, metallic, roughness); + if ( NUM_LIGHTS > 1 ) + { + lightmap_atten = dot(lightmap, cLightInfo[1].color.rgb); + lightmap_atten = lightmap_atten * lightmap_atten * 2.0f; + linearColor += DoPBRLight( vWorldPos, vWorldNormal, albedo, cLightInfo[1].pos, cLightInfo[1].color.rgb, vEye, lightmap_atten, metallic, roughness); + if ( NUM_LIGHTS > 2 ) + { + lightmap_atten = dot(lightmap, cLightInfo[2].color.rgb); + lightmap_atten = lightmap_atten * lightmap_atten * 2.0f; + linearColor += DoPBRLight( vWorldPos, vWorldNormal, albedo, cLightInfo[2].pos, cLightInfo[2].color.rgb, vEye,lightmap_atten, metallic, roughness); + if ( NUM_LIGHTS > 3 ) + { + // Unpack the 4th light's data from tight constant packing + float3 vLight3Color = float3( cLightInfo[0].color.w, cLightInfo[0].pos.w, cLightInfo[1].color.w ); + float3 vLight3Pos = float3( cLightInfo[1].pos.w, cLightInfo[2].color.w, cLightInfo[2].pos.w ); + lightmap_atten = dot(lightmap, vLight3Color); + lightmap_atten = lightmap_atten * lightmap_atten * 2.0f; + linearColor += DoPBRLight( vWorldPos, vWorldNormal, albedo, vLight3Pos, vLight3Color, vEye, lightmap_atten, metallic, roughness); + } + } + } + } + #endif + + return linearColor; +} + +// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile +half3 EnvBRDFApprox( half3 SpecularColor, half Roughness, half NoV ) +{ + const half4 c0 = { -1, -0.0275, -0.572, 0.022 }; + const half4 c1 = { 1, 0.0425, 1.04, -0.04 }; + half4 r = Roughness * c0 + c1; + half a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y; + half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw; + return SpecularColor * AB.x + AB.y; +} + +float3 fresnelSchlickRoughness(float cosTheta, float3 F0, float roughness) +{ + return F0 + (max(1.0f.xxx - roughness, F0) - F0) * pow(1.0 - cosTheta, 5.0); +} + +float3 DoIBL(float3 vEye, float3 vWorldNormal, float3 vWorldPos, float2 screenUV, float3 albedo, float metallness, float roughness, float3 lightmap) +{ + float3 metallic = clamp(metallness, 0.0f, 0.9f); +#if CUBEMAP == 1 + float3 V = normalize( vEye - vWorldPos ); + float3 N = normalize( vWorldNormal ); + + //precompute dots + float NV = max(0.0,dot(N, V)); + + HALF3 reflectVect = 2.0 * NV * N - V; + float4 directionPosX = { 1.0f, 0.01f, 0.01f, 12.0f }; float4 directionNegX = {-1.0f, 0.01f, 0.01f, 12.0f }; + float4 directionPosY = { 0.01f, 1.0f, 0.01f, 12.0f }; float4 directionNegY = { 0.01f,-1.0f, 0.01f, 12.0f }; + float4 directionPosZ = { 0.01f, 0.01f, 1.0f, 12.0f }; float4 directionNegZ = { 0.01f, 0.01f,-1.0f, 12.0f }; + float3 lookupPosX = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionPosX); + float3 lookupNegX = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionNegX); + float3 lookupPosY = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionPosY); + float3 lookupNegY = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionNegY); + float3 lookupPosZ = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionPosZ); + float3 lookupNegZ = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionNegZ); + float3 envmapCube[6] = { lookupPosX, lookupNegX, lookupPosY, lookupNegY, lookupPosZ, lookupNegZ }; + +#if LIGHTMAP == 0 + float3 irradiance = PixelShaderAmbientLight( N, cAmbientCube ); +#else + float3 irradiance = lightmap; +#endif + + float3 f0 = 0.04f.xxx; + f0 = lerp(f0, albedo.rgb, metallic); + float3 F = fresnelSchlickRoughness(NV, f0, roughness); // ambient Lighting Fresnel Term + + half3 BRDF = EnvBRDFApprox(f0, roughness, NV); + + float3 kD = 1.0f.xxx - F; + kD *= 1.0 - metallic; + + float3 diffuseIBL = kD * albedo * irradiance; + float3 lookup = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, float4(reflectVect, roughness * 12.0)).rgb; + float3 specularIrradiance = lerp(lookup, PixelShaderAmbientLight( reflectVect, envmapCube ), roughness * roughness ); + float3 specularIBL = BRDF * specularIrradiance; + //mix + return max(0.0, diffuseIBL + specularIBL); +#else + + float3 V = normalize( vEye - vWorldPos ); + float3 N = normalize( vWorldNormal ); + + //precompute dots + float NV = max(0.0,dot(N, V)); + +#if LIGHTMAP == 0 + float3 irradiance = PixelShaderAmbientLight( N, cAmbientCube ); +#else + float3 irradiance = lightmap; +#endif + + float3 f0 = 0.04f.xxx; + f0 = lerp(f0, albedo.rgb, metallic); + float3 F = fresnelSchlickRoughness(NV, f0, roughness); // ambient Lighting Fresnel Term + + float3 kD = 1.0f.xxx - F; + kD *= 1.0 - metallic; + + float3 diffuseIBL = kD * albedo * irradiance; + + return max(0.0, diffuseIBL); +#endif +} + +#if FLASHLIGHT == 1 +float3 DoFlashlight(float3 vWorldNormal, float3 vWorldPos, float2 vScreenCords, float3 albedo, float metallic, float roughness) +{ + float4 flashlightSpacePosition = mul( float4(vWorldPos, 1.0f ), g_FlashlightWorldToTexture ); + float3 vProjCoords = flashlightSpacePosition.xyz / flashlightSpacePosition.w; + float3 flashlightColor = tex2D( FlashlightSampler, vProjCoords); + float3 shadow = 1.0f; + #if FLASHLIGHTSHADOWS + shadow = DoFlashlightShadow( ShadowDepthSampler, NormalizeRandRotSampler, vProjCoords, vScreenCords, 0, g_ShadowTweaks, false ); + //shadow = tex2DprojBicubic(ShadowDepthSampler, 512.0f.xx, vProjCoords.xy, vProjCoords.z); + #endif + float2 dist = float2(length(g_FlashlightPos_RimBoost.xyz - vWorldPos), dot(g_FlashlightPos_RimBoost.xyz - vWorldPos,g_FlashlightPos_RimBoost.xyz - vWorldPos)); + float fAtten = saturate( dot( g_FlashlightAttenuationFactors.xyz, float3( 1.0f, 1.0f/dist.x, 1.0f/dist.y ) ) ); + float3 light = DoPBRLight( vWorldPos, vWorldNormal, albedo, g_FlashlightPos_RimBoost.xyz, flashlightColor.rgb * g_FlashlightColor.xyz, g_EyePos.xyz, shadow * fAtten * g_FlashlightColor.w, metallic, roughness); + return light; +} +#endif + +struct PS_INPUT +{ + float2 baseTexCoord : TEXCOORD0; + float4 lightAtten : TEXCOORD1; + float3 worldNormal : TEXCOORD2; + float3 worldPos : TEXCOORD3; + float4 projPos : TEXCOORD4; + float4 color : TEXCOORD5; + float3 localPos : TEXCOORD6; // for Irradiance calculations + float4 vWorldTangent: TEXCOORD7; + float3 vWorldBinormal: TEXCOORD8; +}; + +struct PS_OUTPUT +{ + float4 MainOut : COLOR0; + float4 Normal : COLOR1; + float4 MRAO : COLOR2; + float4 Albedo : COLOR3; +}; + +#if LIGHT_PREVIEW == 2 +LPREVIEW_PS_OUT main( PS_INPUT i ) : COLOR +#elif LIGHT_PREVIEW == 1 +HALF4 main(PS_INPUT i) : COLOR +#else +PS_OUTPUT main(PS_INPUT i) : COLOR +#endif +{ + float2 UV = i.baseTexCoord; + float2 screenUV = i.projPos.xy / i.projPos.w; + screenUV = screenUV * 0.5f + 0.5f; + float4 baseColor = tex2D( BaseTextureSampler, UV ); + +#if SMOOTHNESS == 0 + float roughnessMap = tex2D( RoughnessSampler, UV ); +#else + float roughnessMap = 1.0f - tex2D( RoughnessSampler, UV ); +#endif + + float metallicMap = tex2D( MetallicSampler, UV ); + float AOSample = tex2D( AOSampler, UV ); + float3 EmissiveSample = tex2D( EmissiveSampler, UV ); + float4 normalTexel = tex2D( BumpmapSampler, UV); + float3 lightmapTexel = GammaToLinear( 2.0f * tex2D( LightmapSampler, UV ).rgb ); + + float3 worldPos = i.worldPos; + float3 worldNormal = i.worldNormal; + float3 eyeToWorld = (g_EyePos - worldPos); + float3 albedo = g_DiffuseModulation.rgb * baseColor.rgb; + bool bCubemap = (CUBEMAP) ? true : false; + + float3 tangentSpaceNormal = normalTexel * 2.0f - 1.0f; + float3 vWorldBinormal = i.vWorldBinormal; + + float3 vWorldNormal = Vec3TangentToWorld( tangentSpaceNormal, worldNormal, i.vWorldTangent, vWorldBinormal ); + vWorldNormal = normalize( vWorldNormal ); + + float3 projPos = i.projPos.xyz; + float3 Lighting = float(0.0).xxx; + +#if LIGHMAP == 0 + // Summation of diffuse illumination from all local lights + Lighting = DoPBRLights(g_EyePos.xyz, vWorldNormal, worldPos, baseColor, i.lightAtten, lightmapTexel, metallicMap, roughnessMap); +#endif + float3 IBL = DoIBL(g_EyePos.xyz, vWorldNormal, worldPos, screenUV, baseColor.rgb, metallicMap, roughnessMap, lightmapTexel); +#if FLASHLIGHT + float3 Flashlight = DoFlashlight(vWorldNormal, worldPos, i.projPos.xy / i.projPos.w, baseColor.rgb, metallicMap, roughnessMap); +#endif + + float3 result = ( +#if FLASHLIGHT + Flashlight); +#else + Lighting + IBL * AOSample) + EmissiveSample; +#endif + float alpha = baseColor.a * g_DiffuseModulation.a; + + float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos.z, i.worldPos.z, i.projPos.z ); + +#if WRITEWATERFOGTODESTALPHA && ( PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT ) + alpha = fogFactor; +#endif + +#if LIGHT_PREVIEW == 1 + result = DoPBRLight(worldPos, vWorldNormal, baseColor, g_EyePos.xyz, 1.0f.xxx, g_EyePos.xyz, 5.0f, metallicMap, roughnessMap); + bool bWriteDepthToAlpha = ( WRITE_DEPTH_TO_DESTALPHA != 0 ) && ( WRITEWATERFOGTODESTALPHA == 0 ); + return FinalOutput( float4( result, alpha), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, bWriteDepthToAlpha, i.projPos.z ); +#elif LIGHT_PREVIEW == 2 + LPREVIEW_PS_OUT Output; + Output.color = float4( baseColor.xyz,alpha ); + Output.normal = float4( vWorldNormal,alpha ); + Output.position = float4( worldPos, alpha ); + Output.flags = float4( 1.0f - metallicMap, roughnessMap, 1, alpha ); + return FinalOutput( Output, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE ); +#else + + PS_OUTPUT output = (PS_OUTPUT) 0; + + bool bWriteDepthToAlpha = ( WRITE_DEPTH_TO_DESTALPHA != 0 ) && ( WRITEWATERFOGTODESTALPHA == 0 ); + output.MainOut = FinalOutput(float4(result, alpha), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, bWriteDepthToAlpha, i.projPos.z); +#if !FLASHLIGHT + output.Normal = float4(vWorldNormal.xyz, i.projPos.z / i.projPos.w); + output.MRAO = float4(metallicMap, roughnessMap, AOSample, 0.0f); + output.Albedo = float4(baseColor.xyz, 1.0f); +#endif + return output; +#endif +} diff --git a/materialsystem/stdshaders/vertexlitPBR_vs30.fxc b/materialsystem/stdshaders/vertexlitPBR_vs30.fxc new file mode 100644 index 0000000..4bd0236 --- /dev/null +++ b/materialsystem/stdshaders/vertexlitPBR_vs30.fxc @@ -0,0 +1,131 @@ +//===================== Copyright (c) Valve Corporation. All Rights Reserved. ====================== +// +// Example vertex shader that can be applied to models +// +//================================================================================================== + + +// STATIC: "VERTEXCOLOR" "0..1" +// STATIC: "CUBEMAP" "0..1" +// STATIC: "DONT_GAMMA_CONVERT_VERTEX_COLOR" "0..1" + +// DYNAMIC: "COMPRESSED_VERTS" "0..1" +// DYNAMIC: "DOWATERFOG" "0..1" +// DYNAMIC: "SKINNING" "0..1" +// DYNAMIC: "LIGHTING_PREVIEW" "0..1" +// DYNAMIC: "NUM_LIGHTS" "0..4" +// DYNAMIC: "DYNAMIC_LIGHT" "0..1" +// DYNAMIC: "STATIC_LIGHT" "0..1" + +#include "common_vs_fxc.h" + +static const bool g_bSkinning = SKINNING ? true : false; +static const bool g_bVertexColor = VERTEXCOLOR ? true : false; +static const int g_FogType = DOWATERFOG; + +const float4 cBaseTexCoordTransform[2] : register( SHADER_SPECIFIC_CONST_0 ); + +//----------------------------------------------------------------------------- +// Input vertex format +//----------------------------------------------------------------------------- +struct VS_INPUT +{ + // This is all of the stuff that we ever use. + float4 vPos : POSITION; + float4 vBoneWeights : BLENDWEIGHT; + float4 vBoneIndices : BLENDINDICES; + float4 vNormal : NORMAL; + float2 vTexCoord0 : TEXCOORD0; + float4 vColor : COLOR0; + float3 vTangentS : TANGENT; + float3 vTangentT : BINORMAL; + float4 vUserData : TANGENT; +}; + +struct VS_OUTPUT +{ + // Stuff that isn't seen by the pixel shader + float4 projPosSetup : POSITION; + float fog : FOG; + // Stuff that is seen by the pixel shader + float2 baseTexCoord : TEXCOORD0; + float4 lightAtten : TEXCOORD1; + float3 worldNormal : TEXCOORD2; + float3 worldPos : TEXCOORD3; + float4 projPos : TEXCOORD4; + float4 color : TEXCOORD5; // Vertex color (from lighting or unlit) + float3 localPos : TEXCOORD6; // for Irradiance calculations + float4 vWorldTangent : TEXCOORD7; + float3 vWorldBinormal : TEXCOORD8; +}; + +//----------------------------------------------------------------------------- +// Main shader entry point +//----------------------------------------------------------------------------- +VS_OUTPUT main( const VS_INPUT v ) +{ + VS_OUTPUT o = ( VS_OUTPUT )0; + + bool bDynamicLight = DYNAMIC_LIGHT ? true : false; + bool bStaticLight = STATIC_LIGHT ? true : false; + bool bDoLighting = !g_bVertexColor && (bDynamicLight || bStaticLight); + + float4 vPosition = v.vPos; + float3 vNormal; + float4 vTangent; + DecompressVertex_NormalTangent( v.vNormal, v.vUserData, vNormal, vTangent ); + + // Perform skinning + float3 worldNormal, worldPos, worldTangentS, worldTangentT; + SkinPositionNormalAndTangentSpace( g_bSkinning, vPosition, vNormal, vTangent, + v.vBoneWeights, v.vBoneIndices, worldPos, + worldNormal, worldTangentS, worldTangentT ); + + // Always normalize since flex path is controlled by runtime + // constant not a shader combo and will always generate the normalization + worldNormal = normalize( worldNormal ); + worldTangentS = normalize( worldTangentS ); + worldTangentT = normalize( worldTangentT ); + + // Transform into projection space + float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj ); + o.projPosSetup = vProjPos; + vProjPos.z = dot( float4( worldPos, 1 ), cViewProjZ ); + + o.projPos = vProjPos; + o.fog = CalcFog( worldPos, vProjPos.xyz, g_FogType ); + + // Needed for water fog alpha and diffuse lighting + o.worldPos = worldPos; + o.worldNormal.xyz = worldNormal.xyz; + o.vWorldTangent = float4( worldTangentS.xyz, vTangent.w ); // Propagate binormal sign in world tangent.w + o.vWorldBinormal.xyz = worldTangentT.xyz; + + if ( g_bVertexColor ) + { + // Assume that this is unlitgeneric if you are using vertex color. + o.color.rgb = ( DONT_GAMMA_CONVERT_VERTEX_COLOR ) ? v.vColor.rgb : GammaToLinear( v.vColor.rgb ); + o.color.a = v.vColor.a; + } + + // Scalar attenuations for four lights + o.lightAtten.xyz = float4(0,0,0,0); + #if ( NUM_LIGHTS > 0 ) + o.lightAtten.x = GetVertexAttenForLight( worldPos, 0, false ); + #endif + #if ( NUM_LIGHTS > 1 ) + o.lightAtten.y = GetVertexAttenForLight( worldPos, 1, false ); + #endif + #if ( NUM_LIGHTS > 2 ) + o.lightAtten.z = GetVertexAttenForLight( worldPos, 2, false ); + #endif + #if ( NUM_LIGHTS > 3 ) + o.lightAtten.w = GetVertexAttenForLight( worldPos, 3, false ); + #endif + + // Base texture coordinate transform + o.baseTexCoord.x = dot( v.vTexCoord0, cBaseTexCoordTransform[0] ); + o.baseTexCoord.y = dot( v.vTexCoord0, cBaseTexCoordTransform[1] ); + + return o; +}