Lighting.hlsl 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. #ifdef SM3
  62. #define NUMCASCADES 4
  63. #else
  64. #define NUMCASCADES 3
  65. #endif
  66. #else
  67. #define NUMCASCADES 1
  68. #endif
  69. void GetShadowPos(float4 projWorldPos, out float4 shadowPos[NUMCASCADES])
  70. {
  71. // Shadow projection: transform from world space to shadow space
  72. #if defined(DIRLIGHT)
  73. shadowPos[0] = mul(projWorldPos, cLightMatrices[0]);
  74. shadowPos[1] = mul(projWorldPos, cLightMatrices[1]);
  75. shadowPos[2] = mul(projWorldPos, cLightMatrices[2]);
  76. #ifdef SM3
  77. shadowPos[3] = mul(projWorldPos, cLightMatrices[3]);
  78. #endif
  79. #elif defined(SPOTLIGHT)
  80. shadowPos[0] = mul(projWorldPos, cLightMatrices[1]);
  81. #else
  82. shadowPos[0] = float4(projWorldPos.xyz - cLightPos.xyz, 0.0);
  83. #endif
  84. }
  85. #endif
  86. #endif
  87. #ifdef COMPILEPS
  88. float GetDiffuse(float3 normal, float3 worldPos, out float3 lightDir)
  89. {
  90. #ifdef DIRLIGHT
  91. lightDir = cLightDirPS;
  92. return saturate(dot(normal, lightDir));
  93. #else
  94. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  95. float lightDist = length(lightVec);
  96. lightDir = lightVec / lightDist;
  97. return saturate(dot(normal, lightDir)) * tex1D(sLightRampMap, lightDist).r;
  98. #endif
  99. }
  100. float GetDiffuseVolumetric(float3 worldPos)
  101. {
  102. #ifdef DIRLIGHT
  103. return 1.0;
  104. #else
  105. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  106. float lightDist = length(lightVec);
  107. return tex1D(sLightRampMap, lightDist).r;
  108. #endif
  109. }
  110. float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularPower)
  111. {
  112. float3 halfVec = normalize(normalize(eyeVec) + lightDir);
  113. return pow(dot(normal, halfVec), specularPower);
  114. }
  115. float GetIntensity(float3 color)
  116. {
  117. return dot(color, float3(0.333, 0.333, 0.333));
  118. }
  119. #ifdef SHADOW
  120. #ifdef DIRLIGHT
  121. #ifdef SM3
  122. #define NUMCASCADES 4
  123. #else
  124. #define NUMCASCADES 3
  125. #endif
  126. #else
  127. #define NUMCASCADES 1
  128. #endif
  129. float GetShadow(float4 shadowPos)
  130. {
  131. #ifndef LQSHADOW
  132. // Take four samples and average them
  133. // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
  134. #ifndef POINTLIGHT
  135. float2 offsets = cShadowMapInvSize * shadowPos.w;
  136. #else
  137. float2 offsets = cShadowMapInvSize;
  138. #endif
  139. float4 inLight = float4(
  140. tex2Dproj(sShadowMap, shadowPos).r,
  141. tex2Dproj(sShadowMap, float4(shadowPos.x + offsets.x, shadowPos.yzw)).r,
  142. tex2Dproj(sShadowMap, float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r,
  143. tex2Dproj(sShadowMap, float4(shadowPos.xy + offsets.xy, shadowPos.zw)).r
  144. );
  145. #ifndef SHADOWCMP
  146. return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
  147. #else
  148. #ifndef POINTLIGHT
  149. return cShadowIntensity.y + dot(inLight * shadowPos.w > shadowPos.z, cShadowIntensity.x);
  150. #else
  151. return cShadowIntensity.y + dot(inLight > shadowPos.z, cShadowIntensity.x);
  152. #endif
  153. #endif
  154. #else
  155. // Take one sample
  156. float inLight = tex2Dproj(sShadowMap, shadowPos).r;
  157. #ifndef SHADOWCMP
  158. return cShadowIntensity.y + cShadowIntensity.x * inLight;
  159. #else
  160. #ifndef POINTLIGHT
  161. return cShadowIntensity.y + cShadowIntensity.x * (inLight * shadowPos.w > shadowPos.z);
  162. #else
  163. return cShadowIntensity.y + cShadowIntensity.x * (inLight > shadowPos.z);
  164. #endif
  165. #endif
  166. #endif
  167. }
  168. #ifdef POINTLIGHT
  169. float GetPointShadow(float3 lightVec)
  170. {
  171. float3 axis = texCUBE(sFaceSelectCubeMap, lightVec).rgb;
  172. float depth = abs(dot(lightVec, axis));
  173. // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
  174. // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
  175. // case filtering across faces is wrong
  176. const float factor = 1.0 / 256.0;
  177. lightVec += factor * axis * lightVec;
  178. // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
  179. float4 indirectPos = texCUBE(sIndirectionCubeMap, lightVec);
  180. indirectPos.xy *= cShadowCubeAdjust.xy;
  181. indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
  182. float4 shadowPos = float4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
  183. return GetShadow(shadowPos);
  184. }
  185. #endif
  186. #ifdef DIRLIGHT
  187. float GetDirShadowFade(float inLight, float depth)
  188. {
  189. return saturate(inLight + saturate((depth - cShadowDepthFade.z) * cShadowDepthFade.w));
  190. }
  191. float GetDirShadow(const float4 iShadowPos[NUMCASCADES], float depth)
  192. {
  193. float4 shadowPos;
  194. #ifdef SM3
  195. if (depth < cShadowSplits.x)
  196. shadowPos = iShadowPos[0];
  197. else if (depth < cShadowSplits.y)
  198. shadowPos = iShadowPos[1];
  199. else if (depth < cShadowSplits.z)
  200. shadowPos = iShadowPos[2];
  201. else
  202. shadowPos = iShadowPos[3];
  203. #else
  204. if (depth < cShadowSplits.x)
  205. shadowPos = iShadowPos[0];
  206. else if (depth < cShadowSplits.y)
  207. shadowPos = iShadowPos[1];
  208. else
  209. shadowPos = iShadowPos[2];
  210. #endif
  211. return GetDirShadowFade(GetShadow(shadowPos), depth);
  212. }
  213. float GetDirShadowDeferred(float4 projWorldPos, float depth)
  214. {
  215. float4 shadowPos;
  216. #ifdef SM3
  217. if (depth < cShadowSplits.x)
  218. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  219. else if (depth < cShadowSplits.y)
  220. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  221. else if (depth < cShadowSplits.z)
  222. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  223. else
  224. shadowPos = mul(projWorldPos, cLightMatricesPS[3]);
  225. #else
  226. if (depth < cShadowSplits.x)
  227. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  228. else if (depth < cShadowSplits.y)
  229. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  230. else if (depth < cShadowSplits.z)
  231. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  232. #endif
  233. return GetDirShadowFade(GetShadow(shadowPos), depth);
  234. }
  235. #endif
  236. float GetShadow(float4 iShadowPos[NUMCASCADES], float depth)
  237. {
  238. #if defined(DIRLIGHT)
  239. return GetDirShadow(iShadowPos, depth);
  240. #elif defined(SPOTLIGHT)
  241. return GetShadow(iShadowPos[0]);
  242. #else
  243. return GetPointShadow(iShadowPos[0].xyz);
  244. #endif
  245. }
  246. float GetShadowDeferred(float4 projWorldPos, float depth)
  247. {
  248. #if defined(DIRLIGHT)
  249. return GetDirShadowDeferred(projWorldPos, depth);
  250. #elif defined(SPOTLIGHT)
  251. float4 shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  252. return GetShadow(shadowPos);
  253. #else
  254. float3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
  255. return GetPointShadow(shadowPos);
  256. #endif
  257. }
  258. #endif
  259. #endif