Lighting.hlsl 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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 worldPos, out float3 lightDir)
  83. {
  84. #ifdef DIRLIGHT
  85. lightDir = cLightDirPS;
  86. return saturate(dot(normal, lightDir));
  87. #else
  88. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  89. float lightDist = length(lightVec);
  90. lightDir = lightVec / lightDist;
  91. return saturate(dot(normal, lightDir)) * Sample2D(LightRampMap, float2(lightDist, 0.0)).r;
  92. #endif
  93. }
  94. float GetDiffuseVolumetric(float3 worldPos)
  95. {
  96. #ifdef DIRLIGHT
  97. return 1.0;
  98. #else
  99. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  100. float lightDist = length(lightVec);
  101. return Sample2D(LightRampMap, float2(lightDist, 0.0)).r;
  102. #endif
  103. }
  104. float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularPower)
  105. {
  106. float3 halfVec = normalize(normalize(eyeVec) + lightDir);
  107. return saturate(pow(dot(normal, halfVec), specularPower));
  108. }
  109. float GetIntensity(float3 color)
  110. {
  111. return dot(color, float3(0.299, 0.587, 0.114));
  112. }
  113. #ifdef SHADOW
  114. #ifdef DIRLIGHT
  115. #define NUMCASCADES 4
  116. #else
  117. #define NUMCASCADES 1
  118. #endif
  119. float GetShadow(float4 shadowPos)
  120. {
  121. #ifdef D3D11
  122. shadowPos.xyz /= shadowPos.w;
  123. #endif
  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. #if !defined(POINTLIGHT) && !defined(D3D11)
  128. float2 offsets = cShadowMapInvSize * shadowPos.w;
  129. #else
  130. float2 offsets = cShadowMapInvSize;
  131. #endif
  132. float4 shadowPos2 = float4(shadowPos.x + offsets.x, shadowPos.yzw);
  133. float4 shadowPos3 = float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw);
  134. float4 shadowPos4 = float4(shadowPos.xy + offsets.xy, shadowPos.zw);
  135. float4 inLight = float4(
  136. SampleShadow(ShadowMap, shadowPos).r,
  137. SampleShadow(ShadowMap, shadowPos2).r,
  138. SampleShadow(ShadowMap, shadowPos3).r,
  139. SampleShadow(ShadowMap, shadowPos4).r
  140. );
  141. #ifndef SHADOWCMP
  142. return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
  143. #else
  144. #ifndef POINTLIGHT
  145. return cShadowIntensity.y + dot(inLight * shadowPos.w > shadowPos.z, cShadowIntensity.x);
  146. #else
  147. return cShadowIntensity.y + dot(inLight > shadowPos.z, cShadowIntensity.x);
  148. #endif
  149. #endif
  150. #else
  151. // Take one sample
  152. float inLight = SampleShadow(ShadowMap, shadowPos).r;
  153. #ifndef SHADOWCMP
  154. return cShadowIntensity.y + cShadowIntensity.x * inLight;
  155. #else
  156. #ifndef POINTLIGHT
  157. return cShadowIntensity.y + cShadowIntensity.x * (inLight * shadowPos.w > shadowPos.z);
  158. #else
  159. return cShadowIntensity.y + cShadowIntensity.x * (inLight > shadowPos.z);
  160. #endif
  161. #endif
  162. #endif
  163. }
  164. #ifdef POINTLIGHT
  165. float GetPointShadow(float3 lightVec)
  166. {
  167. float3 axis = SampleCube(FaceSelectCubeMap, lightVec).rgb;
  168. float depth = abs(dot(lightVec, axis));
  169. // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
  170. // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
  171. // case filtering across faces is wrong
  172. const float factor = 1.0 / 256.0;
  173. lightVec += factor * axis * lightVec;
  174. // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
  175. float4 indirectPos = SampleCube(IndirectionCubeMap, lightVec);
  176. indirectPos.xy *= cShadowCubeAdjust.xy;
  177. indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
  178. float4 shadowPos = float4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
  179. return GetShadow(shadowPos);
  180. }
  181. #endif
  182. #ifdef DIRLIGHT
  183. float GetDirShadowFade(float inLight, float depth)
  184. {
  185. return saturate(inLight + saturate((depth - cShadowDepthFade.z) * cShadowDepthFade.w));
  186. }
  187. float GetDirShadow(const float4 iShadowPos[NUMCASCADES], float depth)
  188. {
  189. float4 shadowPos;
  190. if (depth < cShadowSplits.x)
  191. shadowPos = iShadowPos[0];
  192. else if (depth < cShadowSplits.y)
  193. shadowPos = iShadowPos[1];
  194. else if (depth < cShadowSplits.z)
  195. shadowPos = iShadowPos[2];
  196. else
  197. shadowPos = iShadowPos[3];
  198. return GetDirShadowFade(GetShadow(shadowPos), depth);
  199. }
  200. float GetDirShadowDeferred(float4 projWorldPos, float depth)
  201. {
  202. float4 shadowPos;
  203. if (depth < cShadowSplits.x)
  204. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  205. else if (depth < cShadowSplits.y)
  206. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  207. else if (depth < cShadowSplits.z)
  208. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  209. else
  210. shadowPos = mul(projWorldPos, cLightMatricesPS[3]);
  211. return GetDirShadowFade(GetShadow(shadowPos), depth);
  212. }
  213. #endif
  214. float GetShadow(float4 iShadowPos[NUMCASCADES], float depth)
  215. {
  216. #if defined(DIRLIGHT)
  217. return GetDirShadow(iShadowPos, depth);
  218. #elif defined(SPOTLIGHT)
  219. return GetShadow(iShadowPos[0]);
  220. #else
  221. return GetPointShadow(iShadowPos[0].xyz);
  222. #endif
  223. }
  224. float GetShadowDeferred(float4 projWorldPos, float depth)
  225. {
  226. #if defined(DIRLIGHT)
  227. return GetDirShadowDeferred(projWorldPos, depth);
  228. #elif defined(SPOTLIGHT)
  229. float4 shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  230. return GetShadow(shadowPos);
  231. #else
  232. float3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
  233. return GetPointShadow(shadowPos);
  234. #endif
  235. }
  236. #endif
  237. #endif