You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
617 lines
26 KiB
617 lines
26 KiB
2 years ago
|
//==================================================================================================
|
||
|
//
|
||
|
// Physically Based Rendering shader for brushes and models
|
||
|
//
|
||
|
//==================================================================================================
|
||
|
|
||
|
// Includes for all shaders
|
||
|
#include "BaseVSShader.h"
|
||
|
#include "cpp_shader_constant_register_map.h"
|
||
|
|
||
|
// Includes for PS30
|
||
|
#include "pbr_vs30.inc"
|
||
|
#include "pbr_ps30.inc"
|
||
|
|
||
|
// Includes for PS20b
|
||
|
#include "pbr_vs20b.inc"
|
||
|
#include "pbr_ps20b.inc"
|
||
|
|
||
|
// Defining samplers
|
||
|
const Sampler_t SAMPLER_BASETEXTURE = SHADER_SAMPLER0;
|
||
|
const Sampler_t SAMPLER_NORMAL = SHADER_SAMPLER1;
|
||
|
const Sampler_t SAMPLER_ENVMAP = SHADER_SAMPLER2;
|
||
|
const Sampler_t SAMPLER_SHADOWDEPTH = SHADER_SAMPLER4;
|
||
|
const Sampler_t SAMPLER_RANDOMROTATION = SHADER_SAMPLER5;
|
||
|
const Sampler_t SAMPLER_FLASHLIGHT = SHADER_SAMPLER6;
|
||
|
const Sampler_t SAMPLER_LIGHTMAP = SHADER_SAMPLER7;
|
||
|
const Sampler_t SAMPLER_MRAO = SHADER_SAMPLER10;
|
||
|
const Sampler_t SAMPLER_EMISSIVE = SHADER_SAMPLER11;
|
||
|
const Sampler_t SAMPLER_SPECULAR = SHADER_SAMPLER12;
|
||
|
|
||
|
// Convars
|
||
|
static ConVar mat_fullbright("mat_fullbright", "0", FCVAR_CHEAT);
|
||
|
static ConVar mat_specular("mat_specular", "1", FCVAR_CHEAT);
|
||
|
static ConVar mat_pbr_force_20b("mat_pbr_force_20b", "0", FCVAR_CHEAT);
|
||
|
static ConVar mat_pbr_parallaxmap("mat_pbr_parallaxmap", "1");
|
||
|
|
||
|
// Variables for this shader
|
||
|
struct PBR_Vars_t
|
||
|
{
|
||
|
PBR_Vars_t()
|
||
|
{
|
||
|
memset(this, 0xFF, sizeof(*this));
|
||
|
}
|
||
|
|
||
|
int baseTexture;
|
||
|
int baseColor;
|
||
|
int normalTexture;
|
||
|
int bumpMap;
|
||
|
int envMap;
|
||
|
int baseTextureFrame;
|
||
|
int baseTextureTransform;
|
||
|
int useParallax;
|
||
|
int parallaxDepth;
|
||
|
int parallaxCenter;
|
||
|
int alphaTestReference;
|
||
|
int flashlightTexture;
|
||
|
int flashlightTextureFrame;
|
||
|
int emissionTexture;
|
||
|
int mraoTexture;
|
||
|
int useEnvAmbient;
|
||
|
int specularTexture;
|
||
|
};
|
||
|
|
||
|
// Beginning the shader
|
||
|
BEGIN_VS_SHADER(PBR, "PBR shader")
|
||
|
|
||
|
// Setting up vmt parameters
|
||
|
BEGIN_SHADER_PARAMS;
|
||
|
SHADER_PARAM(ALPHATESTREFERENCE, SHADER_PARAM_TYPE_FLOAT, "0", "");
|
||
|
SHADER_PARAM(ENVMAP, SHADER_PARAM_TYPE_ENVMAP, "", "Set the cubemap for this material.");
|
||
|
SHADER_PARAM(MRAOTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "Texture with metalness in R, roughness in G, ambient occlusion in B.");
|
||
|
SHADER_PARAM(EMISSIONTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "Emission texture");
|
||
|
SHADER_PARAM(NORMALTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "Normal texture (deprecated, use $bumpmap)");
|
||
|
SHADER_PARAM(BUMPMAP, SHADER_PARAM_TYPE_TEXTURE, "", "Normal texture");
|
||
|
SHADER_PARAM(USEENVAMBIENT, SHADER_PARAM_TYPE_BOOL, "0", "Use the cubemaps to compute ambient light.");
|
||
|
SHADER_PARAM(SPECULARTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "Specular F0 RGB map");
|
||
|
SHADER_PARAM(PARALLAX, SHADER_PARAM_TYPE_BOOL, "0", "Use Parallax Occlusion Mapping.");
|
||
|
SHADER_PARAM(PARALLAXDEPTH, SHADER_PARAM_TYPE_FLOAT, "0.0030", "Depth of the Parallax Map");
|
||
|
SHADER_PARAM(PARALLAXCENTER, SHADER_PARAM_TYPE_FLOAT, "0.5", "Center depth of the Parallax Map");
|
||
|
END_SHADER_PARAMS;
|
||
|
|
||
|
// Setting up variables for this shader
|
||
|
void SetupVars(PBR_Vars_t &info)
|
||
|
{
|
||
|
info.baseTexture = BASETEXTURE;
|
||
|
info.baseColor = COLOR;
|
||
|
info.normalTexture = NORMALTEXTURE;
|
||
|
info.bumpMap = BUMPMAP;
|
||
|
info.baseTextureFrame = FRAME;
|
||
|
info.baseTextureTransform = BASETEXTURETRANSFORM;
|
||
|
info.alphaTestReference = ALPHATESTREFERENCE;
|
||
|
info.flashlightTexture = FLASHLIGHTTEXTURE;
|
||
|
info.flashlightTextureFrame = FLASHLIGHTTEXTUREFRAME;
|
||
|
info.envMap = ENVMAP;
|
||
|
info.emissionTexture = EMISSIONTEXTURE;
|
||
|
info.mraoTexture = MRAOTEXTURE;
|
||
|
info.useEnvAmbient = USEENVAMBIENT;
|
||
|
info.specularTexture = SPECULARTEXTURE;
|
||
|
info.useParallax = PARALLAX;
|
||
|
info.parallaxDepth = PARALLAXDEPTH;
|
||
|
info.parallaxCenter = PARALLAXCENTER;
|
||
|
};
|
||
|
|
||
|
// Initializing parameters
|
||
|
SHADER_INIT_PARAMS()
|
||
|
{
|
||
|
// Fallback for changed parameter
|
||
|
if (params[NORMALTEXTURE]->IsDefined())
|
||
|
params[BUMPMAP]->SetStringValue(params[NORMALTEXTURE]->GetStringValue());
|
||
|
|
||
|
// Dynamic lights need a bumpmap
|
||
|
if (!params[BUMPMAP]->IsDefined())
|
||
|
params[BUMPMAP]->SetStringValue("dev/flat_normal");
|
||
|
|
||
|
// Set a good default mrao texture
|
||
|
if (!params[MRAOTEXTURE]->IsDefined())
|
||
|
params[MRAOTEXTURE]->SetStringValue("dev/pbr_mraotexture");
|
||
|
|
||
|
// PBR relies heavily on envmaps
|
||
|
if (!params[ENVMAP]->IsDefined())
|
||
|
params[ENVMAP]->SetStringValue("env_cubemap");
|
||
|
|
||
|
// Check if the hardware supports flashlight border color
|
||
|
if (g_pHardwareConfig->SupportsBorderColor())
|
||
|
{
|
||
|
params[FLASHLIGHTTEXTURE]->SetStringValue("effects/flashlight_border");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
params[FLASHLIGHTTEXTURE]->SetStringValue("effects/flashlight001");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Define shader fallback
|
||
|
SHADER_FALLBACK
|
||
|
{
|
||
|
return 0;
|
||
|
};
|
||
|
|
||
|
SHADER_INIT
|
||
|
{
|
||
|
PBR_Vars_t info;
|
||
|
SetupVars(info);
|
||
|
|
||
|
Assert(info.flashlightTexture >= 0);
|
||
|
LoadTexture(info.flashlightTexture, TEXTUREFLAGS_SRGB);
|
||
|
|
||
|
Assert(info.bumpMap >= 0);
|
||
|
LoadBumpMap(info.bumpMap);
|
||
|
|
||
|
Assert(info.envMap >= 0);
|
||
|
int envMapFlags = g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ? TEXTUREFLAGS_SRGB : 0;
|
||
|
envMapFlags |= TEXTUREFLAGS_ALL_MIPS;
|
||
|
LoadCubeMap(info.envMap, envMapFlags);
|
||
|
|
||
|
if (info.emissionTexture >= 0 && params[EMISSIONTEXTURE]->IsDefined())
|
||
|
LoadTexture(info.emissionTexture, TEXTUREFLAGS_SRGB);
|
||
|
|
||
|
Assert(info.mraoTexture >= 0);
|
||
|
LoadTexture(info.mraoTexture, 0);
|
||
|
|
||
|
if (params[info.baseTexture]->IsDefined())
|
||
|
{
|
||
|
LoadTexture(info.baseTexture, TEXTUREFLAGS_SRGB);
|
||
|
}
|
||
|
|
||
|
if (params[info.specularTexture]->IsDefined())
|
||
|
{
|
||
|
LoadTexture(info.specularTexture, TEXTUREFLAGS_SRGB);
|
||
|
}
|
||
|
|
||
|
if (IS_FLAG_SET(MATERIAL_VAR_MODEL)) // Set material var2 flags specific to models
|
||
|
{
|
||
|
SET_FLAGS2(MATERIAL_VAR2_SUPPORTS_HW_SKINNING); // Required for skinning
|
||
|
SET_FLAGS2(MATERIAL_VAR2_DIFFUSE_BUMPMAPPED_MODEL); // Required for dynamic lighting
|
||
|
SET_FLAGS2(MATERIAL_VAR2_NEEDS_TANGENT_SPACES); // Required for dynamic lighting
|
||
|
SET_FLAGS2(MATERIAL_VAR2_LIGHTING_VERTEX_LIT); // Required for dynamic lighting
|
||
|
SET_FLAGS2(MATERIAL_VAR2_NEEDS_BAKED_LIGHTING_SNAPSHOTS); // Required for ambient cube
|
||
|
SET_FLAGS2(MATERIAL_VAR2_SUPPORTS_FLASHLIGHT); // Required for flashlight
|
||
|
SET_FLAGS2(MATERIAL_VAR2_USE_FLASHLIGHT); // Required for flashlight
|
||
|
}
|
||
|
else // Set material var2 flags specific to brushes
|
||
|
{
|
||
|
SET_FLAGS2(MATERIAL_VAR2_LIGHTING_LIGHTMAP); // Required for lightmaps
|
||
|
SET_FLAGS2(MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP); // Required for lightmaps
|
||
|
SET_FLAGS2(MATERIAL_VAR2_SUPPORTS_FLASHLIGHT); // Required for flashlight
|
||
|
SET_FLAGS2(MATERIAL_VAR2_USE_FLASHLIGHT); // Required for flashlight
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Drawing the shader
|
||
|
SHADER_DRAW
|
||
|
{
|
||
|
PBR_Vars_t info;
|
||
|
SetupVars(info);
|
||
|
|
||
|
// Setting up booleans
|
||
|
bool bHasBaseTexture = (info.baseTexture != -1) && params[info.baseTexture]->IsTexture();
|
||
|
bool bHasNormalTexture = (info.bumpMap != -1) && params[info.bumpMap]->IsTexture();
|
||
|
bool bHasMraoTexture = (info.mraoTexture != -1) && params[info.mraoTexture]->IsTexture();
|
||
|
bool bHasEmissionTexture = (info.emissionTexture != -1) && params[info.emissionTexture]->IsTexture();
|
||
|
bool bHasEnvTexture = (info.envMap != -1) && params[info.envMap]->IsTexture();
|
||
|
bool bIsAlphaTested = IS_FLAG_SET(MATERIAL_VAR_ALPHATEST) != 0;
|
||
|
bool bHasFlashlight = UsingFlashlight(params);
|
||
|
bool bHasColor = (info.baseColor != -1) && params[info.baseColor]->IsDefined();
|
||
|
bool bLightMapped = !IS_FLAG_SET(MATERIAL_VAR_MODEL);
|
||
|
bool bUseEnvAmbient = (info.useEnvAmbient != -1) && (params[info.useEnvAmbient]->GetIntValue() == 1);
|
||
|
bool bHasSpecularTexture = (info.specularTexture != -1) && params[info.specularTexture]->IsTexture();
|
||
|
|
||
|
// Determining whether we're dealing with a fully opaque material
|
||
|
BlendType_t nBlendType = EvaluateBlendRequirements(info.baseTexture, true);
|
||
|
bool bFullyOpaque = (nBlendType != BT_BLENDADD) && (nBlendType != BT_BLEND) && !bIsAlphaTested;
|
||
|
|
||
|
if (IsSnapshotting())
|
||
|
{
|
||
|
// If alphatest is on, enable it
|
||
|
pShaderShadow->EnableAlphaTest(bIsAlphaTested);
|
||
|
|
||
|
if (info.alphaTestReference != -1 && params[info.alphaTestReference]->GetFloatValue() > 0.0f)
|
||
|
{
|
||
|
pShaderShadow->AlphaFunc(SHADER_ALPHAFUNC_GEQUAL, params[info.alphaTestReference]->GetFloatValue());
|
||
|
}
|
||
|
|
||
|
if (bHasFlashlight )
|
||
|
{
|
||
|
pShaderShadow->EnableBlending(true);
|
||
|
pShaderShadow->BlendFunc(SHADER_BLEND_ONE, SHADER_BLEND_ONE); // Additive blending
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetDefaultBlendingShadowState(info.baseTexture, true);
|
||
|
}
|
||
|
|
||
|
int nShadowFilterMode = bHasFlashlight ? g_pHardwareConfig->GetShadowFilterMode() : 0;
|
||
|
|
||
|
// Setting up samplers
|
||
|
pShaderShadow->EnableTexture(SAMPLER_BASETEXTURE, true); // Basecolor texture
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_BASETEXTURE, true); // Basecolor is sRGB
|
||
|
pShaderShadow->EnableTexture(SAMPLER_EMISSIVE, true); // Emission texture
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_EMISSIVE, true); // Emission is sRGB
|
||
|
pShaderShadow->EnableTexture(SAMPLER_LIGHTMAP, true); // Lightmap texture
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_LIGHTMAP, false); // Lightmaps aren't sRGB
|
||
|
pShaderShadow->EnableTexture(SAMPLER_MRAO, true); // MRAO texture
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_MRAO, false); // MRAO isn't sRGB
|
||
|
pShaderShadow->EnableTexture(SAMPLER_NORMAL, true); // Normal texture
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_NORMAL, false); // Normals aren't sRGB
|
||
|
pShaderShadow->EnableTexture(SAMPLER_SPECULAR, true); // Specular F0 texture
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_SPECULAR, true); // Specular F0 is sRGB
|
||
|
|
||
|
// If the flashlight is on, set up its textures
|
||
|
if (bHasFlashlight)
|
||
|
{
|
||
|
pShaderShadow->EnableTexture(SAMPLER_SHADOWDEPTH, true); // Shadow depth map
|
||
|
pShaderShadow->SetShadowDepthFiltering(SAMPLER_SHADOWDEPTH);
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_SHADOWDEPTH, false);
|
||
|
pShaderShadow->EnableTexture(SAMPLER_RANDOMROTATION, true); // Noise map
|
||
|
pShaderShadow->EnableTexture(SAMPLER_FLASHLIGHT, true); // Flashlight cookie
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_FLASHLIGHT, true);
|
||
|
}
|
||
|
|
||
|
// Setting up envmap
|
||
|
if (bHasEnvTexture)
|
||
|
{
|
||
|
pShaderShadow->EnableTexture(SAMPLER_ENVMAP, true); // Envmap
|
||
|
if (g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE)
|
||
|
{
|
||
|
pShaderShadow->EnableSRGBRead(SAMPLER_ENVMAP, true); // Envmap is only sRGB with HDR disabled?
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Enabling sRGB writing
|
||
|
// See common_ps_fxc.h line 349
|
||
|
// PS2b shaders and up write sRGB
|
||
|
pShaderShadow->EnableSRGBWrite(true);
|
||
|
|
||
|
if (IS_FLAG_SET(MATERIAL_VAR_MODEL))
|
||
|
{
|
||
|
// We only need the position and surface normal
|
||
|
unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_FORMAT_COMPRESSED;
|
||
|
// We need three texcoords, all in the default float2 size
|
||
|
pShaderShadow->VertexShaderVertexFormat(flags, 1, 0, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We need the position, surface normal, and vertex compression format
|
||
|
unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL;
|
||
|
// We only need one texcoord, in the default float2 size
|
||
|
pShaderShadow->VertexShaderVertexFormat(flags, 3, 0, 0);
|
||
|
}
|
||
|
|
||
|
int useParallax = params[info.useParallax]->GetIntValue();
|
||
|
if (!mat_pbr_parallaxmap.GetBool())
|
||
|
{
|
||
|
useParallax = 0;
|
||
|
}
|
||
|
|
||
|
if (!g_pHardwareConfig->SupportsShaderModel_3_0() || mat_pbr_force_20b.GetBool())
|
||
|
{
|
||
|
// Setting up static vertex shader
|
||
|
DECLARE_STATIC_VERTEX_SHADER(pbr_vs20b);
|
||
|
SET_STATIC_VERTEX_SHADER(pbr_vs20b);
|
||
|
|
||
|
// Setting up static pixel shader
|
||
|
DECLARE_STATIC_PIXEL_SHADER(pbr_ps20b);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(FLASHLIGHT, bHasFlashlight);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(LIGHTMAPPED, bLightMapped);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(EMISSIVE, bHasEmissionTexture);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(SPECULAR, 0);
|
||
|
SET_STATIC_PIXEL_SHADER(pbr_ps20b);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Setting up static vertex shader
|
||
|
DECLARE_STATIC_VERTEX_SHADER(pbr_vs30);
|
||
|
SET_STATIC_VERTEX_SHADER(pbr_vs30);
|
||
|
|
||
|
// Setting up static pixel shader
|
||
|
DECLARE_STATIC_PIXEL_SHADER(pbr_ps30);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(FLASHLIGHT, bHasFlashlight);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(LIGHTMAPPED, bLightMapped);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(USEENVAMBIENT, bUseEnvAmbient);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(EMISSIVE, bHasEmissionTexture);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(SPECULAR, bHasSpecularTexture);
|
||
|
SET_STATIC_PIXEL_SHADER_COMBO(PARALLAXOCCLUSION, useParallax);
|
||
|
SET_STATIC_PIXEL_SHADER(pbr_ps30);
|
||
|
}
|
||
|
|
||
|
// Setting up fog
|
||
|
DefaultFog(); // I think this is correct
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
// Setting up albedo texture
|
||
|
if (bHasBaseTexture)
|
||
|
{
|
||
|
BindTexture(SAMPLER_BASETEXTURE, info.baseTexture, info.baseTextureFrame);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_BASETEXTURE, TEXTURE_GREY);
|
||
|
}
|
||
|
|
||
|
// Setting up vmt color
|
||
|
Vector color;
|
||
|
if (bHasColor)
|
||
|
{
|
||
|
params[info.baseColor]->GetVecValue(color.Base(), 3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
color = Vector{1.f, 1.f, 1.f};
|
||
|
}
|
||
|
pShaderAPI->SetPixelShaderConstant(PSREG_SELFILLUMTINT, color.Base());
|
||
|
|
||
|
// Setting up environment map
|
||
|
if (bHasEnvTexture)
|
||
|
{
|
||
|
BindTexture(SAMPLER_ENVMAP, info.envMap, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_ENVMAP, TEXTURE_BLACK);
|
||
|
}
|
||
|
|
||
|
// Setting up emissive texture
|
||
|
if (bHasEmissionTexture)
|
||
|
{
|
||
|
BindTexture(SAMPLER_EMISSIVE, info.emissionTexture, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_EMISSIVE, TEXTURE_BLACK);
|
||
|
}
|
||
|
|
||
|
// Setting up normal map
|
||
|
if (bHasNormalTexture)
|
||
|
{
|
||
|
BindTexture(SAMPLER_NORMAL, info.bumpMap, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_NORMAL, TEXTURE_NORMALMAP_FLAT);
|
||
|
}
|
||
|
|
||
|
// Setting up mrao map
|
||
|
if (bHasMraoTexture)
|
||
|
{
|
||
|
BindTexture(SAMPLER_MRAO, info.mraoTexture, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_MRAO, TEXTURE_WHITE);
|
||
|
}
|
||
|
|
||
|
if (bHasSpecularTexture)
|
||
|
{
|
||
|
BindTexture(SAMPLER_SPECULAR, info.specularTexture, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_SPECULAR, TEXTURE_BLACK);
|
||
|
}
|
||
|
|
||
|
// Getting the light state
|
||
|
LightState_t lightState;
|
||
|
pShaderAPI->GetDX9LightState(&lightState);
|
||
|
|
||
|
// Brushes don't need ambient cubes or dynamic lights
|
||
|
if (!IS_FLAG_SET(MATERIAL_VAR_MODEL))
|
||
|
{
|
||
|
lightState.m_bAmbientLight = false;
|
||
|
lightState.m_nNumLights = 0;
|
||
|
}
|
||
|
|
||
|
// Setting up the flashlight related textures and variables
|
||
|
bool bFlashlightShadows = false;
|
||
|
if (bHasFlashlight)
|
||
|
{
|
||
|
Assert(info.flashlightTexture >= 0 && info.flashlightTextureFrame >= 0);
|
||
|
Assert(params[info.flashlightTexture]->IsTexture());
|
||
|
BindTexture(SAMPLER_FLASHLIGHT, info.flashlightTexture, info.flashlightTextureFrame);
|
||
|
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)
|
||
|
{
|
||
|
BindTexture(SAMPLER_SHADOWDEPTH, pFlashlightDepthTexture, 0);
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_RANDOMROTATION, TEXTURE_SHADOW_NOISE_2D);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Getting fog info
|
||
|
MaterialFogMode_t fogType = pShaderAPI->GetSceneFogMode();
|
||
|
int fogIndex = (fogType == MATERIAL_FOG_LINEAR_BELOW_FOG_Z) ? 1 : 0;
|
||
|
|
||
|
// Getting skinning info
|
||
|
int numBones = pShaderAPI->GetCurrentNumBones();
|
||
|
|
||
|
// Some debugging stuff
|
||
|
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.");
|
||
|
}
|
||
|
|
||
|
float vEyePos_SpecExponent[4];
|
||
|
pShaderAPI->GetWorldSpaceCameraPosition(vEyePos_SpecExponent);
|
||
|
|
||
|
// Determining the max level of detail for the envmap
|
||
|
int iEnvMapLOD = 6;
|
||
|
auto envTexture = params[info.envMap]->GetTextureValue();
|
||
|
if (envTexture)
|
||
|
{
|
||
|
// Get power of 2 of texture width
|
||
|
int width = envTexture->GetMappingWidth();
|
||
|
int mips = 0;
|
||
|
while (width >>= 1)
|
||
|
++mips;
|
||
|
|
||
|
// Cubemap has 4 sides so 2 mips less
|
||
|
iEnvMapLOD = mips;
|
||
|
}
|
||
|
|
||
|
// Dealing with very high and low resolution cubemaps
|
||
|
if (iEnvMapLOD > 12)
|
||
|
iEnvMapLOD = 12;
|
||
|
if (iEnvMapLOD < 4)
|
||
|
iEnvMapLOD = 4;
|
||
|
|
||
|
// This has some spare space
|
||
|
vEyePos_SpecExponent[3] = iEnvMapLOD;
|
||
|
pShaderAPI->SetPixelShaderConstant(PSREG_EYEPOS_SPEC_EXPONENT, vEyePos_SpecExponent, 1);
|
||
|
|
||
|
// Setting lightmap texture
|
||
|
s_pShaderAPI->BindStandardTexture(SAMPLER_LIGHTMAP, TEXTURE_LIGHTMAP_BUMPED);
|
||
|
|
||
|
if (!g_pHardwareConfig->SupportsShaderModel_3_0() || mat_pbr_force_20b.GetBool())
|
||
|
{
|
||
|
// Setting up dynamic vertex shader
|
||
|
DECLARE_DYNAMIC_VERTEX_SHADER(pbr_vs20b);
|
||
|
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(pbr_vs20b);
|
||
|
|
||
|
// Setting up dynamic pixel shader
|
||
|
DECLARE_DYNAMIC_PIXEL_SHADER(pbr_ps20b);
|
||
|
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(pbr_ps20b);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Setting up dynamic vertex shader
|
||
|
DECLARE_DYNAMIC_VERTEX_SHADER(pbr_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(pbr_vs30);
|
||
|
|
||
|
// Setting up dynamic pixel shader
|
||
|
DECLARE_DYNAMIC_PIXEL_SHADER(pbr_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(pbr_ps30);
|
||
|
}
|
||
|
|
||
|
// Setting up base texture transform
|
||
|
SetVertexShaderTextureTransform(VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, info.baseTextureTransform);
|
||
|
|
||
|
// This is probably important
|
||
|
SetModulationPixelShaderDynamicState_LinearColorSpace(1);
|
||
|
|
||
|
// Send ambient cube to the pixel shader, force to black if not available
|
||
|
pShaderAPI->SetPixelShaderStateAmbientLightCube(PSREG_AMBIENT_CUBE, !lightState.m_bAmbientLight);
|
||
|
|
||
|
// Send lighting array to the pixel shader
|
||
|
pShaderAPI->CommitPixelShaderLighting(PSREG_LIGHT_INFO_ARRAY);
|
||
|
|
||
|
// Handle mat_fullbright 2 (diffuse lighting only)
|
||
|
if (bLightingOnly)
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_BASETEXTURE, TEXTURE_GREY); // Basecolor
|
||
|
}
|
||
|
|
||
|
// Handle mat_specular 0 (no envmap reflections)
|
||
|
if (!mat_specular.GetBool())
|
||
|
{
|
||
|
pShaderAPI->BindStandardTexture(SAMPLER_ENVMAP, TEXTURE_BLACK); // Envmap
|
||
|
}
|
||
|
|
||
|
// Sending fog info to the pixel shader
|
||
|
pShaderAPI->SetPixelShaderFogParams(PSREG_FOG_PARAMS);
|
||
|
|
||
|
// Set up shader modulation color
|
||
|
float modulationColor[4] = { 1.0, 1.0, 1.0, 1.0 };
|
||
|
ComputeModulationColor(modulationColor);
|
||
|
float flLScale = pShaderAPI->GetLightMapScaleFactor();
|
||
|
modulationColor[0] *= flLScale;
|
||
|
modulationColor[1] *= flLScale;
|
||
|
modulationColor[2] *= flLScale;
|
||
|
pShaderAPI->SetPixelShaderConstant(PSREG_DIFFUSE_MODULATION, modulationColor);
|
||
|
|
||
|
// More flashlight related stuff
|
||
|
if (bHasFlashlight)
|
||
|
{
|
||
|
VMatrix worldToTexture;
|
||
|
float atten[4], pos[4], tweaks[4];
|
||
|
|
||
|
const FlashlightState_t &flashlightState = pShaderAPI->GetFlashlightState(worldToTexture);
|
||
|
SetFlashLightColorFromState(flashlightState, pShaderAPI, PSREG_FLASHLIGHT_COLOR);
|
||
|
|
||
|
BindTexture(SAMPLER_FLASHLIGHT, flashlightState.m_pSpotlightTexture, flashlightState.m_nSpotlightTextureFrame);
|
||
|
|
||
|
// Set the flashlight attenuation factors
|
||
|
atten[0] = flashlightState.m_fConstantAtten;
|
||
|
atten[1] = flashlightState.m_fLinearAtten;
|
||
|
atten[2] = flashlightState.m_fQuadraticAtten;
|
||
|
atten[3] = flashlightState.m_FarZ;
|
||
|
pShaderAPI->SetPixelShaderConstant(PSREG_FLASHLIGHT_ATTENUATION, atten, 1);
|
||
|
|
||
|
// Set the flashlight origin
|
||
|
pos[0] = flashlightState.m_vecLightOrigin[0];
|
||
|
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);
|
||
|
HashShadow2DJitter(flashlightState.m_flShadowJitterSeed, &tweaks[2], &tweaks[3]);
|
||
|
pShaderAPI->SetPixelShaderConstant(PSREG_ENVMAP_TINT__SHADOW_TWEAKS, tweaks, 1);
|
||
|
}
|
||
|
|
||
|
float flParams[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||
|
// Parallax Depth (the strength of the effect)
|
||
|
flParams[0] = GetFloatParam(info.parallaxDepth, params, 3.0f);
|
||
|
// Parallax Center (the height at which it's not moved)
|
||
|
flParams[1] = GetFloatParam(info.parallaxCenter, params, 3.0f);
|
||
|
pShaderAPI->SetPixelShaderConstant(27, flParams, 1);
|
||
|
|
||
|
}
|
||
|
|
||
|
// Actually draw the shader
|
||
|
Draw();
|
||
|
};
|
||
|
|
||
|
// Closing it off
|
||
|
END_SHADER;
|