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.
130 lines
4.1 KiB
130 lines
4.1 KiB
// DYNAMIC: "FOGTYPE" "0..1" |
|
|
|
#include "common_vs_fxc.h" |
|
|
|
static const int g_FogType = FOGTYPE; |
|
const float4 cCustomConstants[6] : register( SHADER_SPECIFIC_CONST_0 ); |
|
|
|
|
|
const float4 g_vLightPosition : register( SHADER_SPECIFIC_CONST_0 ); |
|
const float4 g_vLightColor : register( SHADER_SPECIFIC_CONST_1 ); // range 0-1 |
|
const float g_flLightIntensity : register( SHADER_SPECIFIC_CONST_2 ); // scales g_vLightColor |
|
|
|
|
|
struct VS_INPUT |
|
{ |
|
// If this is float4, and the input is float3, the w component default to one. |
|
float4 vPos : POSITION; |
|
float2 vBumpTexCoord : TEXCOORD0; |
|
float4 vAmbientColor : COLOR0; |
|
}; |
|
|
|
struct VS_OUTPUT |
|
{ |
|
float4 projPos : POSITION; |
|
#if !defined( _X360 ) |
|
float fog : FOG; |
|
#endif |
|
float2 vBumpTexCoord : TEXCOORD0; |
|
float3 vTangentSpaceLightDir : TEXCOORD1; |
|
float3 vAmbientColor : TEXCOORD2; |
|
|
|
#if defined( _X360 ) |
|
float4 vScreenPos_ReverseZ : TEXCOORD3; |
|
#else |
|
float4 vScreenPos : TEXCOORD3; |
|
#endif |
|
|
|
|
|
float4 vDirLightScale : COLOR0; |
|
|
|
float4 worldPos_projPosZ : TEXCOORD7; // Necessary for pixel fog |
|
}; |
|
|
|
VS_OUTPUT main( const VS_INPUT v ) |
|
{ |
|
VS_OUTPUT o; |
|
|
|
// Transform the input position. |
|
float4 projPos = mul( v.vPos, cModelViewProj ); |
|
o.projPos = projPos; |
|
projPos.z = dot( v.vPos, cModelViewProjZ ); |
|
|
|
#if defined( _X360 ) |
|
o.vScreenPos_ReverseZ.x = projPos.x; |
|
o.vScreenPos_ReverseZ.y = -projPos.y; // invert Y |
|
o.vScreenPos_ReverseZ.xy = (o.vScreenPos_ReverseZ.xy + projPos.w) * 0.5f; |
|
o.vScreenPos_ReverseZ.z = projPos.w - projPos.z; |
|
o.vScreenPos_ReverseZ.w = projPos.w; |
|
#else |
|
o.vScreenPos.x = projPos.x; |
|
o.vScreenPos.y = -projPos.y; // invert Y |
|
o.vScreenPos.xy = (o.vScreenPos.xy + projPos.w) * 0.5f; |
|
o.vScreenPos.z = projPos.z; |
|
o.vScreenPos.w = projPos.w; |
|
#endif |
|
|
|
o.worldPos_projPosZ = float4( v.vPos.xyz, projPos.z ); |
|
|
|
#if !defined( _X360 ) |
|
// Setup fog. |
|
o.fog = CalcFog( mul( v.vPos, cModel[0] ), projPos, g_FogType ); |
|
#endif |
|
|
|
// Copy texcoords over. |
|
o.vBumpTexCoord = v.vBumpTexCoord; |
|
|
|
// Copy the vertex color over. |
|
o.vAmbientColor = v.vAmbientColor; |
|
|
|
// ------------------------------------------------------------------------------ |
|
// Generate a tangent space and rotate L. |
|
// This can be thought of as rotating the normal map to face the viewer. |
|
// |
|
// This is useful when a particle is way off to the side of the screen. |
|
// You should be looking at the half-sphere with a normal pointing from the |
|
// particle to the viewer. Instead, you're looking at the half-sphere with |
|
// a normal along Z. This tangent space builder code fixes the problem. |
|
// |
|
// Note that since the model and view matrices are identity, the coordinate |
|
// system has X=right, Y=up, and Z=behind you (negative Z goes into the screen). |
|
// ------------------------------------------------------------------------------ |
|
|
|
// This basis wants Z positive going into the screen so flip it here. |
|
float4 vForward = normalize( float4( v.vPos.x, v.vPos.y, -v.vPos.z, 1 ) ); |
|
|
|
// This is the same as CrossProduct( vForward, Vector( 1, 0, 0 ) ) |
|
float4 vUp = normalize( float4( 0, vForward.z, -vForward.y, vForward.w ) ); |
|
|
|
// vRight = CrossProduct( vUp, vForward ) |
|
float4 vRight = vUp.yzxw * vForward.zxyw; |
|
vRight += -vUp.zxyw * vForward.yzxw; |
|
|
|
|
|
// Put the light in tangent space. |
|
float4 vToLight = g_vLightPosition - v.vPos; |
|
float4 vTangentSpaceLight = vRight*vToLight.x + vUp*vToLight.y + vForward*vToLight.z; |
|
|
|
// Output texcoord 1 holds the normalized transformed light direction. |
|
o.vTangentSpaceLightDir = normalize( vTangentSpaceLight ) * 0.5 + 0.5; // make it 0-1 for the pixel shader |
|
|
|
|
|
// Handle oversaturation here. The shader code already scaled the light color so its max value is 1, |
|
// so if our intensity/distance scale is > 1, then all we need to do is use the light color. |
|
float flTransposedLenSqr = dot( vTangentSpaceLight, vTangentSpaceLight ); |
|
float flScaledIntensity = g_flLightIntensity / flTransposedLenSqr; |
|
if ( flScaledIntensity > 1 ) |
|
{ |
|
o.vDirLightScale.xyz = g_vLightColor; |
|
} |
|
else |
|
{ |
|
o.vDirLightScale.xyz = g_vLightColor * flScaledIntensity; |
|
} |
|
|
|
// Alpha comes right from the vertex color. |
|
o.vDirLightScale.a = v.vAmbientColor.a; |
|
return o; |
|
} |
|
|
|
|
|
|