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
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 );
|
|
}
|
|
|