lighting.hlsl 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "./torque.hlsl"
  23. #ifndef TORQUE_SHADERGEN
  24. // These are the uniforms used by most lighting shaders.
  25. uniform float4 inLightPos[3];
  26. uniform float4 inLightInvRadiusSq;
  27. uniform float4 inLightColor[4];
  28. #ifndef TORQUE_BL_NOSPOTLIGHT
  29. uniform float4 inLightSpotDir[3];
  30. uniform float4 inLightSpotAngle;
  31. uniform float4 inLightSpotFalloff;
  32. #endif
  33. uniform float4 ambient;
  34. #define ambientCameraFactor 0.3
  35. uniform float specularPower;
  36. uniform float4 specularColor;
  37. #endif // !TORQUE_SHADERGEN
  38. void compute4Lights( float3 wsView,
  39. float3 wsPosition,
  40. float3 wsNormal,
  41. float4 shadowMask,
  42. #ifdef TORQUE_SHADERGEN
  43. float4 inLightPos[3],
  44. float4 inLightInvRadiusSq,
  45. float4 inLightColor[4],
  46. float4 inLightSpotDir[3],
  47. float4 inLightSpotAngle,
  48. float4 inLightSpotFalloff,
  49. float specularPower,
  50. float4 specularColor,
  51. #endif // TORQUE_SHADERGEN
  52. out float4 outDiffuse,
  53. out float4 outSpecular )
  54. {
  55. // NOTE: The light positions and spotlight directions
  56. // are stored in SoA order, so inLightPos[0] is the
  57. // x coord for all 4 lights... inLightPos[1] is y... etc.
  58. //
  59. // This is the key to fully utilizing the vector units and
  60. // saving a huge amount of instructions.
  61. //
  62. // For example this change saved more than 10 instructions
  63. // over a simple for loop for each light.
  64. int i;
  65. float4 lightVectors[3];
  66. for ( i = 0; i < 3; i++ )
  67. lightVectors[i] = wsPosition[i] - inLightPos[i];
  68. float4 squareDists = 0;
  69. for ( i = 0; i < 3; i++ )
  70. squareDists += lightVectors[i] * lightVectors[i];
  71. // Accumulate the dot product between the light
  72. // vector and the normal.
  73. //
  74. // The normal is negated because it faces away from
  75. // the surface and the light faces towards the
  76. // surface... this keeps us from needing to flip
  77. // the light vector direction which complicates
  78. // the spot light calculations.
  79. //
  80. // We normalize the result a little later.
  81. //
  82. float4 nDotL = 0;
  83. for ( i = 0; i < 3; i++ )
  84. nDotL += lightVectors[i] * -wsNormal[i];
  85. float4 rDotL = 0;
  86. #ifndef TORQUE_BL_NOSPECULAR
  87. // We're using the Phong specular reflection model
  88. // here where traditionally Torque has used Blinn-Phong
  89. // which has proven to be more accurate to real materials.
  90. //
  91. // We do so because its cheaper as do not need to
  92. // calculate the half angle for all 4 lights.
  93. //
  94. // Advanced Lighting still uses Blinn-Phong, but the
  95. // specular reconstruction it does looks fairly similar
  96. // to this.
  97. //
  98. float3 R = reflect( wsView, -wsNormal );
  99. for ( i = 0; i < 3; i++ )
  100. rDotL += lightVectors[i] * R[i];
  101. #endif
  102. // Normalize the dots.
  103. //
  104. // Notice we're using the half type here to get a
  105. // much faster sqrt via the rsq_pp instruction at
  106. // the loss of some precision.
  107. //
  108. // Unless we have some extremely large point lights
  109. // i don't believe the precision loss will matter.
  110. //
  111. half4 correction = (half4)rsqrt( squareDists );
  112. nDotL = saturate( nDotL * correction );
  113. rDotL = clamp( rDotL * correction, 0.00001, 1.0 );
  114. // First calculate a simple point light linear
  115. // attenuation factor.
  116. //
  117. // If this is a directional light the inverse
  118. // radius should be greater than the distance
  119. // causing the attenuation to have no affect.
  120. //
  121. float4 atten = saturate( 1.0 - ( squareDists * inLightInvRadiusSq ) );
  122. #ifndef TORQUE_BL_NOSPOTLIGHT
  123. // The spotlight attenuation factor. This is really
  124. // fast for what it does... 6 instructions for 4 spots.
  125. float4 spotAtten = 0;
  126. for ( i = 0; i < 3; i++ )
  127. spotAtten += lightVectors[i] * inLightSpotDir[i];
  128. float4 cosAngle = ( spotAtten * correction ) - inLightSpotAngle;
  129. atten *= saturate( cosAngle * inLightSpotFalloff );
  130. #endif
  131. // Finally apply the shadow masking on the attenuation.
  132. atten *= shadowMask;
  133. // Get the final light intensity.
  134. float4 intensity = nDotL * atten;
  135. // Combine the light colors for output.
  136. outDiffuse = 0;
  137. for ( i = 0; i < 4; i++ )
  138. outDiffuse += intensity[i] * inLightColor[i];
  139. // Output the specular power.
  140. float4 specularIntensity = pow( rDotL, specularPower.xxxx ) * atten;
  141. // Apply the per-light specular attenuation.
  142. float4 specular = float4(0,0,0,1);
  143. for ( i = 0; i < 4; i++ )
  144. specular += float4( inLightColor[i].rgb * inLightColor[i].a * specularIntensity[i], 1 );
  145. // Add the final specular intensity values together
  146. // using a single dot product operation then get the
  147. // final specular lighting color.
  148. outSpecular = specularColor * specular;
  149. }
  150. // This value is used in AL as a constant power to raise specular values
  151. // to, before storing them into the light info buffer. The per-material
  152. // specular value is then computer by using the integer identity of
  153. // exponentiation:
  154. //
  155. // (a^m)^n = a^(m*n)
  156. //
  157. // or
  158. //
  159. // (specular^constSpecular)^(matSpecular/constSpecular) = specular^(matSpecular*constSpecular)
  160. //
  161. #define AL_ConstantSpecularPower 12.0f
  162. /// The specular calculation used in Advanced Lighting.
  163. ///
  164. /// @param toLight Normalized vector representing direction from the pixel
  165. /// being lit, to the light source, in world space.
  166. ///
  167. /// @param normal Normalized surface normal.
  168. ///
  169. /// @param toEye The normalized vector representing direction from the pixel
  170. /// being lit to the camera.
  171. ///
  172. float AL_CalcSpecular( float3 toLight, float3 normal, float3 toEye )
  173. {
  174. // (R.V)^c
  175. float specVal = dot( normalize( -reflect( toLight, normal ) ), toEye );
  176. // Return the specular factor.
  177. return pow( max( specVal, 0.00001f ), AL_ConstantSpecularPower );
  178. }
  179. /// The output for Deferred Lighting
  180. ///
  181. /// @param toLight Normalized vector representing direction from the pixel
  182. /// being lit, to the light source, in world space.
  183. ///
  184. /// @param normal Normalized surface normal.
  185. ///
  186. /// @param toEye The normalized vector representing direction from the pixel
  187. /// being lit to the camera.
  188. ///
  189. float4 AL_DeferredOutput(
  190. float3 lightColor,
  191. float3 diffuseColor,
  192. float4 matInfo,
  193. float4 ambient,
  194. float specular,
  195. float shadowAttenuation)
  196. {
  197. float3 specularColor = float3(specular, specular, specular);
  198. bool metalness = getFlag(matInfo.r, 3);
  199. if ( metalness )
  200. {
  201. specularColor = 0.04 * (1 - specular) + diffuseColor * specular;
  202. }
  203. //specular = color * map * spec^gloss
  204. float specularOut = (specularColor * matInfo.b * min(pow(abs(specular), max(( matInfo.a/ AL_ConstantSpecularPower),1.0f)),matInfo.a)).r;
  205. lightColor *= shadowAttenuation;
  206. lightColor += ambient.rgb;
  207. return float4(lightColor.rgb, specularOut);
  208. }