Lighting.hlsl 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #pragma warning(disable:3571)
  2. #ifdef COMPILEVS
  3. float3 GetAmbient(float zonePos)
  4. {
  5. return cAmbientStartColor + zonePos * cAmbientEndColor;
  6. }
  7. #ifdef NUMVERTEXLIGHTS
  8. float GetVertexLight(int index, float3 worldPos, float3 normal)
  9. {
  10. float3 lightDir = cVertexLights[index * 3 + 1].xyz;
  11. float3 lightPos = cVertexLights[index * 3 + 2].xyz;
  12. float invRange = cVertexLights[index * 3].w;
  13. float cutoff = cVertexLights[index * 3 + 1].w;
  14. float invCutoff = cVertexLights[index * 3 + 2].w;
  15. // Directional light
  16. if (invRange == 0.0)
  17. {
  18. float NdotL = max(dot(normal, lightDir), 0.0);
  19. return NdotL;
  20. }
  21. // Point/spot light
  22. else
  23. {
  24. float3 lightVec = (lightPos - worldPos) * invRange;
  25. float lightDist = length(lightVec);
  26. float3 localDir = lightVec / lightDist;
  27. float NdotL = max(dot(normal, localDir), 0.0);
  28. float atten = saturate(1.0 - lightDist * lightDist);
  29. float spotEffect = dot(localDir, lightDir);
  30. float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
  31. return NdotL * atten * spotAtten;
  32. }
  33. }
  34. float GetVertexLightVolumetric(int index, float3 worldPos)
  35. {
  36. float3 lightDir = cVertexLights[index * 3 + 1].xyz;
  37. float3 lightPos = cVertexLights[index * 3 + 2].xyz;
  38. float invRange = cVertexLights[index * 3].w;
  39. float cutoff = cVertexLights[index * 3 + 1].w;
  40. float invCutoff = cVertexLights[index * 3 + 2].w;
  41. // Directional light
  42. if (invRange == 0.0)
  43. {
  44. return 1.0;
  45. }
  46. // Point/spot light
  47. else
  48. {
  49. float3 lightVec = (lightPos - worldPos) * invRange;
  50. float lightDist = length(lightVec);
  51. float3 localDir = lightVec / lightDist;
  52. float atten = saturate(1.0 - lightDist * lightDist);
  53. float spotEffect = dot(localDir, lightDir);
  54. float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
  55. return atten * spotAtten;
  56. }
  57. }
  58. #endif
  59. #ifdef SHADOW
  60. #ifdef DIRLIGHT
  61. #define NUMCASCADES 4
  62. #else
  63. #define NUMCASCADES 1
  64. #endif
  65. void GetShadowPos(float4 projWorldPos, out float4 shadowPos[NUMCASCADES])
  66. {
  67. // Shadow projection: transform from world space to shadow space
  68. #if defined(DIRLIGHT)
  69. shadowPos[0] = mul(projWorldPos, cLightMatrices[0]);
  70. shadowPos[1] = mul(projWorldPos, cLightMatrices[1]);
  71. shadowPos[2] = mul(projWorldPos, cLightMatrices[2]);
  72. shadowPos[3] = mul(projWorldPos, cLightMatrices[3]);
  73. #elif defined(SPOTLIGHT)
  74. shadowPos[0] = mul(projWorldPos, cLightMatrices[1]);
  75. #else
  76. shadowPos[0] = float4(projWorldPos.xyz - cLightPos.xyz, 0.0);
  77. #endif
  78. }
  79. #endif
  80. #endif
  81. #ifdef COMPILEPS
  82. float GetDiffuse(float3 normal, float3 lightVec, out float3 lightDir)
  83. {
  84. #ifdef DIRLIGHT
  85. #ifdef NORMALMAP
  86. // In normal mapped forward lighting, the tangent space light vector needs renormalization
  87. lightDir = normalize(lightVec);
  88. #else
  89. lightDir = lightVec;
  90. #endif
  91. return saturate(dot(normal, lightDir));
  92. #else
  93. float lightDist = length(lightVec);
  94. lightDir = lightVec / lightDist;
  95. return saturate(dot(normal, lightDir)) * tex1D(sLightRampMap, lightDist).r;
  96. #endif
  97. }
  98. float GetDiffuseVolumetric(float3 lightVec)
  99. {
  100. #ifdef DIRLIGHT
  101. return 1.0;
  102. #else
  103. float lightDist = length(lightVec);
  104. return tex1D(sLightRampMap, lightDist).r;
  105. #endif
  106. }
  107. float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularPower)
  108. {
  109. float3 halfVec = normalize(normalize(eyeVec) + lightDir);
  110. return pow(dot(normal, halfVec), specularPower);
  111. }
  112. float GetIntensity(float3 color)
  113. {
  114. return dot(color, float3(0.333, 0.333, 0.333));
  115. }
  116. #ifdef SHADOW
  117. #ifdef DIRLIGHT
  118. #define NUMCASCADES 4
  119. #else
  120. #define NUMCASCADES 1
  121. #endif
  122. float GetShadow(float4 shadowPos)
  123. {
  124. #ifndef LQSHADOW
  125. // Take four samples and average them
  126. // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
  127. #ifndef POINTLIGHT
  128. float2 offsets = cShadowMapInvSize * shadowPos.w;
  129. #else
  130. float2 offsets = cShadowMapInvSize;
  131. #endif
  132. float4 inLight = float4(
  133. tex2Dproj(sShadowMap, shadowPos).r,
  134. tex2Dproj(sShadowMap, float4(shadowPos.x + offsets.x, shadowPos.yzw)).r,
  135. tex2Dproj(sShadowMap, float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r,
  136. tex2Dproj(sShadowMap, float4(shadowPos.xy + offsets.xy, shadowPos.zw)).r
  137. );
  138. #ifndef SHADOWCMP
  139. return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
  140. #else
  141. #ifndef POINTLIGHT
  142. return cShadowIntensity.y + dot(inLight * shadowPos.w > shadowPos.z, cShadowIntensity.x);
  143. #else
  144. return cShadowIntensity.y + dot(inLight > shadowPos.z, cShadowIntensity.x);
  145. #endif
  146. #endif
  147. #else
  148. // Take one sample
  149. float inLight = tex2Dproj(sShadowMap, shadowPos).r;
  150. #ifndef SHADOWCMP
  151. return cShadowIntensity.y + cShadowIntensity.x * inLight;
  152. #else
  153. #ifndef POINTLIGHT
  154. return cShadowIntensity.y + cShadowIntensity.x * (inLight * shadowPos.w > shadowPos.z);
  155. #else
  156. return cShadowIntensity.y + cShadowIntensity.x * (inLight > shadowPos.z);
  157. #endif
  158. #endif
  159. #endif
  160. }
  161. #ifdef POINTLIGHT
  162. float GetPointShadow(float3 lightVec)
  163. {
  164. float3 axis = texCUBE(sFaceSelectCubeMap, lightVec).rgb;
  165. float depth = abs(dot(lightVec, axis));
  166. // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
  167. // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
  168. // case filtering across faces is wrong
  169. const float factor = 1.0 / 256.0;
  170. lightVec += factor * axis * lightVec;
  171. // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
  172. float4 indirectPos = texCUBE(sIndirectionCubeMap, lightVec);
  173. indirectPos.xy *= cShadowCubeAdjust.xy;
  174. indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
  175. float4 shadowPos = float4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
  176. return GetShadow(shadowPos);
  177. }
  178. #endif
  179. #ifdef DIRLIGHT
  180. float GetDirShadowFade(float inLight, float depth)
  181. {
  182. return saturate(inLight + saturate((depth - cShadowDepthFade.z) * cShadowDepthFade.w));
  183. }
  184. float GetDirShadow(const float4 iShadowPos[NUMCASCADES], float depth)
  185. {
  186. float4 shadowPos;
  187. if (depth < cShadowSplits.x)
  188. shadowPos = iShadowPos[0];
  189. else if (depth < cShadowSplits.y)
  190. shadowPos = iShadowPos[1];
  191. else if (depth < cShadowSplits.z)
  192. shadowPos = iShadowPos[2];
  193. else
  194. shadowPos = iShadowPos[3];
  195. return GetDirShadowFade(GetShadow(shadowPos), depth);
  196. }
  197. float GetDirShadowDeferred(float4 projWorldPos, float depth)
  198. {
  199. float4 shadowPos;
  200. #ifdef SM3
  201. if (depth < cShadowSplits.x)
  202. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  203. else if (depth < cShadowSplits.y)
  204. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  205. else if (depth < cShadowSplits.z)
  206. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  207. else
  208. shadowPos = mul(projWorldPos, cLightMatricesPS[3]);
  209. #else
  210. if (depth < cShadowSplits.x)
  211. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  212. else if (depth < cShadowSplits.y)
  213. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  214. else if (depth < cShadowSplits.z)
  215. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  216. #endif
  217. return GetDirShadowFade(GetShadow(shadowPos), depth);
  218. }
  219. #endif
  220. float GetShadow(float4 iShadowPos[NUMCASCADES], float depth)
  221. {
  222. #if defined(DIRLIGHT)
  223. return GetDirShadow(iShadowPos, depth);
  224. #elif defined(SPOTLIGHT)
  225. return GetShadow(iShadowPos[0]);
  226. #else
  227. return GetPointShadow(iShadowPos[0].xyz);
  228. #endif
  229. }
  230. float GetShadowDeferred(float4 projWorldPos, float depth)
  231. {
  232. #if defined(DIRLIGHT)
  233. return GetDirShadowDeferred(projWorldPos, depth);
  234. #elif defined(SPOTLIGHT)
  235. float4 shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  236. return GetShadow(shadowPos);
  237. #else
  238. float3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
  239. return GetPointShadow(shadowPos);
  240. #endif
  241. }
  242. #endif
  243. #endif