1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
// STATIC: "CONVERT_TO_SRGB" "0..1" [ps20b][= g_pHardwareConfig->NeedsShaderSRGBConversion()] [PC]
// STATIC: "CONVERT_TO_SRGB" "0..1" [ps30][= g_pHardwareConfig->NeedsShaderSRGBConversion()] [PC]
// STATIC: "CONVERT_TO_SRGB" "0..0" [= 0] [XBOX]
// STATIC: "LIGHTWARPTEXTURE" "0..1"
// DYNAMIC: "PIXELFOGTYPE" "0..1"
// DYNAMIC: "WRITEWATERFOGTODESTALPHA" "0..1"
// DYNAMIC: "NUM_LIGHTS" "0..2" [ps20]
// DYNAMIC: "NUM_LIGHTS" "0..4" [ps20b]
// DYNAMIC: "NUM_LIGHTS" "0..4" [ps30]
#include "shader_constant_register_map.h"
sampler BaseSampler : register( s0 ); // Base map
sampler DiffuseWarpSampler : register( s1 ); // 1D texture for diffuse lighting modification
sampler RefractSampler : register( s2 ); // Refraction map copied from back buffer
sampler NormalSampler : register( s3 ); // Normal map
sampler SpecExponentSampler : register( s4 ); // Flashlight cookie
sampler NormalizeSampler : register( s5 ); // Normalization cube map
const float3x3 g_ViewProj : register( c0 ); // 1st row of Projection matrix
// c1 // 2nd row
// c2 // 4th row
const float2 g_CloakControl : register( c3 ); // { refract amount, cloak, ?, ? }
const float3 cAmbientCube[6] : register( PSREG_AMBIENT_CUBE );
const float4 g_EyePos_SpecExponent : register( PSREG_EYEPOS_SPEC_EXPONENT );
const float4 g_FogParams : register( PSREG_FOG_PARAMS );
const float4 g_FlashlightAttenuationFactors_RimMask : register( PSREG_FLASHLIGHT_ATTENUATION ); // On non-flashlight pass, x has rim mask control
const float4 g_RimBoost : register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
const float4 g_FresnelSpecParams : register( PSREG_FRESNEL_SPEC_PARAMS ); // xyz are fresnel, w is specular boost
const float4 g_SpecularRimParams : register( PSREG_SPEC_RIM_PARAMS ); // xyz are specular tint color, w is rim power
PixelShaderLightInfo cLightInfo[3] : register( PSREG_LIGHT_INFO_ARRAY ); // 2 registers each - 6 registers total
#define g_fRimBoost g_RimBoost.w
#define g_FresnelRanges g_FresnelSpecParams.xyz
#define g_SpecularBoost g_FresnelSpecParams.w
#define g_SpecularTint g_SpecularRimParams.xyz
#define g_RimExponent g_SpecularRimParams.w
#define g_FlashlightAttenuationFactors g_FlashlightAttenuationFactors_RimMask
#define g_RimMaskControl g_FlashlightAttenuationFactors_RimMask.x
// 8 2D Poisson offsets (designed to use .xy and .wz swizzles (not .zw)
static const float4 gPoissonOffset[4] = { float4 (-0.0876f, 0.9703f, 0.5651f, 0.4802f ),
float4 ( 0.1851f, 0.1580f, -0.0617f, -0.2616f ),
float4 (-0.5477f, -0.6603f, 0.0711f, -0.5325f ),
float4 (-0.0751f, -0.8954f, 0.4054f, 0.6384f ) };
struct PS_INPUT
{
float2 vBaseTexCoord : TEXCOORD0;
float3x3 tangentSpaceTranspose : TEXCOORD1;
// second row : TEXCOORD2;
// third row : TEXCOORD3;
float3 worldPos : TEXCOORD4;
float3 projPos : TEXCOORD5;
float4 lightAtten : TEXCOORD6;
};
float4 main( PS_INPUT i ) : COLOR
{
float3 vSpecular = float3( 0.0f, 0.0f, 0.0f );
bool bDoDiffuseWarp = LIGHTWARPTEXTURE ? true : false;
int nNumLights = NUM_LIGHTS;
// Base color
float4 albedo = tex2D( BaseSampler, i.vBaseTexCoord );
// Load normal and expand range
float4 vNormalSample = tex2D( NormalSampler, i.vBaseTexCoord );
float3 tangentSpaceNormal = 2.0f * vNormalSample.xyz - 1.0f;
// We need a world space normal if we're doing any lighting
float3 vWorldNormal = normalize( mul( i.tangentSpaceTranspose, tangentSpaceNormal ) );
float3 vWorldEyeDir = normalize( g_EyePos_SpecExponent.xyz - i.worldPos );
// Vanilla 1-(N.V) fresnel term used later in transition lerp
float fresnel = 1-saturate( dot( vWorldNormal, vWorldEyeDir ) );
// Summation of diffuse illumination from all local lights
float3 diffuseLighting = PixelShaderDoLighting( i.worldPos, vWorldNormal,
float3( 0.0f, 0.0f, 0.0f ), false,
true, i.lightAtten, cAmbientCube, NormalizeSampler,
nNumLights, cLightInfo, true, false, 1.0f,
bDoDiffuseWarp, DiffuseWarpSampler );
// Transform world space normal into clip space and project
float2 vProjNormal;
vProjNormal.x = dot( vWorldNormal, g_ViewProj[0] ); // 1st row
vProjNormal.y = dot( vWorldNormal, g_ViewProj[1] ); // 2nd row
// Compute coordinates for sampling refraction
float2 vRefractTexCoordNoWarp = i.projPos.xy / i.projPos.z;
float2 vRefractTexCoord = vProjNormal.xy;
float scale = lerp( g_CloakControl.x, 0.0f, g_CloakControl.y );
vRefractTexCoord *= scale;
vRefractTexCoord += vRefractTexCoordNoWarp;
#ifdef SHADER_MODEL_PS_2_0
float3 vRefract = tex2D( RefractSampler, vRefractTexCoordNoWarp );
#endif
// Extra refraction rays, specular, rim etc are only done on ps_2_b
#if defined( SHADER_MODEL_PS_2_B ) || defined( SHADER_MODEL_PS_3_0 )
// Blur by scalable Poisson filter
float fBlurAmount = lerp( 0.05f, 0.0f, g_CloakControl.y );
float3 vRefract = tex2D( RefractSampler, vRefractTexCoord );
vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[0].xy * fBlurAmount );
vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[0].wz * fBlurAmount );
vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[1].xy * fBlurAmount );
vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[1].wz * fBlurAmount );
vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[2].xy * fBlurAmount );
vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[2].wz * fBlurAmount );
// We're right at the hairy edge of constant register usage and hence have to drop these taps...
// vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[3].xy * fBlurAmount );
// vRefract += tex2D( RefractSampler, vRefractTexCoord + gPoissonOffset[3].wz * fBlurAmount );
vRefract /= 7.0f;
float3 rimLighting = float3( 0.0f, 0.0f, 0.0f );
float3 specularLighting = float3( 0.0f, 0.0f, 0.0f );
float fSpecExp = g_EyePos_SpecExponent.w;
float fSpecMask = vNormalSample.a;
float4 vSpecExpMap = tex2D( SpecExponentSampler, i.vBaseTexCoord );
float fSpecExpMap = vSpecExpMap.r;
float fRimMask = 1.0f;//lerp( 1.0f, vSpecExpMap.a, g_RimMaskControl ); // Select rim mask
float3 vSpecularTint;
// If the exponent passed in as a constant is zero, use the value from the map as the exponent
if ( fSpecExp == 0 )
fSpecExp = 1.0f - fSpecExpMap + 150.0f * fSpecExpMap;
// If constant tint is negative, tint with albedo, based upon scalar tint map
if ( g_SpecularTint.r == -1 )
vSpecularTint = lerp( float3(1.0f, 1.0f, 1.0f), albedo, vSpecExpMap.g );
else
vSpecularTint = g_SpecularTint.rgb;
// Fresnel to match regular specular lighting
float fFresnelRanges = Fresnel( vWorldNormal, vWorldEyeDir, g_FresnelRanges );
// Summation of specular from all local lights besides the flashlight
PixelShaderDoSpecularLighting( i.worldPos, vWorldNormal, fSpecExp, vWorldEyeDir,
i.lightAtten, nNumLights, cLightInfo, false, 1.0f, false,
NormalizeSampler, 1.0f, true, g_RimExponent,
// Outputs
specularLighting, rimLighting );
// Modulate with spec mask, boost, tint and fresnel ranges
specularLighting *= fSpecMask * g_SpecularBoost * fFresnelRanges * vSpecularTint;
float fRimFresnel = Fresnel4( vWorldNormal, vWorldEyeDir );
// Add in rim light modulated with tint, mask and traditional Fresnel (not using Fresnel ranges)
rimLighting *= vSpecularTint * fRimMask * fRimFresnel;
// Fold rim lighting into specular term by using the max so that we don't really add light twice...
specularLighting = max (specularLighting, rimLighting);
// Add in view-ray lookup from ambient cube
specularLighting += fRimFresnel * fRimMask * vSpecularTint /* g_fRimBoost */ * PixelShaderAmbientLight( vWorldEyeDir, cAmbientCube) * saturate(dot(vWorldNormal, float3(0, 0 , 1)) );
float tintLerpFactor = saturate(lerp( 1, fresnel-1.1, saturate(g_CloakControl.y)));
tintLerpFactor = smoothstep( 0.4f, 0.425f, tintLerpFactor );
float3 vTintedRefract = lerp( vRefract, albedo * vRefract, 0.7f );
vRefract = lerp( vRefract, vTintedRefract, tintLerpFactor );
vSpecular = specularLighting * smoothstep( 0.98, 0.8, saturate(g_CloakControl.y ));
#endif
// Blend refraction component with diffusely lit model
float diffuseLerpFactor = saturate(lerp( 1, fresnel - 1.35, saturate(g_CloakControl.y)));
diffuseLerpFactor = smoothstep( 0.4f, 0.425f, diffuseLerpFactor );
float3 fDiffuse = lerp( vRefract, albedo * diffuseLighting, diffuseLerpFactor );
float3 result = fDiffuse + vSpecular;
float alpha = 1.0f;
// Emulate LinearColorToHDROutput() when uncloaked
result = lerp( result.xyz * LINEAR_LIGHT_SCALE, result, saturate(g_CloakControl.y) );
float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos_SpecExponent.z, i.worldPos.z, i.projPos.z );
#if WRITEWATERFOGTODESTALPHA && (PIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT)
alpha = fogFactor;
#endif
return FinalOutput( float4( result, alpha ), fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE );
}
|