Created
May 21, 2021 08:50
-
-
Save untodesu/a42e29b34c76dc4c0035f81a921c6fe3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// PBR shader. | |
// Originates from https://github.com/thexa4/source-pbr | |
// Adopted for Refraction. Things done so far: | |
// 1. Fixed SP branch crash (See PSREG_FREE). | |
// 2. Removed all the verbosity in the comments | |
// leaving only stuff that explains obfuscated stuff. | |
#include "BaseVSShader.h" | |
#include "cpp_shader_constant_register_map.h" | |
#include "pbr_vs30.inc" | |
#include "pbr_ps30.inc" | |
// memdbgon must be the last include file in a .cpp file!!! | |
#include "tier0/memdbgon.h" | |
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; | |
static ConVarRef mat_fullbright( "mat_fullbright", false ); | |
static ConVarRef mat_specular( "mat_specular", false ); | |
static ConVar mat_pbr_parallaxmap( "mat_pbr_parallaxmap", "1" ); | |
struct PBR_Vars_t { | |
PBR_Vars_t() | |
{ | |
memset( this, 0xFF, sizeof( *this ) ); | |
} | |
int baseTexture; | |
int baseColor; | |
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; | |
}; | |
BEGIN_VS_SHADER( PBR, "Help for PBR shader" ) | |
BEGIN_SHADER_PARAMS; | |
SHADER_PARAM( ALPHATESTREFERENCE, SHADER_PARAM_TYPE_FLOAT, "0", "" ) | |
SHADER_PARAM( ENVMAP, SHADER_PARAM_TYPE_ENVMAP, "", "" ) | |
SHADER_PARAM( MRAOTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "" ) | |
SHADER_PARAM( EMISSIONTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "" ) | |
SHADER_PARAM( BUMPMAP, SHADER_PARAM_TYPE_TEXTURE, "", "" ) | |
SHADER_PARAM( USEENVAMBIENT, SHADER_PARAM_TYPE_BOOL, "0", "" ) | |
SHADER_PARAM( SPECULARTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "" ) | |
SHADER_PARAM( PARALLAX, SHADER_PARAM_TYPE_BOOL, "0", "" ) | |
SHADER_PARAM( PARALLAXDEPTH, SHADER_PARAM_TYPE_FLOAT, "0.0030", "" ) | |
SHADER_PARAM( PARALLAXCENTER, SHADER_PARAM_TYPE_FLOAT, "0.5", "" ) | |
END_SHADER_PARAMS; | |
void SetupVars( PBR_Vars_t &info ) | |
{ | |
info.baseTexture = BASETEXTURE; | |
info.baseColor = COLOR; | |
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; | |
} | |
SHADER_FALLBACK | |
{ | |
return 0; | |
} | |
SHADER_INIT | |
{ | |
if( !params[BUMPMAP]->IsDefined() ) | |
params[BUMPMAP]->SetStringValue( "dev/flat_normal" ); | |
if( !params[MRAOTEXTURE]->IsDefined() ) | |
params[MRAOTEXTURE]->SetStringValue( "dev/pbr_mraotexture" ); | |
if( !params[ENVMAP]->IsDefined() ) | |
params[ENVMAP]->SetStringValue( "env_cubemap" ); | |
if( g_pHardwareConfig->SupportsBorderColor() ) | |
params[FLASHLIGHTTEXTURE]->SetStringValue( "effects/flashlight_border" ); | |
else | |
params[FLASHLIGHTTEXTURE]->SetStringValue( "effects/flashlight001" ); | |
PBR_Vars_t info; | |
SetupVars( info ); | |
LoadTexture( info.flashlightTexture, TEXTUREFLAGS_SRGB ); | |
LoadBumpMap( info.bumpMap ); | |
LoadCubeMap( info.envMap, ( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ? TEXTUREFLAGS_SRGB : 0 ) | TEXTUREFLAGS_ALL_MIPS ); | |
LoadTexture( info.mraoTexture, 0 ); | |
if( info.emissionTexture >= 0 && params[EMISSIONTEXTURE]->IsDefined() ) | |
LoadTexture( info.emissionTexture, TEXTUREFLAGS_SRGB ); | |
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_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_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 | |
} | |
} | |
SHADER_DRAW | |
{ | |
PBR_Vars_t info; | |
SetupVars( info ); | |
const bool bAlphaTested = IS_FLAG_SET( MATERIAL_VAR_ALPHATEST ); | |
const bool bLightmapped = !IS_FLAG_SET( MATERIAL_VAR_MODEL ); | |
const bool bHasBaseTexture = params[info.baseTexture]->IsTexture(); | |
const bool bHasBumpTexture = params[info.bumpMap]->IsTexture(); | |
const bool bHasMRAOTexture = params[info.mraoTexture]->IsTexture(); | |
const bool bHasEmissionTexture = params[info.emissionTexture]->IsTexture(); | |
const bool bHasSpecularTexture = params[info.specularTexture]->IsTexture(); | |
const bool bHasEnvMapTexture = params[info.envMap]->IsTexture(); | |
const bool bUsingFlashlight = UsingFlashlight( params ); | |
const bool bHasColor = params[info.baseColor]->IsDefined() && info.baseColor != -1; | |
const bool bUseEnvAmbient = !!params[info.useEnvAmbient]->GetIntValue(); | |
BlendType_t nBlendType = EvaluateBlendRequirements( info.baseTexture, true ); | |
bool bFullyOpaque = ( nBlendType != BT_BLENDADD ) && ( nBlendType != BT_BLEND ) && !bAlphaTested; | |
SHADOW_STATE | |
{ | |
pShaderShadow->EnableAlphaTest( bAlphaTested ); | |
if( info.alphaTestReference != -1 && params[info.alphaTestReference]->GetFloatValue() > 0.0f ) { | |
pShaderShadow->AlphaFunc( SHADER_ALPHAFUNC_GEQUAL, params[info.alphaTestReference]->GetFloatValue() ); | |
} | |
if( bUsingFlashlight ) { | |
// Additive blending | |
pShaderShadow->EnableBlending( true ); | |
pShaderShadow->BlendFunc( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); | |
} | |
else | |
SetDefaultBlendingShadowState( info.baseTexture, true ); | |
int nShadowFilterMode = bUsingFlashlight ? g_pHardwareConfig->GetShadowFilterMode() : 0; | |
pShaderShadow->EnableTexture( SAMPLER_BASETEXTURE, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_BASETEXTURE, true ); | |
pShaderShadow->EnableTexture( SAMPLER_EMISSIVE, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_EMISSIVE, true ); | |
pShaderShadow->EnableTexture( SAMPLER_LIGHTMAP, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_LIGHTMAP, false ); | |
pShaderShadow->EnableTexture( SAMPLER_MRAO, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_MRAO, false ); | |
pShaderShadow->EnableTexture( SAMPLER_NORMAL, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_NORMAL, false ); | |
pShaderShadow->EnableTexture( SAMPLER_SPECULAR, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_SPECULAR, true ); | |
if( bUsingFlashlight ) { | |
pShaderShadow->EnableTexture( SAMPLER_SHADOWDEPTH, true ); | |
pShaderShadow->SetShadowDepthFiltering( SAMPLER_SHADOWDEPTH ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_SHADOWDEPTH, false ); | |
pShaderShadow->EnableTexture( SAMPLER_RANDOMROTATION, true ); | |
pShaderShadow->EnableTexture( SAMPLER_FLASHLIGHT, true ); | |
pShaderShadow->EnableSRGBRead( SAMPLER_FLASHLIGHT, true ); | |
} | |
if( bHasEnvMapTexture ) { | |
pShaderShadow->EnableTexture( SAMPLER_ENVMAP, true ); | |
if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) | |
pShaderShadow->EnableSRGBRead( SAMPLER_ENVMAP, true ); | |
} | |
// PS2b shaders and up write sRGB (See common_ps_fxc.h line 349) | |
// und: is it true? | |
pShaderShadow->EnableSRGBWrite( true ); | |
if( IS_FLAG_SET( MATERIAL_VAR_MODEL ) ) { | |
unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_FORMAT_COMPRESSED; | |
pShaderShadow->VertexShaderVertexFormat( flags, 1, 0, 0 ); | |
} | |
else { | |
unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL; | |
pShaderShadow->VertexShaderVertexFormat( flags, 3, 0, 0 ); | |
} | |
int useParallax = params[info.useParallax]->GetIntValue(); | |
if( !mat_pbr_parallaxmap.GetBool() ) { | |
useParallax = 0; | |
} | |
DECLARE_STATIC_VERTEX_SHADER( pbr_vs30 ); | |
SET_STATIC_VERTEX_SHADER( pbr_vs30 ); | |
DECLARE_STATIC_PIXEL_SHADER( pbr_ps30 ); | |
SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, bUsingFlashlight ); | |
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 ); | |
// I think this is correct | |
DefaultFog(); | |
pShaderShadow->EnableAlphaWrites( bFullyOpaque ); | |
} | |
DYNAMIC_STATE | |
{ | |
bool bLightingOnly = mat_fullbright.GetInt() == 2 && !IS_FLAG_SET( MATERIAL_VAR_NO_DEBUG_OVERRIDE ); | |
if( bHasBaseTexture ) | |
BindTexture( SAMPLER_BASETEXTURE, info.baseTexture, info.baseTextureFrame ); | |
else | |
pShaderAPI->BindStandardTexture( SAMPLER_BASETEXTURE, TEXTURE_GREY ); | |
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() ); | |
if( bHasEnvMapTexture ) | |
BindTexture( SAMPLER_ENVMAP, info.envMap, 0 ); | |
else | |
pShaderAPI->BindStandardTexture( SAMPLER_ENVMAP, TEXTURE_BLACK ); | |
if( bHasEmissionTexture ) | |
BindTexture( SAMPLER_EMISSIVE, info.emissionTexture, 0 ); | |
else | |
pShaderAPI->BindStandardTexture( SAMPLER_EMISSIVE, TEXTURE_BLACK ); | |
if( bHasBumpTexture ) | |
BindTexture( SAMPLER_NORMAL, info.bumpMap, 0 ); | |
else | |
pShaderAPI->BindStandardTexture( SAMPLER_NORMAL, TEXTURE_NORMALMAP_FLAT ); | |
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 ); | |
LightState_t lightState; | |
pShaderAPI->GetDX9LightState( &lightState ); | |
if( !IS_FLAG_SET( MATERIAL_VAR_MODEL ) ) { | |
lightState.m_bAmbientLight = false; | |
lightState.m_nNumLights = 0; | |
} | |
bool bFlashlightShadows = false; | |
if( bUsingFlashlight ) { | |
BindTexture( SAMPLER_FLASHLIGHT, info.flashlightTexture, info.flashlightTextureFrame ); | |
VMatrix worldToTexture; | |
ITexture *pFlashlightDepthTexture; | |
FlashlightState_t state = pShaderAPI->GetFlashlightStateEx( worldToTexture, &pFlashlightDepthTexture ); | |
bFlashlightShadows = state.m_bEnableShadows && pFlashlightDepthTexture; | |
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 ); | |
} | |
} | |
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 ); | |
} | |
float vEyePos_SpecExponent[4]; | |
pShaderAPI->GetWorldSpaceCameraPosition( vEyePos_SpecExponent ); | |
int iEnvMapLOD = 6; | |
auto envTexture = params[info.envMap]->GetTextureValue(); | |
if( envTexture ) { | |
int width = envTexture->GetMappingWidth(); | |
int mips = 0; | |
while( width >>= 1 ) mips++; | |
iEnvMapLOD = mips; | |
} | |
iEnvMapLOD = Clamp( iEnvMapLOD, 4, 12 ); | |
// vEyePos_SpecExponent has some spare space | |
vEyePos_SpecExponent[3] = iEnvMapLOD; | |
pShaderAPI->SetPixelShaderConstant( PSREG_EYEPOS_SPEC_EXPONENT, vEyePos_SpecExponent, 1 ); | |
s_pShaderAPI->BindStandardTexture( SAMPLER_LIGHTMAP, TEXTURE_LIGHTMAP_BUMPED ); | |
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 ); | |
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 ); | |
SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, info.baseTextureTransform ); | |
// This is probably important | |
SetModulationPixelShaderDynamicState_LinearColorSpace( 1 ); | |
pShaderAPI->SetPixelShaderStateAmbientLightCube( PSREG_AMBIENT_CUBE, !lightState.m_bAmbientLight ); | |
pShaderAPI->CommitPixelShaderLighting( PSREG_LIGHT_INFO_ARRAY ); | |
// Handle mat_fullbright 2 (diffuse lighting only) | |
if( bLightingOnly ) | |
pShaderAPI->BindStandardTexture( SAMPLER_BASETEXTURE, TEXTURE_GREY ); | |
// Handle mat_specular 0 (no envmap reflections) | |
if( !mat_specular.GetBool() ) | |
pShaderAPI->BindStandardTexture( SAMPLER_ENVMAP, TEXTURE_BLACK ); | |
pShaderAPI->SetPixelShaderFogParams( PSREG_FOG_PARAMS ); | |
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 ); | |
if( bUsingFlashlight ) { | |
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 ); | |
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 ); | |
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[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 ); | |
// und: used PSREG_FREE (c27) instead of hardcoded c40. | |
// SP somehow does not support more than 32 (c31) constants. Too bad! | |
pShaderAPI->SetPixelShaderConstant( PSREG_FREE, flParams, 1 ); | |
} | |
Draw(); | |
} | |
END_SHADER |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// STATIC: "FLASHLIGHT" "0..1" | |
// STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..2" | |
// STATIC: "LIGHTMAPPED" "0..1" | |
// STATIC: "USEENVAMBIENT" "0..1" | |
// STATIC: "EMISSIVE" "0..1" | |
// STATIC: "SPECULAR" "0..1" | |
// STATIC: "PARALLAXOCCLUSION" "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" | |
// Can't write fog to alpha if there is no fog | |
// SKIP: ($PIXELFOGTYPE == 0) && ($WRITEWATERFOGTODESTALPHA != 0) | |
// We don't care about flashlight depth unless the flashlight is on | |
// SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) | |
// Flashlight shadow filter mode is irrelevant if there is no flashlight | |
// SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) | |
#include "common_ps_fxc.h" | |
#include "common_flashlight_fxc.h" | |
#include "shader_constant_register_map.h" | |
// Universal Constants | |
static const float PI = 3.141592; | |
static const float ONE_OVER_PI = 0.318309; | |
static const float EPSILON = 0.00001; | |
// Shlick's approximation of the Fresnel factor | |
float3 fresnelSchlick(float3 F0, float cosTheta) | |
{ | |
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); | |
} | |
// Shlick's approximation of the Fresnel factor with account for roughness | |
float3 fresnelSchlickRoughness(float3 F0, float cosTheta, float roughness) | |
{ | |
return F0 + (max(float3(1.0, 1.0, 1.0) - roughness, F0) - F0) * pow(1.0 - cosTheta, 5.0); | |
} | |
// GGX/Towbridge-Reitz normal distribution function | |
// Uses Disney's reparametrization of alpha = roughness^2 | |
float ndfGGX(float cosLh, float roughness) | |
{ | |
float alpha = roughness * roughness; | |
float alphaSq = alpha * alpha; | |
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; | |
return alphaSq / (PI * denom * denom); | |
} | |
// Single term for separable Schlick-GGX below | |
float gaSchlickG1(float cosTheta, float k) | |
{ | |
return cosTheta / (cosTheta * (1.0 - k) + k); | |
} | |
// Schlick-GGX approximation of geometric attenuation function using Smith's method | |
float gaSchlickGGX(float cosLi, float cosLo, float roughness) | |
{ | |
float r = roughness + 1.0; | |
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights | |
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); | |
} | |
// Monte Carlo integration, approximate analytic version based on Dimitar Lazarov's work | |
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile | |
float3 EnvBRDFApprox(float3 SpecularColor, float Roughness, float NoV) | |
{ | |
const float4 c0 = { -1, -0.0275, -0.572, 0.022 }; | |
const float4 c1 = { 1, 0.0425, 1.04, -0.04 }; | |
float4 r = Roughness * c0 + c1; | |
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; | |
float2 AB = float2(-1.04, 1.04) * a004 + r.zw; | |
return SpecularColor * AB.x + AB.y; | |
} | |
// Compute the matrix used to transform tangent space normals to world space | |
// This expects DirectX normal maps in Mikk Tangent Space http://www.mikktspace.com | |
float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv, out float3 T, out float3 B, out float sign_det) | |
{ | |
float3 dp1 = ddx(P); | |
float3 dp2 = ddy(P); | |
float2 duv1 = ddx(uv); | |
float2 duv2 = ddy(uv); | |
sign_det = dot(dp2, cross(N, dp1)) > 0.0 ? -1 : 1; | |
float3x3 M = float3x3(dp1, dp2, cross(dp1, dp2)); | |
float2x3 inverseM = float2x3(cross(M[1], M[2]), cross(M[2], M[0])); | |
T = normalize(mul(float2(duv1.x, duv2.x), inverseM)); | |
B = normalize(mul(float2(duv1.y, duv2.y), inverseM)); | |
return float3x3(T, B, N); | |
} | |
float GetAttenForLight(float4 lightAtten, int lightNum) | |
{ | |
#if NUM_LIGHTS > 1 | |
if (lightNum == 1) | |
return lightAtten.y; | |
#endif | |
#if NUM_LIGHTS > 2 | |
if (lightNum == 2) | |
return lightAtten.z; | |
#endif | |
#if NUM_LIGHTS > 3 | |
if (lightNum == 3) | |
return lightAtten.w; | |
#endif | |
return lightAtten.x; | |
} | |
// Calculate direct light for one source | |
float3 calculateLight(float3 lightIn, float3 lightIntensity, float3 lightOut, float3 normal, float3 fresnelReflectance, float roughness, float metalness, float lightDirectionAngle, float3 albedo) | |
{ | |
// Lh | |
float3 HalfAngle = normalize(lightIn + lightOut); | |
float cosLightIn = max(0.0, dot(normal, lightIn)); | |
float cosHalfAngle = max(0.0, dot(normal, HalfAngle)); | |
// F - Calculate Fresnel term for direct lighting | |
float3 F = fresnelSchlick(fresnelReflectance, max(0.0, dot(HalfAngle, lightOut))); | |
// D - Calculate normal distribution for specular BRDF | |
float D = ndfGGX(cosHalfAngle, roughness); | |
// Calculate geometric attenuation for specular BRDF | |
float G = gaSchlickGGX(cosLightIn, lightDirectionAngle, roughness); | |
// Diffuse scattering happens due to light being refracted multiple times by a dielectric medium | |
// Metals on the other hand either reflect or absorb energso diffuse contribution is always, zero | |
// To be energy conserving we must scale diffuse BRDF contribution based on Fresnel factor & metalness | |
#if SPECULAR | |
// Metalness is not used if F0 map is available | |
float3 kd = float3(1, 1, 1) - F; | |
#else | |
float3 kd = lerp(float3(1, 1, 1) - F, float3(0, 0, 0), metalness); | |
#endif | |
float3 diffuseBRDF = kd * albedo; | |
// Cook-Torrance specular microfacet BRDF | |
float3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLightIn * lightDirectionAngle); | |
#if LIGHTMAPPED && !FLASHLIGHT | |
// Ambient light from static lights is already precomputed in the lightmap. Don't add it again | |
return specularBRDF * lightIntensity * cosLightIn; | |
#else | |
return (diffuseBRDF + specularBRDF) * lightIntensity * cosLightIn; | |
#endif | |
} | |
// Get diffuse ambient light | |
float3 ambientLookupLightmap(float3 normal, float3 EnvAmbientCube[6], float3 textureNormal, float4 lightmapTexCoord1And2, float4 lightmapTexCoord3, sampler LightmapSampler, float4 g_DiffuseModulation) | |
{ | |
float2 bumpCoord1; | |
float2 bumpCoord2; | |
float2 bumpCoord3; | |
ComputeBumpedLightmapCoordinates(lightmapTexCoord1And2, lightmapTexCoord3.xy, bumpCoord1, bumpCoord2, bumpCoord3); | |
float3 lightmapColor1 = tex2D(LightmapSampler, bumpCoord1).rgb; | |
float3 lightmapColor2 = tex2D(LightmapSampler, bumpCoord2).rgb; | |
float3 lightmapColor3 = tex2D(LightmapSampler, bumpCoord3).rgb; | |
float3 dp; | |
dp.x = saturate(dot(textureNormal, bumpBasis[0])); | |
dp.y = saturate(dot(textureNormal, bumpBasis[1])); | |
dp.z = saturate(dot(textureNormal, bumpBasis[2])); | |
dp *= dp; | |
float3 diffuseLighting = dp.x * lightmapColor1 + dp.y * lightmapColor2 + dp.z * lightmapColor3; | |
float sum = dot(dp, float3(1, 1, 1)); | |
diffuseLighting *= g_DiffuseModulation.xyz / sum; | |
return diffuseLighting; | |
} | |
float3 ambientLookup(float3 normal, float3 EnvAmbientCube[6], float3 textureNormal, float4 lightmapTexCoord1And2, float4 lightmapTexCoord3, sampler LightmapSampler, float4 g_DiffuseModulation) | |
{ | |
#if LIGHTMAPPED | |
return ambientLookupLightmap(normal, EnvAmbientCube, textureNormal, lightmapTexCoord1And2, lightmapTexCoord3, LightmapSampler, g_DiffuseModulation); | |
#else | |
return PixelShaderAmbientLight(normal, EnvAmbientCube); | |
#endif | |
} | |
// Create an ambient cube from the envmap | |
void setupEnvMapAmbientCube(out float3 EnvAmbientCube[6], sampler EnvmapSampler) | |
{ | |
float4 directionPosX = { 1, 0, 0, 12 }; float4 directionNegX = {-1, 0, 0, 12 }; | |
float4 directionPosY = { 0, 1, 0, 12 }; float4 directionNegY = { 0,-1, 0, 12 }; | |
float4 directionPosZ = { 0, 0, 1, 12 }; float4 directionNegZ = { 0, 0,-1, 12 }; | |
EnvAmbientCube[0] = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionPosX).rgb; | |
EnvAmbientCube[1] = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionNegX).rgb; | |
EnvAmbientCube[2] = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionPosY).rgb; | |
EnvAmbientCube[3] = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionNegY).rgb; | |
EnvAmbientCube[4] = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionPosZ).rgb; | |
EnvAmbientCube[5] = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, directionNegZ).rgb; | |
} | |
#if PARALLAXOCCLUSION | |
float2 parallaxCorrect(float2 texCoord, float3 viewRelativeDir, sampler depthMap, float parallaxDepth, float parallaxCenter) | |
{ | |
float fLength = length( viewRelativeDir ); | |
float fParallaxLength = sqrt( fLength * fLength - viewRelativeDir.z * viewRelativeDir.z ) / viewRelativeDir.z; | |
float2 vParallaxDirection = normalize( viewRelativeDir.xy ); | |
float2 vParallaxOffsetTS = vParallaxDirection * fParallaxLength; | |
vParallaxOffsetTS *= parallaxDepth; | |
// Compute all the derivatives: | |
float2 dx = ddx( texCoord ); | |
float2 dy = ddy( texCoord ); | |
int nNumSteps = 20; | |
float fCurrHeight = 0.0; | |
float fStepSize = 1.0 / (float) nNumSteps; | |
float fPrevHeight = 1.0; | |
float fNextHeight = 0.0; | |
int nStepIndex = 0; | |
bool bCondition = true; | |
float2 vTexOffsetPerStep = fStepSize * vParallaxOffsetTS; | |
float2 vTexCurrentOffset = texCoord; | |
float fCurrentBound = 1.0; | |
float fParallaxAmount = 0.0; | |
float2 pt1 = 0; | |
float2 pt2 = 0; | |
float2 texOffset2 = 0; | |
while ( nStepIndex < nNumSteps ) | |
{ | |
vTexCurrentOffset -= vTexOffsetPerStep; | |
// Sample height map which in this case is stored in the alpha channel of the normal map: | |
fCurrHeight = parallaxCenter + tex2Dgrad( depthMap, vTexCurrentOffset, dx, dy ).a; | |
fCurrentBound -= fStepSize; | |
if ( fCurrHeight > fCurrentBound ) | |
{ | |
pt1 = float2( fCurrentBound, fCurrHeight ); | |
pt2 = float2( fCurrentBound + fStepSize, fPrevHeight ); | |
texOffset2 = vTexCurrentOffset - vTexOffsetPerStep; | |
nStepIndex = nNumSteps + 1; | |
} | |
else | |
{ | |
nStepIndex++; | |
fPrevHeight = fCurrHeight; | |
} | |
} // End of while ( nStepIndex < nNumSteps ) | |
float fDelta2 = pt2.x - pt2.y; | |
float fDelta1 = pt1.x - pt1.y; | |
fParallaxAmount = (pt1.x * fDelta2 - pt2.x * fDelta1 ) / ( fDelta2 - fDelta1 ); | |
float2 vParallaxOffset = vParallaxOffsetTS * (1 - fParallaxAmount); | |
// The computed texture offset for the displaced point on the pseudo-extruded surface: | |
float2 texSample = texCoord - vParallaxOffset; | |
return texSample; | |
} | |
#endif | |
float3 worldToRelative(float3 worldVector, float3 surfTangent, float3 surfBasis, float3 surfNormal) | |
{ | |
return float3(dot(worldVector, surfTangent), dot(worldVector, surfBasis), dot(worldVector, surfNormal)); | |
} | |
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); | |
const float4 g_FlashlightAttenuationFactors : register(PSREG_FLASHLIGHT_ATTENUATION); | |
const float4 g_FlashlightPos : register(PSREG_FLASHLIGHT_POSITION_RIM_BOOST); | |
const float4x4 g_FlashlightWorldToTexture : register(PSREG_FLASHLIGHT_TO_WORLD_TEXTURE); | |
PixelShaderLightInfo cLightInfo[3] : register(PSREG_LIGHT_INFO_ARRAY); // 2 registers each - 6 registers total (4th light spread across w's) | |
const float4 g_BaseColor : register(PSREG_SELFILLUMTINT); | |
#if PARALLAXOCCLUSION | |
const float4 g_ParallaxParms : register(PSREG_FREE); // c40? That breaks in SP branch. Too bad! | |
#define PARALLAX_DEPTH g_ParallaxParms.r | |
#define PARALLAX_CENTER g_ParallaxParms.g | |
#endif | |
sampler BaseTextureSampler : register(s0); // Base map, selfillum in alpha | |
sampler NormalTextureSampler : register(s1); // Normal map | |
sampler EnvmapSampler : register(s2); // Cubemap | |
sampler ShadowDepthSampler : register(s4); // Flashlight shadow depth map sampler | |
sampler RandRotSampler : register(s5); // RandomRotation sampler | |
sampler FlashlightSampler : register(s6); // Flashlight cookie | |
sampler LightmapSampler : register(s7); // Lightmap | |
sampler MRAOTextureSampler : register(s10); // MRAO texture | |
#if EMISSIVE | |
sampler EmissionTextureSampler : register(s11); // Emission texture | |
#endif | |
#if SPECULAR | |
sampler SpecularTextureSampler : register(s12); // Specular F0 texture | |
#endif | |
#define ENVMAPLOD (g_EyePos.a) | |
struct PSInput { | |
float2 baseTexCoord : TEXCOORD0; | |
float4 lightAtten : TEXCOORD1; | |
float3 worldNormal : TEXCOORD2; | |
float3 worldPos : TEXCOORD3; | |
float3 projPos : TEXCOORD4; | |
float4 lightmapTexCoord1And2 : TEXCOORD5; | |
float4 lightmapTexCoord3 : TEXCOORD6; | |
}; | |
// Entry point | |
float4 main(PSInput i) : COLOR | |
{ | |
#if USEENVAMBIENT | |
float3 EnvAmbientCube[6]; | |
setupEnvMapAmbientCube(EnvAmbientCube, EnvmapSampler); | |
#else | |
#define EnvAmbientCube cAmbientCube | |
#endif | |
float3 surfNormal = normalize(i.worldNormal); | |
float3 surfTangent; | |
float3 surfBase; | |
float flipSign; | |
float3x3 normalBasis = compute_tangent_frame(surfNormal, i.worldPos, i.baseTexCoord , surfTangent, surfBase, flipSign); | |
#if PARALLAXOCCLUSION | |
float3 outgoingLightRay = g_EyePos.xyz - i.worldPos; | |
float3 outgoingLightDirectionTS = worldToRelative( outgoingLightRay, surfTangent, surfBase, surfNormal); | |
float2 correctedTexCoord = parallaxCorrect(i.baseTexCoord, outgoingLightDirectionTS , NormalTextureSampler , PARALLAX_DEPTH , PARALLAX_CENTER); | |
#else | |
float2 correctedTexCoord = i.baseTexCoord; | |
#endif | |
float3 textureNormal = normalize((tex2D( NormalTextureSampler, correctedTexCoord).xyz - float3(0.5, 0.5, 0.5)) * 2); | |
float3 normal = normalize(mul(textureNormal, normalBasis)); // World Normal | |
float4 albedo = tex2D(BaseTextureSampler, correctedTexCoord); | |
albedo.xyz *= g_BaseColor.xyz; | |
float3 mrao = tex2D(MRAOTextureSampler, correctedTexCoord).xyz; | |
float metalness = mrao.x, roughness = mrao.y, ambientOcclusion = mrao.z; | |
#if EMISSIVE | |
float3 emission = tex2D(EmissionTextureSampler, correctedTexCoord).xyz; | |
#endif | |
#if SPECULAR | |
float3 specular = tex2D(SpecularTextureSampler, correctedTexCoord).xyz; | |
#endif | |
textureNormal.y *= flipSign; // Fixup textureNormal for ambient lighting | |
float3 outgoingLightDirection = normalize(g_EyePos.xyz - i.worldPos); // Lo | |
float lightDirectionAngle = max(0, dot(normal, outgoingLightDirection)); // cosLo | |
float3 specularReflectionVector = 2.0 * lightDirectionAngle * normal - outgoingLightDirection; // Lr | |
#if SPECULAR | |
float3 fresnelReflectance = specular.rgb; // F0 | |
#else | |
float3 dielectricCoefficient = 0.04; //F0 dielectric | |
float3 fresnelReflectance = lerp(dielectricCoefficient, albedo.rgb, metalness); // F0 | |
#endif | |
// Start ambient | |
float3 ambientLighting = 0.0; | |
if (!FLASHLIGHT) | |
{ | |
float3 diffuseIrradiance = ambientLookup(normal, EnvAmbientCube, textureNormal, i.lightmapTexCoord1And2, i.lightmapTexCoord3, LightmapSampler, g_DiffuseModulation); | |
float3 ambientLightingFresnelTerm = fresnelSchlickRoughness(fresnelReflectance, lightDirectionAngle, roughness); // F | |
#if SPECULAR | |
float3 diffuseContributionFactor = 1 - ambientLightingFresnelTerm; // kd | |
#else | |
float3 diffuseContributionFactor = lerp(1 - ambientLightingFresnelTerm, 0, metalness); ; // kd | |
#endif | |
float3 diffuseIBL = diffuseContributionFactor * albedo.rgb * diffuseIrradiance; | |
float4 specularUV = float4(specularReflectionVector, roughness * ENVMAPLOD); | |
float3 lookupHigh = ENV_MAP_SCALE * texCUBElod(EnvmapSampler, specularUV).xyz; | |
float3 lookupLow = PixelShaderAmbientLight(specularReflectionVector, EnvAmbientCube); | |
float3 specularIrradiance = lerp(lookupHigh, lookupLow, roughness * roughness); | |
float3 specularIBL = specularIrradiance * EnvBRDFApprox(fresnelReflectance, roughness, lightDirectionAngle); | |
ambientLighting = (diffuseIBL + specularIBL) * ambientOcclusion; | |
} | |
// End ambient | |
// Start direct | |
float3 directLighting = 0.0; | |
if (!FLASHLIGHT) { | |
for (uint n = 0; n < NUM_LIGHTS; ++n) { | |
float3 LightIn = normalize(PixelShaderGetLightVector(i.worldPos, cLightInfo, n)); | |
float3 LightColor = PixelShaderGetLightColor(cLightInfo, n) * GetAttenForLight(i.lightAtten, n); // Li | |
directLighting += calculateLight(LightIn, LightColor, outgoingLightDirection, normal, fresnelReflectance, roughness, metalness, lightDirectionAngle, albedo.rgb); | |
} | |
} | |
// End direct | |
// Start flashlight | |
if (FLASHLIGHT) { | |
float4 flashlightSpacePosition = mul(float4(i.worldPos, 1.0), g_FlashlightWorldToTexture); | |
clip( flashlightSpacePosition.w ); // stop projected textures from projecting backwards (only really happens if they have a big FOV because they get frustum culled.) | |
float3 vProjCoords = flashlightSpacePosition.xyz / flashlightSpacePosition.w; | |
float3 delta = g_FlashlightPos.xyz - i.worldPos; | |
float distSquared = dot(delta, delta); | |
float dist = sqrt(distSquared); | |
float3 flashlightColor = tex2D(FlashlightSampler, vProjCoords.xy).xyz; | |
flashlightColor *= cFlashlightColor.xyz; | |
#if FLASHLIGHTSHADOWS | |
float flashlightShadow = DoFlashlightShadow(ShadowDepthSampler, RandRotSampler, vProjCoords, i.projPos.xy, FLASHLIGHTDEPTHFILTERMODE, g_ShadowTweaks, true); | |
float flashlightAttenuated = lerp(flashlightShadow, 1.0, g_ShadowTweaks.y); // Blend between fully attenuated and not attenuated | |
float fAtten = saturate(dot(g_FlashlightAttenuationFactors.xyz, float3(1.0, 1.0 / dist, 1.0 / distSquared))); | |
flashlightShadow = saturate(lerp(flashlightAttenuated, flashlightShadow, fAtten)); // Blend between shadow and above, according to light attenuation | |
flashlightColor *= flashlightShadow; | |
#endif | |
float farZ = g_FlashlightAttenuationFactors.w; | |
float endFalloffFactor = RemapValClamped(dist, farZ, 0.6 * farZ, 0.0, 1.0); | |
float3 flashLightIntensity = flashlightColor * endFalloffFactor; | |
float3 flashLightIn = normalize(g_FlashlightPos.xyz - i.worldPos); | |
directLighting += max(0, calculateLight(flashLightIn, flashLightIntensity, outgoingLightDirection, normal, fresnelReflectance, roughness, metalness, lightDirectionAngle, albedo.rgb)); | |
} | |
// End flashlight | |
float fogFactor = 0.0f; | |
#if !FLASHLIGHT | |
fogFactor = CalcPixelFogFactor(PIXELFOGTYPE, g_FogParams, g_EyePos.z, i.worldPos.z, i.projPos.z); | |
#endif | |
float alpha = 0.0f; | |
#if !FLASHLIGHT | |
#if WRITEWATERFOGTODESTALPHA && (PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT) | |
alpha = fogFactor; | |
#else | |
alpha = albedo.a; | |
#endif | |
#endif | |
bool bWriteDepthToAlpha = (WRITE_DEPTH_TO_DESTALPHA != 0) && (WRITEWATERFOGTODESTALPHA == 0); | |
float3 combinedLighting = directLighting + ambientLighting; | |
#if EMISSIVE && !FLASHLIGHT | |
combinedLighting += emission; | |
#endif | |
return FinalOutput(float4(combinedLighting, alpha), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, bWriteDepthToAlpha, i.projPos.z); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DYNAMIC: "COMPRESSED_VERTS" "0..1" | |
// DYNAMIC: "DOWATERFOG" "0..1" | |
// DYNAMIC: "SKINNING" "0..1" | |
// DYNAMIC: "LIGHTING_PREVIEW" "0..1" | |
// DYNAMIC: "NUM_LIGHTS" "0..4" | |
#include "common_vs_fxc.h" | |
static const bool g_bSkinning = SKINNING; | |
static const int g_FogType = DOWATERFOG; | |
const float4 cBaseTexCoordTransform[2] : register(SHADER_SPECIFIC_CONST_0); | |
struct VSInput { | |
float4 vPos : POSITION; | |
float4 vBoneWeights : BLENDWEIGHT; | |
float4 vBoneIndices : BLENDINDICES; | |
float4 vNormal : NORMAL; | |
float2 vTexCoord0 : TEXCOORD0; | |
float4 vLightmapTexCoord : TEXCOORD1; | |
float4 vLightmapTexCoordOffset : TEXCOORD2; | |
}; | |
struct VSOutput { | |
float4 projPosSetup : POSITION; | |
float fog : FOG; | |
float2 baseTexCoord : TEXCOORD0; | |
float4 lightAtten : TEXCOORD1; | |
float3 worldNormal : TEXCOORD2; | |
float3 worldPos : TEXCOORD3; | |
float3 projPos : TEXCOORD4; | |
float4 lightmapTexCoord1And2 : TEXCOORD5; | |
float4 lightmapTexCoord3 : TEXCOORD6; | |
}; | |
VSOutput main(const VSInput input) | |
{ | |
VSOutput output = (VSOutput)0; | |
output.lightmapTexCoord3.z = dot(input.vTexCoord0, cBaseTexCoordTransform[0].xy) + cBaseTexCoordTransform[0].w; | |
output.lightmapTexCoord3.w = dot(input.vTexCoord0, cBaseTexCoordTransform[1].xy) + cBaseTexCoordTransform[1].w; | |
output.lightmapTexCoord1And2.xy = input.vLightmapTexCoord.xy + input.vLightmapTexCoordOffset.xy; | |
float2 lightmapTexCoord2 = output.lightmapTexCoord1And2.xy + input.vLightmapTexCoordOffset.xy; | |
float2 lightmapTexCoord3 = lightmapTexCoord2 + input.vLightmapTexCoordOffset.xy; | |
// Reversed component order | |
output.lightmapTexCoord1And2.w = lightmapTexCoord2.x; | |
output.lightmapTexCoord1And2.z = lightmapTexCoord2.y; | |
output.lightmapTexCoord3.xy = lightmapTexCoord3; | |
float3 vNormal; | |
DecompressVertex_Normal(input.vNormal, vNormal); | |
float3 worldNormal, worldPos; | |
SkinPositionAndNormal(g_bSkinning, input.vPos, vNormal, input.vBoneWeights, input.vBoneIndices, worldPos, worldNormal); | |
// Transform into projection space | |
float4 vProjPos = mul(float4(worldPos, 1), cViewProj); | |
output.projPosSetup = vProjPos; | |
vProjPos.z = dot(float4(worldPos, 1), cViewProjZ); | |
output.projPos = vProjPos.xyz; | |
output.fog = CalcFog(worldPos, vProjPos.xyz, g_FogType); | |
// Needed for water fog alpha and diffuse lighting | |
output.worldPos = worldPos; | |
output.worldNormal = normalize(worldNormal); | |
// Scalar attenuations for four lights | |
output.lightAtten = float4(0, 0, 0, 0); | |
#if NUM_LIGHTS > 0 | |
output.lightAtten.x = GetVertexAttenForLight(worldPos, 0, false); | |
#endif | |
#if NUM_LIGHTS > 1 | |
output.lightAtten.y = GetVertexAttenForLight(worldPos, 1, false); | |
#endif | |
#if NUM_LIGHTS > 2 | |
output.lightAtten.z = GetVertexAttenForLight(worldPos, 2, false); | |
#endif | |
#if NUM_LIGHTS > 3 | |
output.lightAtten.w = GetVertexAttenForLight(worldPos, 3, false); | |
#endif | |
// Base texture coordinate transform | |
output.baseTexCoord.x = dot(input.vTexCoord0, cBaseTexCoordTransform[0].xy); | |
output.baseTexCoord.y = dot(input.vTexCoord0, cBaseTexCoordTransform[1].xy); | |
output.baseTexCoord = input.vTexCoord0; | |
return output; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment