Team Fortress 2 Source Code as on 22/4/2020
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.

955 lines
30 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This is where all common code for vertex shaders go.
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #ifndef COMMON_VS_FXC_H_
  9. #define COMMON_VS_FXC_H_
  10. #include "common_fxc.h"
  11. // Put global skip commands here. . make sure and check that the appropriate vars are defined
  12. // so these aren't used on the wrong shaders!
  13. // --------------------------------------------------------------------------------
  14. // Ditch all fastpath attemps if we are doing LIGHTING_PREVIEW.
  15. // SKIP: defined $LIGHTING_PREVIEW && defined $FASTPATH && $LIGHTING_PREVIEW && $FASTPATH
  16. // --------------------------------------------------------------------------------
  17. #ifndef COMPRESSED_VERTS
  18. // Default to no vertex compression
  19. #define COMPRESSED_VERTS 0
  20. #endif
  21. #if ( !defined( SHADER_MODEL_VS_2_0 ) && !defined( SHADER_MODEL_VS_3_0 ) )
  22. #if COMPRESSED_VERTS == 1
  23. #error "Vertex compression is only for DX9 and up!"
  24. #endif
  25. #endif
  26. // We're testing 2 normal compression methods
  27. // One compressed normals+tangents into a SHORT2 each (8 bytes total)
  28. // The other compresses them together, into a single UBYTE4 (4 bytes total)
  29. // FIXME: pick one or the other, compare lighting quality in important cases
  30. #define COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 0
  31. #define COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 1
  32. //#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2
  33. #define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4
  34. #define FOGTYPE_RANGE 0
  35. #define FOGTYPE_HEIGHT 1
  36. #define COMPILE_ERROR ( 1/0; )
  37. // -------------------------
  38. // CONSTANTS
  39. // -------------------------
  40. #pragma def ( vs, c0, 0.0f, 1.0f, 2.0f, 0.5f )
  41. const float4 cConstants1 : register(c1);
  42. #define cOOGamma cConstants1.x
  43. #define cOverbright 2.0f
  44. #define cOneThird cConstants1.z
  45. #define cOOOverbright ( 1.0f / 2.0f )
  46. // The g_bLightEnabled registers and g_nLightCountRegister hold the same information regarding
  47. // enabling lights, but callers internal to this file tend to use the loops, while external
  48. // callers will end up using the booleans
  49. const bool g_bLightEnabled[4] : register(b0);
  50. // through b3
  51. const int g_nLightCountRegister : register(i0);
  52. #define g_nLightCount g_nLightCountRegister.x
  53. const float4 cEyePosWaterZ : register(c2);
  54. #define cEyePos cEyePosWaterZ.xyz
  55. // Only cFlexScale.x is used
  56. // It is a binary value used to switch on/off the addition of the flex delta stream
  57. const float4 cFlexScale : register( c3 );
  58. const float4x4 cModelViewProj : register(c4);
  59. const float4x4 cViewProj : register(c8);
  60. // Used to compute projPosZ in shaders without skinning
  61. // Using cModelViewProj with FastClip generates incorrect results
  62. // This is just row two of the non-FastClip cModelViewProj matrix
  63. const float4 cModelViewProjZ : register(c12);
  64. // More constants working back from the top...
  65. const float4 cViewProjZ : register(c13);
  66. const float4 cFogParams : register(c16);
  67. #define cFogEndOverFogRange cFogParams.x
  68. #define cFogOne cFogParams.y
  69. #define cFogMaxDensity cFogParams.z
  70. #define cOOFogRange cFogParams.w
  71. const float4x4 cViewModel : register(c17);
  72. const float3 cAmbientCubeX [ 2 ] : register ( c21 ) ;
  73. const float3 cAmbientCubeY [ 2 ] : register ( c23 ) ;
  74. const float3 cAmbientCubeZ [ 2 ] : register ( c25 ) ;
  75. #if defined ( SHADER_MODEL_VS_3_0 )
  76. const float4 cFlexWeights [ 512 ] : register ( c1024 ) ;
  77. #endif
  78. struct LightInfo
  79. {
  80. float4 color; // {xyz} is color w is light type code (see comment below)
  81. float4 dir; // {xyz} is dir w is light type code
  82. float4 pos;
  83. float4 spotParams;
  84. float4 atten;
  85. };
  86. // w components of color and dir indicate light type:
  87. // 1x - directional
  88. // 01 - spot
  89. // 00 - point
  90. // Four lights x 5 constants each = 20 constants
  91. LightInfo cLightInfo[4] : register(c27);
  92. #define LIGHT_0_POSITION_REG c29
  93. #ifdef SHADER_MODEL_VS_1_1
  94. const float4 cModulationColor : register(c37);
  95. #define SHADER_SPECIFIC_CONST_0 c38
  96. #define SHADER_SPECIFIC_CONST_1 c39
  97. #define SHADER_SPECIFIC_CONST_2 c40
  98. #define SHADER_SPECIFIC_CONST_3 c41
  99. #define SHADER_SPECIFIC_CONST_4 c42
  100. #define SHADER_SPECIFIC_CONST_5 c43
  101. #define SHADER_SPECIFIC_CONST_6 c44
  102. #define SHADER_SPECIFIC_CONST_7 c45
  103. #define SHADER_SPECIFIC_CONST_8 c46
  104. #define SHADER_SPECIFIC_CONST_9 c47
  105. #define SHADER_SPECIFIC_CONST_10 c14
  106. #define SHADER_SPECIFIC_CONST_11 c15
  107. static const int cModel0Index = 48;
  108. const float4x3 cModel[16] : register(c48);
  109. // last cmodel is c105 for dx80, c214 for dx90
  110. #else // DX9 shaders (vs20 and beyond)
  111. const float4 cModulationColor : register( c47 );
  112. #define SHADER_SPECIFIC_CONST_0 c48
  113. #define SHADER_SPECIFIC_CONST_1 c49
  114. #define SHADER_SPECIFIC_CONST_2 c50
  115. #define SHADER_SPECIFIC_CONST_3 c51
  116. #define SHADER_SPECIFIC_CONST_4 c52
  117. #define SHADER_SPECIFIC_CONST_5 c53
  118. #define SHADER_SPECIFIC_CONST_6 c54
  119. #define SHADER_SPECIFIC_CONST_7 c55
  120. #define SHADER_SPECIFIC_CONST_8 c56
  121. #define SHADER_SPECIFIC_CONST_9 c57
  122. #define SHADER_SPECIFIC_CONST_10 c14
  123. #define SHADER_SPECIFIC_CONST_11 c15
  124. static const int cModel0Index = 58;
  125. const float4x3 cModel[53] : register( c58 );
  126. // last cmodel is c105 for dx80, c216 for dx90
  127. #define SHADER_SPECIFIC_BOOL_CONST_0 b4
  128. #define SHADER_SPECIFIC_BOOL_CONST_1 b5
  129. #define SHADER_SPECIFIC_BOOL_CONST_2 b6
  130. #define SHADER_SPECIFIC_BOOL_CONST_3 b7
  131. #define SHADER_SPECIFIC_BOOL_CONST_4 b8
  132. #define SHADER_SPECIFIC_BOOL_CONST_5 b9
  133. #define SHADER_SPECIFIC_BOOL_CONST_6 b10
  134. #define SHADER_SPECIFIC_BOOL_CONST_7 b11
  135. #endif // vertex shader model constant packing changes
  136. //=======================================================================================
  137. // Methods to decompress vertex normals
  138. //=======================================================================================
  139. //-----------------------------------------------------------------------------------
  140. // Decompress a normal from two-component compressed format
  141. // We expect this data to come from a signed SHORT2 stream in the range of -32768..32767
  142. //
  143. // -32678 and 0 are invalid encodings
  144. // w contains the sign to use in the cross product when generating a binormal
  145. void _DecompressShort2Tangent( float2 inputTangent, out float4 outputTangent )
  146. {
  147. float2 ztSigns = sign( inputTangent ); // sign bits for z and tangent (+1 or -1)
  148. float2 xyAbs = abs( inputTangent ); // 1..32767
  149. outputTangent.xy = (xyAbs - 16384.0f) / 16384.0f; // x and y
  150. outputTangent.z = ztSigns.x * sqrt( saturate( 1.0f - dot( outputTangent.xy, outputTangent.xy ) ) );
  151. outputTangent.w = ztSigns.y;
  152. }
  153. //-----------------------------------------------------------------------------------
  154. // Same code as _DecompressShort2Tangent, just one returns a float4, one a float3
  155. void _DecompressShort2Normal( float2 inputNormal, out float3 outputNormal )
  156. {
  157. float4 result;
  158. _DecompressShort2Tangent( inputNormal, result );
  159. outputNormal = result.xyz;
  160. }
  161. //-----------------------------------------------------------------------------------
  162. // Decompress normal+tangent together
  163. void _DecompressShort2NormalTangent( float2 inputNormal, float2 inputTangent, out float3 outputNormal, out float4 outputTangent )
  164. {
  165. // FIXME: if we end up sticking with the SHORT2 format, pack the normal and tangent into a single SHORT4 element
  166. // (that would make unpacking normal+tangent here together much cheaper than the sum of their parts)
  167. _DecompressShort2Normal( inputNormal, outputNormal );
  168. _DecompressShort2Tangent( inputTangent, outputTangent );
  169. }
  170. //=======================================================================================
  171. // Decompress a normal and tangent from four-component compressed format
  172. // We expect this data to come from an unsigned UBYTE4 stream in the range of 0..255
  173. // The final vTangent.w contains the sign to use in the cross product when generating a binormal
  174. void _DecompressUByte4NormalTangent( float4 inputNormal,
  175. out float3 outputNormal, // {nX, nY, nZ}
  176. out float4 outputTangent ) // {tX, tY, tZ, sign of binormal}
  177. {
  178. float fOne = 1.0f;
  179. float4 ztztSignBits = ( inputNormal - 128.0f ) < 0; // sign bits for zs and binormal (1 or 0) set-less-than (slt) asm instruction
  180. float4 xyxyAbs = abs( inputNormal - 128.0f ) - ztztSignBits; // 0..127
  181. float4 xyxySignBits = ( xyxyAbs - 64.0f ) < 0; // sign bits for xs and ys (1 or 0)
  182. float4 normTan = (abs( xyxyAbs - 64.0f ) - xyxySignBits) / 63.0f; // abs({nX, nY, tX, tY})
  183. outputNormal.xy = normTan.xy; // abs({nX, nY, __, __})
  184. outputTangent.xy = normTan.zw; // abs({tX, tY, __, __})
  185. float4 xyxySigns = 1 - 2*xyxySignBits; // Convert sign bits to signs
  186. float4 ztztSigns = 1 - 2*ztztSignBits; // ( [1,0] -> [-1,+1] )
  187. outputNormal.z = 1.0f - outputNormal.x - outputNormal.y; // Project onto x+y+z=1
  188. outputNormal.xyz = normalize( outputNormal.xyz ); // Normalize onto unit sphere
  189. outputNormal.xy *= xyxySigns.xy; // Restore x and y signs
  190. outputNormal.z *= ztztSigns.x; // Restore z sign
  191. outputTangent.z = 1.0f - outputTangent.x - outputTangent.y; // Project onto x+y+z=1
  192. outputTangent.xyz = normalize( outputTangent.xyz ); // Normalize onto unit sphere
  193. outputTangent.xy *= xyxySigns.zw; // Restore x and y signs
  194. outputTangent.z *= ztztSigns.z; // Restore z sign
  195. outputTangent.w = ztztSigns.w; // Binormal sign
  196. }
  197. //-----------------------------------------------------------------------------------
  198. // Decompress just a normal from four-component compressed format (same as above)
  199. // We expect this data to come from an unsigned UBYTE4 stream in the range of 0..255
  200. // [ When compiled, this works out to approximately 17 asm instructions ]
  201. void _DecompressUByte4Normal( float4 inputNormal,
  202. out float3 outputNormal) // {nX, nY, nZ}
  203. {
  204. float fOne = 1.0f;
  205. float2 ztSigns = ( inputNormal.xy - 128.0f ) < 0; // sign bits for zs and binormal (1 or 0) set-less-than (slt) asm instruction
  206. float2 xyAbs = abs( inputNormal.xy - 128.0f ) - ztSigns; // 0..127
  207. float2 xySigns = ( xyAbs - 64.0f ) < 0; // sign bits for xs and ys (1 or 0)
  208. outputNormal.xy = ( abs( xyAbs - 64.0f ) - xySigns ) / 63.0f; // abs({nX, nY})
  209. outputNormal.z = 1.0f - outputNormal.x - outputNormal.y; // Project onto x+y+z=1
  210. outputNormal.xyz = normalize( outputNormal.xyz ); // Normalize onto unit sphere
  211. outputNormal.xy *= lerp( fOne.xx, -fOne.xx, xySigns ); // Restore x and y signs
  212. outputNormal.z *= lerp( fOne.x, -fOne.x, ztSigns.x ); // Restore z sign
  213. }
  214. void DecompressVertex_Normal( float4 inputNormal, out float3 outputNormal )
  215. {
  216. if ( COMPRESSED_VERTS == 1 )
  217. {
  218. if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
  219. {
  220. _DecompressShort2Normal( inputNormal.xy, outputNormal );
  221. }
  222. else // ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
  223. {
  224. _DecompressUByte4Normal( inputNormal, outputNormal );
  225. }
  226. }
  227. else
  228. {
  229. outputNormal = inputNormal.xyz;
  230. }
  231. }
  232. void DecompressVertex_NormalTangent( float4 inputNormal, float4 inputTangent, out float3 outputNormal, out float4 outputTangent )
  233. {
  234. if ( COMPRESSED_VERTS == 1 )
  235. {
  236. if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
  237. {
  238. _DecompressShort2NormalTangent( inputNormal.xy, inputTangent.xy, outputNormal, outputTangent );
  239. }
  240. else // ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
  241. {
  242. _DecompressUByte4NormalTangent( inputNormal, outputNormal, outputTangent );
  243. }
  244. }
  245. else
  246. {
  247. outputNormal = inputNormal.xyz;
  248. outputTangent = inputTangent;
  249. }
  250. }
  251. #ifdef SHADER_MODEL_VS_3_0
  252. //-----------------------------------------------------------------------------
  253. // Methods to sample morph data from a vertex texture
  254. // NOTE: vMorphTargetTextureDim.x = width, cVertexTextureDim.y = height, cVertexTextureDim.z = # of float4 fields per vertex
  255. // For position + normal morph for example, there will be 2 fields.
  256. //-----------------------------------------------------------------------------
  257. float4 SampleMorphDelta( sampler2D vt, const float3 vMorphTargetTextureDim, const float4 vMorphSubrect, const float flVertexID, const float flField )
  258. {
  259. float flColumn = floor( flVertexID / vMorphSubrect.w );
  260. float4 t;
  261. t.x = vMorphSubrect.x + vMorphTargetTextureDim.z * flColumn + flField + 0.5f;
  262. t.y = vMorphSubrect.y + flVertexID - flColumn * vMorphSubrect.w + 0.5f;
  263. t.xy /= vMorphTargetTextureDim.xy;
  264. t.z = t.w = 0.f;
  265. return tex2Dlod( vt, t );
  266. }
  267. // Optimized version which reads 2 deltas
  268. void SampleMorphDelta2( sampler2D vt, const float3 vMorphTargetTextureDim, const float4 vMorphSubrect, const float flVertexID, out float4 delta1, out float4 delta2 )
  269. {
  270. float flColumn = floor( flVertexID / vMorphSubrect.w );
  271. float4 t;
  272. t.x = vMorphSubrect.x + vMorphTargetTextureDim.z * flColumn + 0.5f;
  273. t.y = vMorphSubrect.y + flVertexID - flColumn * vMorphSubrect.w + 0.5f;
  274. t.xy /= vMorphTargetTextureDim.xy;
  275. t.z = t.w = 0.f;
  276. delta1 = tex2Dlod( vt, t );
  277. t.x += 1.0f / vMorphTargetTextureDim.x;
  278. delta2 = tex2Dlod( vt, t );
  279. }
  280. #endif // SHADER_MODEL_VS_3_0
  281. #if ( defined( SHADER_MODEL_VS_2_0 ) || defined( SHADER_MODEL_VS_3_0 ) )
  282. //-----------------------------------------------------------------------------
  283. // Method to apply morphs
  284. //-----------------------------------------------------------------------------
  285. bool ApplyMorph( float3 vPosFlex, inout float3 vPosition )
  286. {
  287. // Flexes coming in from a separate stream
  288. float3 vPosDelta = vPosFlex.xyz * cFlexScale.x;
  289. vPosition.xyz += vPosDelta;
  290. return true;
  291. }
  292. bool ApplyMorph( float3 vPosFlex, float3 vNormalFlex, inout float3 vPosition, inout float3 vNormal )
  293. {
  294. // Flexes coming in from a separate stream
  295. float3 vPosDelta = vPosFlex.xyz * cFlexScale.x;
  296. float3 vNormalDelta = vNormalFlex.xyz * cFlexScale.x;
  297. vPosition.xyz += vPosDelta;
  298. vNormal += vNormalDelta;
  299. return true;
  300. }
  301. bool ApplyMorph( float3 vPosFlex, float3 vNormalFlex,
  302. inout float3 vPosition, inout float3 vNormal, inout float3 vTangent )
  303. {
  304. // Flexes coming in from a separate stream
  305. float3 vPosDelta = vPosFlex.xyz * cFlexScale.x;
  306. float3 vNormalDelta = vNormalFlex.xyz * cFlexScale.x;
  307. vPosition.xyz += vPosDelta;
  308. vNormal += vNormalDelta;
  309. vTangent.xyz += vNormalDelta;
  310. return true;
  311. }
  312. bool ApplyMorph( float4 vPosFlex, float3 vNormalFlex,
  313. inout float3 vPosition, inout float3 vNormal, inout float3 vTangent, out float flWrinkle )
  314. {
  315. // Flexes coming in from a separate stream
  316. float3 vPosDelta = vPosFlex.xyz * cFlexScale.x;
  317. float3 vNormalDelta = vNormalFlex.xyz * cFlexScale.x;
  318. flWrinkle = vPosFlex.w * cFlexScale.y;
  319. vPosition.xyz += vPosDelta;
  320. vNormal += vNormalDelta;
  321. vTangent.xyz += vNormalDelta;
  322. return true;
  323. }
  324. #endif // defined( SHADER_MODEL_VS_2_0 ) || defined( SHADER_MODEL_VS_3_0 )
  325. #ifdef SHADER_MODEL_VS_3_0
  326. bool ApplyMorph( sampler2D morphSampler, const float3 vMorphTargetTextureDim, const float4 vMorphSubrect,
  327. const float flVertexID, const float3 vMorphTexCoord,
  328. inout float3 vPosition )
  329. {
  330. #if MORPHING
  331. #if !DECAL
  332. // Flexes coming in from a separate stream
  333. float4 vPosDelta = SampleMorphDelta( morphSampler, vMorphTargetTextureDim, vMorphSubrect, flVertexID, 0 );
  334. vPosition += vPosDelta.xyz;
  335. #else
  336. float4 t = float4( vMorphTexCoord.x, vMorphTexCoord.y, 0.0f, 0.0f );
  337. float3 vPosDelta = tex2Dlod( morphSampler, t );
  338. vPosition += vPosDelta.xyz * vMorphTexCoord.z;
  339. #endif // DECAL
  340. return true;
  341. #else // !MORPHING
  342. return false;
  343. #endif
  344. }
  345. bool ApplyMorph( sampler2D morphSampler, const float3 vMorphTargetTextureDim, const float4 vMorphSubrect,
  346. const float flVertexID, const float3 vMorphTexCoord,
  347. inout float3 vPosition, inout float3 vNormal )
  348. {
  349. #if MORPHING
  350. #if !DECAL
  351. float4 vPosDelta, vNormalDelta;
  352. SampleMorphDelta2( morphSampler, vMorphTargetTextureDim, vMorphSubrect, flVertexID, vPosDelta, vNormalDelta );
  353. vPosition += vPosDelta.xyz;
  354. vNormal += vNormalDelta.xyz;
  355. #else
  356. float4 t = float4( vMorphTexCoord.x, vMorphTexCoord.y, 0.0f, 0.0f );
  357. float3 vPosDelta = tex2Dlod( morphSampler, t );
  358. t.x += 1.0f / vMorphTargetTextureDim.x;
  359. float3 vNormalDelta = tex2Dlod( morphSampler, t );
  360. vPosition += vPosDelta.xyz * vMorphTexCoord.z;
  361. vNormal += vNormalDelta.xyz * vMorphTexCoord.z;
  362. #endif // DECAL
  363. return true;
  364. #else // !MORPHING
  365. return false;
  366. #endif
  367. }
  368. bool ApplyMorph( sampler2D morphSampler, const float3 vMorphTargetTextureDim, const float4 vMorphSubrect,
  369. const float flVertexID, const float3 vMorphTexCoord,
  370. inout float3 vPosition, inout float3 vNormal, inout float3 vTangent )
  371. {
  372. #if MORPHING
  373. #if !DECAL
  374. float4 vPosDelta, vNormalDelta;
  375. SampleMorphDelta2( morphSampler, vMorphTargetTextureDim, vMorphSubrect, flVertexID, vPosDelta, vNormalDelta );
  376. vPosition += vPosDelta.xyz;
  377. vNormal += vNormalDelta.xyz;
  378. vTangent += vNormalDelta.xyz;
  379. #else
  380. float4 t = float4( vMorphTexCoord.x, vMorphTexCoord.y, 0.0f, 0.0f );
  381. float3 vPosDelta = tex2Dlod( morphSampler, t );
  382. t.x += 1.0f / vMorphTargetTextureDim.x;
  383. float3 vNormalDelta = tex2Dlod( morphSampler, t );
  384. vPosition += vPosDelta.xyz * vMorphTexCoord.z;
  385. vNormal += vNormalDelta.xyz * vMorphTexCoord.z;
  386. vTangent += vNormalDelta.xyz * vMorphTexCoord.z;
  387. #endif // DECAL
  388. return true;
  389. #else // MORPHING
  390. return false;
  391. #endif
  392. }
  393. bool ApplyMorph( sampler2D morphSampler, const float3 vMorphTargetTextureDim, const float4 vMorphSubrect,
  394. const float flVertexID, const float3 vMorphTexCoord,
  395. inout float3 vPosition, inout float3 vNormal, inout float3 vTangent, out float flWrinkle )
  396. {
  397. #if MORPHING
  398. #if !DECAL
  399. float4 vPosDelta, vNormalDelta;
  400. SampleMorphDelta2( morphSampler, vMorphTargetTextureDim, vMorphSubrect, flVertexID, vPosDelta, vNormalDelta );
  401. vPosition += vPosDelta.xyz;
  402. vNormal += vNormalDelta.xyz;
  403. vTangent += vNormalDelta.xyz;
  404. flWrinkle = vPosDelta.w;
  405. #else
  406. float4 t = float4( vMorphTexCoord.x, vMorphTexCoord.y, 0.0f, 0.0f );
  407. float4 vPosDelta = tex2Dlod( morphSampler, t );
  408. t.x += 1.0f / vMorphTargetTextureDim.x;
  409. float3 vNormalDelta = tex2Dlod( morphSampler, t );
  410. vPosition += vPosDelta.xyz * vMorphTexCoord.z;
  411. vNormal += vNormalDelta.xyz * vMorphTexCoord.z;
  412. vTangent += vNormalDelta.xyz * vMorphTexCoord.z;
  413. flWrinkle = vPosDelta.w * vMorphTexCoord.z;
  414. #endif // DECAL
  415. return true;
  416. #else // MORPHING
  417. flWrinkle = 0.0f;
  418. return false;
  419. #endif
  420. }
  421. #endif // SHADER_MODEL_VS_3_0
  422. float RangeFog( const float3 projPos )
  423. {
  424. return max( cFogMaxDensity, ( -projPos.z * cOOFogRange + cFogEndOverFogRange ) );
  425. }
  426. float WaterFog( const float3 worldPos, const float3 projPos )
  427. {
  428. float4 tmp;
  429. tmp.xy = cEyePosWaterZ.wz - worldPos.z;
  430. // tmp.x is the distance from the water surface to the vert
  431. // tmp.y is the distance from the eye position to the vert
  432. // if $tmp.x < 0, then set it to 0
  433. // This is the equivalent of moving the vert to the water surface if it's above the water surface
  434. tmp.x = max( 0.0f, tmp.x );
  435. // $tmp.w = $tmp.x / $tmp.y
  436. tmp.w = tmp.x / tmp.y;
  437. tmp.w *= projPos.z;
  438. // $tmp.w is now the distance that we see through water.
  439. return max( cFogMaxDensity, ( -tmp.w * cOOFogRange + cFogOne ) );
  440. }
  441. float CalcFog( const float3 worldPos, const float3 projPos, const int fogType )
  442. {
  443. #if defined( _X360 )
  444. // 360 only does pixel fog
  445. return 1.0f;
  446. #endif
  447. if( fogType == FOGTYPE_RANGE )
  448. {
  449. return RangeFog( projPos );
  450. }
  451. else
  452. {
  453. #if SHADERMODEL_VS_2_0 == 1
  454. // We do this work in the pixel shader in dx9, so don't do any fog here.
  455. return 1.0f;
  456. #else
  457. return WaterFog( worldPos, projPos );
  458. #endif
  459. }
  460. }
  461. float CalcFog( const float3 worldPos, const float3 projPos, const bool bWaterFog )
  462. {
  463. #if defined( _X360 )
  464. // 360 only does pixel fog
  465. return 1.0f;
  466. #endif
  467. float flFog;
  468. if( !bWaterFog )
  469. {
  470. flFog = RangeFog( projPos );
  471. }
  472. else
  473. {
  474. #if SHADERMODEL_VS_2_0 == 1
  475. // We do this work in the pixel shader in dx9, so don't do any fog here.
  476. flFog = 1.0f;
  477. #else
  478. flFog = WaterFog( worldPos, projPos );
  479. #endif
  480. }
  481. return flFog;
  482. }
  483. float4 DecompressBoneWeights( const float4 weights )
  484. {
  485. float4 result = weights;
  486. if ( COMPRESSED_VERTS )
  487. {
  488. // Decompress from SHORT2 to float. In our case, [-1, +32767] -> [0, +1]
  489. // NOTE: we add 1 here so we can divide by 32768 - which is exact (divide by 32767 is not).
  490. // This avoids cracking between meshes with different numbers of bone weights.
  491. // We use SHORT2 instead of SHORT2N for a similar reason - the GPU's conversion
  492. // from [-32768,+32767] to [-1,+1] is imprecise in the same way.
  493. result += 1;
  494. result /= 32768;
  495. }
  496. return result;
  497. }
  498. void SkinPosition( bool bSkinning, const float4 modelPos,
  499. const float4 boneWeights, float4 fBoneIndices,
  500. out float3 worldPos )
  501. {
  502. #if !defined( _X360 )
  503. int3 boneIndices = D3DCOLORtoUBYTE4( fBoneIndices );
  504. #else
  505. int3 boneIndices = fBoneIndices;
  506. #endif
  507. // Needed for invariance issues caused by multipass rendering
  508. #if defined( _X360 )
  509. [isolate]
  510. #endif
  511. {
  512. if ( !bSkinning )
  513. {
  514. worldPos = mul4x3( modelPos, cModel[0] );
  515. }
  516. else // skinning - always three bones
  517. {
  518. float4x3 mat1 = cModel[boneIndices[0]];
  519. float4x3 mat2 = cModel[boneIndices[1]];
  520. float4x3 mat3 = cModel[boneIndices[2]];
  521. float3 weights = DecompressBoneWeights( boneWeights ).xyz;
  522. weights[2] = 1 - (weights[0] + weights[1]);
  523. float4x3 blendMatrix = mat1 * weights[0] + mat2 * weights[1] + mat3 * weights[2];
  524. worldPos = mul4x3( modelPos, blendMatrix );
  525. }
  526. }
  527. }
  528. void SkinPositionAndNormal( bool bSkinning, const float4 modelPos, const float3 modelNormal,
  529. const float4 boneWeights, float4 fBoneIndices,
  530. out float3 worldPos, out float3 worldNormal )
  531. {
  532. // Needed for invariance issues caused by multipass rendering
  533. #if defined( _X360 )
  534. [isolate]
  535. #endif
  536. {
  537. #if !defined( _X360 )
  538. int3 boneIndices = D3DCOLORtoUBYTE4( fBoneIndices );
  539. #else
  540. int3 boneIndices = fBoneIndices;
  541. #endif
  542. if ( !bSkinning )
  543. {
  544. worldPos = mul4x3( modelPos, cModel[0] );
  545. worldNormal = mul3x3( modelNormal, ( const float3x3 )cModel[0] );
  546. }
  547. else // skinning - always three bones
  548. {
  549. float4x3 mat1 = cModel[boneIndices[0]];
  550. float4x3 mat2 = cModel[boneIndices[1]];
  551. float4x3 mat3 = cModel[boneIndices[2]];
  552. float3 weights = DecompressBoneWeights( boneWeights ).xyz;
  553. weights[2] = 1 - (weights[0] + weights[1]);
  554. float4x3 blendMatrix = mat1 * weights[0] + mat2 * weights[1] + mat3 * weights[2];
  555. worldPos = mul4x3( modelPos, blendMatrix );
  556. worldNormal = mul3x3( modelNormal, ( float3x3 )blendMatrix );
  557. }
  558. } // end [isolate]
  559. }
  560. // Is it worth keeping SkinPosition and SkinPositionAndNormal around since the optimizer
  561. // gets rid of anything that isn't used?
  562. void SkinPositionNormalAndTangentSpace(
  563. bool bSkinning,
  564. const float4 modelPos, const float3 modelNormal,
  565. const float4 modelTangentS,
  566. const float4 boneWeights, float4 fBoneIndices,
  567. out float3 worldPos, out float3 worldNormal,
  568. out float3 worldTangentS, out float3 worldTangentT )
  569. {
  570. #if !defined( _X360 )
  571. int3 boneIndices = D3DCOLORtoUBYTE4( fBoneIndices );
  572. #else
  573. int3 boneIndices = fBoneIndices;
  574. #endif
  575. // Needed for invariance issues caused by multipass rendering
  576. #if defined( _X360 )
  577. [isolate]
  578. #endif
  579. {
  580. if ( !bSkinning )
  581. {
  582. worldPos = mul4x3( modelPos, cModel[0] );
  583. worldNormal = mul3x3( modelNormal, ( const float3x3 )cModel[0] );
  584. worldTangentS = mul3x3( ( float3 )modelTangentS, ( const float3x3 )cModel[0] );
  585. }
  586. else // skinning - always three bones
  587. {
  588. float4x3 mat1 = cModel[boneIndices[0]];
  589. float4x3 mat2 = cModel[boneIndices[1]];
  590. float4x3 mat3 = cModel[boneIndices[2]];
  591. float3 weights = DecompressBoneWeights( boneWeights ).xyz;
  592. weights[2] = 1 - (weights[0] + weights[1]);
  593. float4x3 blendMatrix = mat1 * weights[0] + mat2 * weights[1] + mat3 * weights[2];
  594. worldPos = mul4x3( modelPos, blendMatrix );
  595. worldNormal = mul3x3( modelNormal, ( const float3x3 )blendMatrix );
  596. worldTangentS = mul3x3( ( float3 )modelTangentS, ( const float3x3 )blendMatrix );
  597. }
  598. worldTangentT = cross( worldNormal, worldTangentS ) * modelTangentS.w;
  599. }
  600. }
  601. //-----------------------------------------------------------------------------
  602. // Lighting helper functions
  603. //-----------------------------------------------------------------------------
  604. float3 AmbientLight( const float3 worldNormal )
  605. {
  606. float3 nSquared = worldNormal * worldNormal;
  607. int3 isNegative = ( worldNormal < 0.0 );
  608. float3 linearColor;
  609. linearColor = nSquared.x * cAmbientCubeX[isNegative.x] +
  610. nSquared.y * cAmbientCubeY[isNegative.y] +
  611. nSquared.z * cAmbientCubeZ[isNegative.z];
  612. return linearColor;
  613. }
  614. // The following "internal" routines are called "privately" by other routines in this file which
  615. // handle the particular flavor of vs20 control flow appropriate to the original caller
  616. float VertexAttenInternal( const float3 worldPos, int lightNum )
  617. {
  618. float result = 0.0f;
  619. // Get light direction
  620. float3 lightDir = cLightInfo[lightNum].pos - worldPos;
  621. // Get light distance squared.
  622. float lightDistSquared = dot( lightDir, lightDir );
  623. // Get 1/lightDistance
  624. float ooLightDist = rsqrt( lightDistSquared );
  625. // Normalize light direction
  626. lightDir *= ooLightDist;
  627. float3 vDist;
  628. # if defined( _X360 )
  629. {
  630. //X360 dynamic compile hits an internal compiler error using dst(), this is the breakdown of how dst() works from the 360 docs.
  631. vDist.x = 1;
  632. vDist.y = lightDistSquared * ooLightDist;
  633. vDist.z = lightDistSquared;
  634. //flDist.w = ooLightDist;
  635. }
  636. # else
  637. {
  638. vDist = dst( lightDistSquared, ooLightDist );
  639. }
  640. # endif
  641. float flDistanceAtten = 1.0f / dot( cLightInfo[lightNum].atten.xyz, vDist );
  642. // Spot attenuation
  643. float flCosTheta = dot( cLightInfo[lightNum].dir.xyz, -lightDir );
  644. float flSpotAtten = (flCosTheta - cLightInfo[lightNum].spotParams.z) * cLightInfo[lightNum].spotParams.w;
  645. flSpotAtten = max( 0.0001f, flSpotAtten );
  646. flSpotAtten = pow( flSpotAtten, cLightInfo[lightNum].spotParams.x );
  647. flSpotAtten = saturate( flSpotAtten );
  648. // Select between point and spot
  649. float flAtten = lerp( flDistanceAtten, flDistanceAtten * flSpotAtten, cLightInfo[lightNum].dir.w );
  650. // Select between above and directional (no attenuation)
  651. result = lerp( flAtten, 1.0f, cLightInfo[lightNum].color.w );
  652. return result;
  653. }
  654. float CosineTermInternal( const float3 worldPos, const float3 worldNormal, int lightNum, bool bHalfLambert )
  655. {
  656. // Calculate light direction assuming this is a point or spot
  657. float3 lightDir = normalize( cLightInfo[lightNum].pos - worldPos );
  658. // Select the above direction or the one in the structure, based upon light type
  659. lightDir = lerp( lightDir, -cLightInfo[lightNum].dir, cLightInfo[lightNum].color.w );
  660. // compute N dot L
  661. float NDotL = dot( worldNormal, lightDir );
  662. if ( !bHalfLambert )
  663. {
  664. NDotL = max( 0.0f, NDotL );
  665. }
  666. else // Half-Lambert
  667. {
  668. NDotL = NDotL * 0.5 + 0.5;
  669. NDotL = NDotL * NDotL;
  670. }
  671. return NDotL;
  672. }
  673. // This routine uses booleans to do early-outs and is meant to be called by routines OUTSIDE of this file
  674. float GetVertexAttenForLight( const float3 worldPos, int lightNum, bool bUseStaticControlFlow )
  675. {
  676. float result = 0.0f;
  677. // Direct3D uses static control flow but OpenGL currently does not
  678. if ( bUseStaticControlFlow )
  679. {
  680. if ( g_bLightEnabled[lightNum] )
  681. {
  682. result = VertexAttenInternal( worldPos, lightNum );
  683. }
  684. }
  685. else // OpenGL non-static-control-flow path
  686. {
  687. result = VertexAttenInternal( worldPos, lightNum );
  688. }
  689. return result;
  690. }
  691. float3 DoLightInternal( const float3 worldPos, const float3 worldNormal, int lightNum, bool bHalfLambert )
  692. {
  693. return cLightInfo[lightNum].color *
  694. CosineTermInternal( worldPos, worldNormal, lightNum, bHalfLambert ) *
  695. VertexAttenInternal( worldPos, lightNum );
  696. }
  697. float3 DoLighting( const float3 worldPos, const float3 worldNormal,
  698. const float3 staticLightingColor, const bool bStaticLight,
  699. const bool bDynamicLight, bool bHalfLambert )
  700. {
  701. float3 linearColor = float3( 0.0f, 0.0f, 0.0f );
  702. if( bStaticLight ) // Static light
  703. {
  704. float3 col = staticLightingColor * cOverbright;
  705. #if defined ( _X360 )
  706. linearColor += col * col;
  707. #else
  708. linearColor += GammaToLinear( col );
  709. #endif
  710. }
  711. if( bDynamicLight ) // Dynamic light
  712. {
  713. for (int i = 0; i < g_nLightCount; i++)
  714. {
  715. linearColor += DoLightInternal( worldPos, worldNormal, i, bHalfLambert );
  716. }
  717. }
  718. if( bDynamicLight )
  719. {
  720. linearColor += AmbientLight( worldNormal ); //ambient light is already remapped
  721. }
  722. return linearColor;
  723. }
  724. float3 DoLightingUnrolled( const float3 worldPos, const float3 worldNormal,
  725. const float3 staticLightingColor, const bool bStaticLight,
  726. const bool bDynamicLight, bool bHalfLambert, const int nNumLights )
  727. {
  728. float3 linearColor = float3( 0.0f, 0.0f, 0.0f );
  729. if( bStaticLight ) // Static light
  730. {
  731. linearColor += GammaToLinear( staticLightingColor * cOverbright );
  732. }
  733. if( bDynamicLight ) // Ambient light
  734. {
  735. if ( nNumLights >= 1 )
  736. linearColor += DoLightInternal( worldPos, worldNormal, 0, bHalfLambert );
  737. if ( nNumLights >= 2 )
  738. linearColor += DoLightInternal( worldPos, worldNormal, 1, bHalfLambert );
  739. if ( nNumLights >= 3 )
  740. linearColor += DoLightInternal( worldPos, worldNormal, 2, bHalfLambert );
  741. if ( nNumLights >= 4 )
  742. linearColor += DoLightInternal( worldPos, worldNormal, 3, bHalfLambert );
  743. }
  744. if( bDynamicLight )
  745. {
  746. linearColor += AmbientLight( worldNormal ); //ambient light is already remapped
  747. }
  748. return linearColor;
  749. }
  750. int4 FloatToInt( in float4 floats )
  751. {
  752. return D3DCOLORtoUBYTE4( floats.zyxw / 255.001953125 );
  753. }
  754. float2 ComputeSphereMapTexCoords( in float3 reflectionVector )
  755. {
  756. // transform reflection vector into view space
  757. reflectionVector = mul( reflectionVector, ( float3x3 )cViewModel );
  758. // generate <rx ry rz+1>
  759. float3 tmp = float3( reflectionVector.x, reflectionVector.y, reflectionVector.z + 1.0f );
  760. // find 1 / len
  761. float ooLen = dot( tmp, tmp );
  762. ooLen = 1.0f / sqrt( ooLen );
  763. // tmp = tmp/|tmp| + 1
  764. tmp.xy = ooLen * tmp.xy + 1.0f;
  765. return tmp.xy * 0.5f;
  766. }
  767. #define DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE 1
  768. // minxyz.minsoftness / maxxyz.maxsoftness
  769. float3 ApplyDeformation( float3 worldpos, int deftype, float4 defparms0, float4 defparms1,
  770. float4 defparms2, float4 defparms3 )
  771. {
  772. float3 ret = worldpos;
  773. if ( deftype == DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE )
  774. {
  775. ret=max( ret, defparms2.xyz );
  776. ret=min( ret, defparms3.xyz );
  777. }
  778. return ret;
  779. }
  780. #endif //#ifndef COMMON_VS_FXC_H_