Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

311 lines
12 KiB

// STATIC: "BUMPMAP" "0..2"
// STATIC: "CUBEMAP" "0..2"
// STATIC: "SEAMLESS" "0..1"
// STATIC: "THICKPAINT" "0..1"
// DYNAMIC: "FASTPATHENVMAPCONTRAST" "0..1"
// DYNAMIC: "FASTPATH" "0..1"
// SKIP: ( $BUMPMAP == 0 )
// Turning off 32bit lightmaps on Portal 2 to save shader perf. --Thorsten
//#define USE_32BIT_LIGHTMAPS_ON_360 // be sure to keep this in sync with the same #define in materialsystem/cmatlightmaps.cpp
#include "common_fog_ps_supportsvertexfog_fxc.h"
#include "common_ps_fxc.h"
#define PIXELSHADER
#include "common_lightmappedgeneric_fxc.h"
#if SEAMLESS
#define USE_FAST_PATH 1
#else
#define USE_FAST_PATH FASTPATH
#endif
const float4 g_EnvmapTint : register( c0 );
#if USE_FAST_PATH == 1
# if FASTPATHENVMAPCONTRAST == 0
static const float3 g_EnvmapContrast = { 0.0f, 0.0f, 0.0f };
# else
static const float3 g_EnvmapContrast = { 1.0f, 1.0f, 1.0f };
# endif
static const float3 g_EnvmapSaturation = { 1.0f, 1.0f, 1.0f };
static const float g_FresnelReflection = 1.0f;
static const float g_OneMinusFresnelReflection = 0.0f;
static const float4 g_SelfIllumTint = { 1.0f, 1.0f, 1.0f, 1.0f };
#else
const float3 g_EnvmapContrast : register( c2 );
const float3 g_EnvmapSaturation : register( c3 );
const float4 g_FresnelReflectionReg : register( c4 );
#define g_FresnelReflection g_FresnelReflectionReg.a
#define g_OneMinusFresnelReflection g_FresnelReflectionReg.b
const float4 g_SelfIllumTint : register( c7 );
#endif
const float3 g_EyePos : register( c10 );
const float4 g_FogParams : register( c11 );
const float4 g_TintValuesTimesLightmapScale : register( c12 );
#define g_flAlpha2 g_TintValuesTimesLightmapScale.w
#if PARALLAX_MAPPING || (CUBEMAP == 2)
const float4 g_ParallaxMappingControl : register( c20 );
#endif
#if (CUBEMAP == 2)
#define g_DiffuseCubemapScale g_ParallaxMappingControl.y
#endif
const float3 g_TintValuesWithoutLightmapScale : register( c21 );
// These constants are used to rotate the world space water normals around the up axis to align the
// normal with the camera and then give us a 2D offset vector to use for reflection and refraction uv's
const float3 g_vWorldToViewRefract0 : register( c22 );
const float3 g_vWorldToViewRefract1 : register( c23 );
sampler LightmapSampler : register( s1 );
samplerCUBE EnvmapSampler : register( s2 );
sampler BubbleLayoutSampler : register( s4 );
sampler BubbleSampler : register( s5 );
sampler SplatNormalSampler : register( s7 );
sampler PaintSampler : register( s9 );
#if defined( _X360 )
[maxtempreg(36)]
#endif // _X360
float4_color_return_type main( PS_INPUT i ) : COLOR
{
float3 worldPos = i.worldPos_projPosZ.xyz;
float3x3 tangenttranspose = float3x3( i.tangentSpaceTranspose0_vertexBlendX.xyz, i.tangentSpaceTranspose1_bumpTexCoord2u.xyz, i.tangentSpaceTranspose2_bumpTexCoord2v.xyz );
float3x3 worldToTangentSpace = transpose( tangenttranspose ); //yay, math both forwards and backwards, for kicks!
float3 worldVertToEyeVector = g_EyePos - worldPos;
float3 lightmapColor1 = float3( 1.0f, 1.0f, 1.0f );
float3 lightmapColor2 = float3( 1.0f, 1.0f, 1.0f );
float3 lightmapColor3 = float3( 1.0f, 1.0f, 1.0f );
float2 bumpCoord1;
float2 bumpCoord2;
float2 bumpCoord3;
ComputeBumpedLightmapCoordinates( i.lightmapTexCoord1And2, i.lightmapTexCoord3_bumpTexCoord.xy,
bumpCoord1, bumpCoord2, bumpCoord3 );
float2 paintCoord = bumpCoord1.xy - ( bumpCoord2.xy - bumpCoord1.xy ); // remove offset from 1st of the bumped coords for vanilla coords
float4 paintColor = tex2D( PaintSampler, paintCoord );
#if ( THICKPAINT )
{
lightmapColor1 = LightMapSample( LightmapSampler, bumpCoord1 ).rgb;
lightmapColor2 = LightMapSample( LightmapSampler, bumpCoord2 ).rgb;
lightmapColor3 = LightMapSample( LightmapSampler, bumpCoord3 ).rgb;
}
#else
{
lightmapColor1 = LightMapSample( LightmapSampler, paintCoord ).rgb; // use vanilla lightmap coords, not bumped
}
#endif
float2 coords = paintCoord.xy * 40.0f;
coords.y *= 0.5f; // paint map is built scaled in y, so must compensate in other texture fetches
#if defined( SHADER_MODEL_PS_2_0 )
return paintColor;
#endif
float alpha = paintColor.a;
clip( alpha - 0.01f );
//paint splat guts
float3 fvNormalTs = float3( 0.0f, 0.0f, 1.0f );
float4 fvSplats = tex2D( SplatNormalSampler, coords );
float3 fvViewDirectionTs = normalize( mul( worldVertToEyeVector, worldToTangentSpace ) );
alpha = (paintColor.a + fvSplats.a ) * 0.5f; // vanilla combined alpha
float fPaintThickness = smoothstep( 0.34f, 0.63f, alpha );
float4 cMixedPaint = paintColor.rgba;
#if( THICKPAINT )
{
float4 fvSplatsPushed = tex2D( SplatNormalSampler, coords + fvViewDirectionTs * fvSplats.a * 0.01 );
float bumpedPaintArea = smoothstep( 0.6f, 0.3f, alpha ); //area in which to super-bump, ie the edges of the paint
bumpedPaintArea *= fPaintThickness;
fvNormalTs = ( fvSplatsPushed.xyz * 2.0f ) - 1.0f ;
fvNormalTs.xy *= lerp( 0.1f, 4.0f, bumpedPaintArea );
float2 fvPaintCoordsDistorted = paintCoord.xy + ( 0.003 - 0.006 * alpha );
cMixedPaint = tex2D( PaintSampler, fvPaintCoordsDistorted ); // use distorted UVs so that the blend between different paint colors isn't blocky
cMixedPaint.rgb = lerp( paintColor.rgb, cMixedPaint.rgb, smoothstep( 0.9f, 1.0f, cMixedPaint.a ) ); // avoid fetching too far by fading out distorted paint towards edges
}
#else
{
fvNormalTs = ( fvSplats.xyz * 2.0f ) - 1.0f;
}
#endif
// Always simulate srgb reads in shader code for the tex2Dsrgb calls since the paint textures look better when filtered in gamma space
#if ( _X360 )
{
#if defined( CSTRIKE15 )
// [mariod] - no PWL for cstrike15
cMixedPaint.rgb = GammaToLinear( cMixedPaint.rgb );
#else
cMixedPaint.rgb = X360GammaToLinear( cMixedPaint.rgb );
#endif
}
#else
{
cMixedPaint.rgb = SrgbGammaToLinear( cMixedPaint.rgb );
}
#endif
float3 vNormalWs = mul( fvNormalTs.xyz, tangenttranspose );
#if ( THICKPAINT )
float4 vN;
vN.x = dot( g_vWorldToViewRefract0.xyz, vNormalWs.xyz );
vN.y = dot( g_vWorldToViewRefract1.xyz, vNormalWs.xyz );
vN.wz = vN.xy;
float flD = (paintColor.a + fvSplats.a );
flD *= smoothstep( 1.0f, 2.0f, flD );
float4 vDependentTexCoords = vN.xyzw * flD;
float2 vRefractTexCoord = vDependentTexCoords.wz;
float2 fvLayoutCoords = coords.xy * 6.5f + fvViewDirectionTs.xy * 0.0014f;
float2 fvDeepLayoutCoords = fvLayoutCoords * 1.76f + fvViewDirectionTs.xy * 0.0007f;
fvLayoutCoords += fvViewDirectionTs.xy * 0.03; //single-step parallax so that the bubbles look higher than the surface they're on
float4 fvLayout = tex2D( BubbleLayoutSampler, fvLayoutCoords );
float4 fvDeepLayout = tex2D( BubbleLayoutSampler, fvDeepLayoutCoords );
fvLayout.xy -= 0.5f;
fvLayout.z *= smoothstep( 0.750f, 0.80f, alpha );
fvDeepLayout.xy -= 0.5f;
fvDeepLayout.z *= smoothstep( 0.40f, 0.75f, alpha );
// generate matrix for transforming UV coordinates to be screen-facing
// used by the paint to render bubbles that act like facing particles, but are distributed
// using a texture that describes the UV layout. Causing the UVs to face the camera
// ensures the bubbles always appear round
float3x3 matCameraFaceUVs;
matCameraFaceUVs[2] = fvViewDirectionTs; // new normal
matCameraFaceUVs[1] = float3( 0.0f, 1.0f, 0.0f ); // tangent
matCameraFaceUVs[0] = normalize( cross( matCameraFaceUVs[1].xyz, matCameraFaceUVs[2].xyz ) ); //binormal
matCameraFaceUVs[1] = normalize( cross( matCameraFaceUVs[2].xyz, matCameraFaceUVs[0].xyz ) ); //re-square tangent
// Should try to do it in vertex shader but lack of tesselation means interpolation is not so pretty
//float2x2 matCameraFaceUVs;
//matCameraFaceUVs[0].xy = i.detailOrBumpAndEnvmapMaskTexCoord.xy;
//matCameraFaceUVs[1].xy = i.detailOrBumpAndEnvmapMaskTexCoord.zw;
float2 fvBubbleCoords;
fvBubbleCoords.x = dot( fvLayout.xy, matCameraFaceUVs[0].xy );
fvBubbleCoords.y = dot( fvLayout.xy, matCameraFaceUVs[1].xy );
float2 fvDeepBubbleCoords;
fvDeepBubbleCoords.x = dot( fvDeepLayout.xy, matCameraFaceUVs[0].xy );
fvDeepBubbleCoords.y = dot( fvDeepLayout.xy, matCameraFaceUVs[1].xy );
float2 fvBubbleSurfaceCoords = fvLayout.xy * 0.5f + 0.5f;
fvBubbleCoords.xy = fvBubbleCoords.xy + 0.5f + vRefractTexCoord * 0.05;
fvDeepBubbleCoords.xy = fvDeepBubbleCoords.xy + 0.5f + vRefractTexCoord * 0.2;
float4 fvDeepBubbles = tex2D( BubbleSampler, fvDeepBubbleCoords.xy );
fvDeepBubbles = lerp( float4( 0.5f, 0.5f, 1.0f, 0.0f ), fvDeepBubbles, fvDeepLayout.z );
float4 fvBubbles = tex2D( BubbleSampler, fvBubbleCoords.xy );
fvBubbles = lerp( float4( 0.5f, 0.5f, 1.0f, 0.0f ), fvBubbles, fvLayout.z );
float3 fvSurfaceBubbles = tex2D( BubbleSampler, fvBubbleSurfaceCoords.xy ).xyz;
fvSurfaceBubbles.xyz = ( fvSurfaceBubbles.xyz * 2.0f ) - 1.0f;
fvSurfaceBubbles.xy *= -2.0f;
fvNormalTs.xyz += fvSurfaceBubbles.xyz * pow( fvLayout.z, 3.5f ) * 0.4f;
fvNormalTs.xyz = normalize( fvNormalTs.xyz );
float4 worldSpaceBubblesNormal = lerp( fvDeepBubbles * float4( 1.0f, 1.0f, 1.0f, 0.4f ), fvBubbles, fvBubbles.a );
worldSpaceBubblesNormal.xyz = mul( worldSpaceBubblesNormal.xyz * 2.0f - 1.0f, tangenttranspose );
worldSpaceBubblesNormal = normalize( worldSpaceBubblesNormal );
#endif
float3 diffuseLighting = float3( 0.0f, 0.0f, 0.0f );
#if ( THICKPAINT )
{
float3 dp;
dp.x = saturate( dot( fvNormalTs.xyz, bumpBasis[0] ) );
dp.y = saturate( dot( fvNormalTs.xyz, bumpBasis[1] ) );
dp.z = saturate( dot( fvNormalTs.xyz, bumpBasis[2] ) );
dp *= dp;
diffuseLighting = dp.x * lightmapColor1 +
dp.y * lightmapColor2 +
dp.z * lightmapColor3;
float sum = dot( dp, float3( 1.0f, 1.0f, 1.0f ) );
diffuseLighting *= g_TintValuesTimesLightmapScale.rgb / sum;
}
#else
{
diffuseLighting = lightmapColor1 * g_TintValuesTimesLightmapScale.rgb;
}
#endif
float3 diffuseComponent = diffuseLighting;
float fLum = dot( cMixedPaint.rgb, float3( 0.299f, 0.587f, 0.114f ) ) * 0.5f; //desaturated, darken
float3 cPaint = lerp( float3( fLum, fLum, fLum ), cMixedPaint.rgb, fPaintThickness ); //less thick areas should be less saturated
vNormalWs.xyz = mul( fvNormalTs, tangenttranspose );
float3 specularLighting = float3( 0.0f, 0.0f, 0.0f );
// Calc Fresnel factor
float3 eyeVect = normalize(worldVertToEyeVector);
float fresnel = dot( vNormalWs, eyeVect );
float3 reflectVect = CalcReflectionVectorUnnormalized( vNormalWs, worldVertToEyeVector );
#if ( THICKPAINT )
float3 reflectVectBubbles = CalcReflectionVectorUnnormalized( worldSpaceBubblesNormal.xyz, worldVertToEyeVector );
#endif
float fBubbleReflectLum = 0.0f;
#if ( CUBEMAP )
// Must use environment map scale to get proper behavior across platforms with different texture formats (divide by 16 because code was written on PC where env_map_scale is 16.0)
specularLighting += ( ENV_MAP_SCALE / 16.0f )* texCUBE( EnvmapSampler, reflectVect ).rgb * ( 1.5f - fresnel ) * 0.67f; //TODO: remove magic numbers
#if ( THICKPAINT )
float3 bubbleSpecularLighting = ( ENV_MAP_SCALE / 16.0f )* texCUBE( EnvmapSampler, reflectVectBubbles ).rgb * ( cPaint ) * worldSpaceBubblesNormal.a * fresnel * 2.0f;
specularLighting.rgb += bubbleSpecularLighting.rgb;
#endif
specularLighting *= ( 1.0f + diffuseComponent );
#endif
float3 result;
alpha = smoothstep( 0.40f, 0.45f, alpha );
#if ( THICKPAINT )
float alphaBubbles = fvBubbles.a * 0.3f + fvDeepBubbles.a * 0.2f;
alpha = alpha - alphaBubbles * 1.25f;
#endif
alpha *= 0.85f;
float3 fvTotalDiffuse = ( ( diffuseComponent * 0.82f ) + 0.04f ) * cPaint.rgb; // Make paint slightly emissive so we can see paint color on darkly lit surfaces
fvTotalDiffuse.rgb *= float3( 0.8f, 0.85f, 1.0f ); // This matches the code in paintblob_ps20b.fxc
result = fvTotalDiffuse.rgb + specularLighting.rgb;
float flVertexFogFactor = 0.0f;
float fogFactor = CalcPixelFogFactorSupportsVertexFog( PIXELFOGTYPE, g_FogParams, g_EyePos.xyz, worldPos, i.worldPos_projPosZ.w, flVertexFogFactor );
return FinalOutput( float4( result.rgb, alpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_LINEAR, false, i.worldPos_projPosZ.w );
}