Lighting.hlsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. #ifdef TRANSLUCENT
  19. float NdotL = abs(dot(normal, lightDir));
  20. #else
  21. float NdotL = max(dot(normal, lightDir), 0.0);
  22. #endif
  23. return NdotL;
  24. }
  25. // Point/spot light
  26. else
  27. {
  28. float3 lightVec = (lightPos - worldPos) * invRange;
  29. float lightDist = length(lightVec);
  30. float3 localDir = lightVec / lightDist;
  31. #ifdef TRANSLUCENT
  32. float NdotL = abs(dot(normal, localDir));
  33. #else
  34. float NdotL = max(dot(normal, localDir), 0.0);
  35. #endif
  36. float atten = saturate(1.0 - lightDist * lightDist);
  37. float spotEffect = dot(localDir, lightDir);
  38. float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
  39. return NdotL * atten * spotAtten;
  40. }
  41. }
  42. float GetVertexLightVolumetric(int index, float3 worldPos)
  43. {
  44. float3 lightDir = cVertexLights[index * 3 + 1].xyz;
  45. float3 lightPos = cVertexLights[index * 3 + 2].xyz;
  46. float invRange = cVertexLights[index * 3].w;
  47. float cutoff = cVertexLights[index * 3 + 1].w;
  48. float invCutoff = cVertexLights[index * 3 + 2].w;
  49. // Directional light
  50. if (invRange == 0.0)
  51. {
  52. return 1.0;
  53. }
  54. // Point/spot light
  55. else
  56. {
  57. float3 lightVec = (lightPos - worldPos) * invRange;
  58. float lightDist = length(lightVec);
  59. float3 localDir = lightVec / lightDist;
  60. float atten = saturate(1.0 - lightDist * lightDist);
  61. float spotEffect = dot(localDir, lightDir);
  62. float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
  63. return atten * spotAtten;
  64. }
  65. }
  66. #endif
  67. #ifdef SHADOW
  68. #ifdef DIRLIGHT
  69. #define NUMCASCADES 4
  70. #else
  71. #define NUMCASCADES 1
  72. #endif
  73. void GetShadowPos(float4 projWorldPos, float3 normal, out float4 shadowPos[NUMCASCADES])
  74. {
  75. // Shadow projection: transform from world space to shadow space
  76. #ifdef NORMALOFFSET
  77. #ifdef DIRLIGHT
  78. float cosAngle = saturate(1.0 - dot(normal, cLightDir));
  79. #else
  80. float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPos.xyz - projWorldPos.xyz)));
  81. #endif
  82. #if defined(DIRLIGHT)
  83. shadowPos[0] = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScale.x * normal, 1.0), cLightMatrices[0]);
  84. shadowPos[1] = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScale.y * normal, 1.0), cLightMatrices[1]);
  85. shadowPos[2] = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScale.z * normal, 1.0), cLightMatrices[2]);
  86. shadowPos[3] = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScale.w * normal, 1.0), cLightMatrices[3]);
  87. #elif defined(SPOTLIGHT)
  88. shadowPos[0] = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScale.x * normal, 1.0), cLightMatrices[1]);
  89. #else
  90. shadowPos[0] = float4(projWorldPos.xyz + cosAngle * cNormalOffsetScale.x * normal - cLightPos.xyz, 0.0);
  91. #endif
  92. #else
  93. #if defined(DIRLIGHT)
  94. shadowPos[0] = mul(projWorldPos, cLightMatrices[0]);
  95. shadowPos[1] = mul(projWorldPos, cLightMatrices[1]);
  96. shadowPos[2] = mul(projWorldPos, cLightMatrices[2]);
  97. shadowPos[3] = mul(projWorldPos, cLightMatrices[3]);
  98. #elif defined(SPOTLIGHT)
  99. shadowPos[0] = mul(projWorldPos, cLightMatrices[1]);
  100. #else
  101. shadowPos[0] = float4(projWorldPos.xyz - cLightPos.xyz, 0.0);
  102. #endif
  103. #endif
  104. }
  105. #endif
  106. #endif
  107. #ifdef COMPILEPS
  108. float GetDiffuse(float3 normal, float3 worldPos, out float3 lightDir)
  109. {
  110. #ifdef DIRLIGHT
  111. lightDir = cLightDirPS;
  112. #ifdef TRANSLUCENT
  113. return abs(dot(normal, lightDir));
  114. #else
  115. return saturate(dot(normal, lightDir));
  116. #endif
  117. #else
  118. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  119. float lightDist = length(lightVec);
  120. lightDir = lightVec / lightDist;
  121. #ifdef TRANSLUCENT
  122. return abs(dot(normal, lightDir)) * Sample2D(LightRampMap, float2(lightDist, 0.0)).r;
  123. #else
  124. return saturate(dot(normal, lightDir)) * Sample2D(LightRampMap, float2(lightDist, 0.0)).r;
  125. #endif
  126. #endif
  127. }
  128. float GetAtten(float3 normal, float3 worldPos, out float3 lightDir)
  129. {
  130. #ifdef DIRLIGHT
  131. lightDir = cLightDirPS;
  132. return saturate(dot(normal, lightDir));
  133. #else
  134. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  135. float lightDist = length(lightVec);
  136. float falloff = pow(saturate(1.0 - pow(lightDist / 1.0, 4.0)), 2.0) / (pow(lightDist, 2.0) + 1.0);
  137. lightDir = lightVec / lightDist;
  138. return saturate(dot(normal, lightDir)) * falloff;
  139. #endif
  140. }
  141. float GetDiffuseVolumetric(float3 worldPos)
  142. {
  143. #ifdef DIRLIGHT
  144. return 1.0;
  145. #else
  146. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  147. float lightDist = length(lightVec);
  148. return Sample2D(LightRampMap, float2(lightDist, 0.0)).r;
  149. #endif
  150. }
  151. float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularPower)
  152. {
  153. float3 halfVec = normalize(normalize(eyeVec) + lightDir);
  154. return saturate(pow(dot(normal, halfVec), specularPower));
  155. }
  156. float GetIntensity(float3 color)
  157. {
  158. return dot(color, float3(0.299, 0.587, 0.114));
  159. }
  160. #ifdef SHADOW
  161. #ifdef DIRLIGHT
  162. #define NUMCASCADES 4
  163. #else
  164. #define NUMCASCADES 1
  165. #endif
  166. #ifdef VSM_SHADOW
  167. float ReduceLightBleeding(float min, float p_max)
  168. {
  169. return clamp((p_max - min) / (1.0 - min), 0.0, 1.0);
  170. }
  171. float Chebyshev(float2 Moments, float depth)
  172. {
  173. //One-tailed inequality valid if depth > Moments.x
  174. float p = float(depth <= Moments.x);
  175. //Compute variance.
  176. float Variance = Moments.y - (Moments.x * Moments.x);
  177. float minVariance = cVSMShadowParams.x;
  178. Variance = max(Variance, minVariance);
  179. //Compute probabilistic upper bound.
  180. float d = depth - Moments.x;
  181. float p_max = Variance / (Variance + d*d);
  182. // Prevent light bleeding
  183. p_max = ReduceLightBleeding(cVSMShadowParams.y, p_max);
  184. return max(p, p_max);
  185. }
  186. #endif
  187. float GetShadow(float4 shadowPos)
  188. {
  189. #if defined(SIMPLE_SHADOW)
  190. // Take one sample
  191. #ifdef D3D11
  192. shadowPos.xyz /= shadowPos.w;
  193. #endif
  194. float inLight = SampleShadow(ShadowMap, shadowPos).r;
  195. #ifndef SHADOWCMP
  196. return cShadowIntensity.y + cShadowIntensity.x * inLight;
  197. #else
  198. #ifndef POINTLIGHT
  199. return cShadowIntensity.y + cShadowIntensity.x * (inLight * shadowPos.w > shadowPos.z);
  200. #else
  201. return cShadowIntensity.y + cShadowIntensity.x * (inLight > shadowPos.z);
  202. #endif
  203. #endif
  204. #elif defined(PCF_SHADOW)
  205. // Take four samples and average them
  206. // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
  207. #ifdef D3D11
  208. shadowPos.xyz /= shadowPos.w;
  209. #endif
  210. #if !defined(POINTLIGHT) && !defined(D3D11)
  211. float2 offsets = cShadowMapInvSize * shadowPos.w;
  212. #else
  213. float2 offsets = cShadowMapInvSize;
  214. #endif
  215. float4 shadowPos2 = float4(shadowPos.x + offsets.x, shadowPos.yzw);
  216. float4 shadowPos3 = float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw);
  217. float4 shadowPos4 = float4(shadowPos.xy + offsets.xy, shadowPos.zw);
  218. float4 inLight = float4(
  219. SampleShadow(ShadowMap, shadowPos).r,
  220. SampleShadow(ShadowMap, shadowPos2).r,
  221. SampleShadow(ShadowMap, shadowPos3).r,
  222. SampleShadow(ShadowMap, shadowPos4).r
  223. );
  224. #ifndef SHADOWCMP
  225. return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
  226. #else
  227. #ifndef POINTLIGHT
  228. return cShadowIntensity.y + dot(inLight * shadowPos.w > shadowPos.z, cShadowIntensity.x);
  229. #else
  230. return cShadowIntensity.y + dot(inLight > shadowPos.z, cShadowIntensity.x);
  231. #endif
  232. #endif
  233. #elif defined(VSM_SHADOW)
  234. float2 samples = Sample2D(ShadowMap, shadowPos.xy / shadowPos.w).rg;
  235. return cShadowIntensity.y + cShadowIntensity.x * Chebyshev(samples, shadowPos.z/shadowPos.w);
  236. #endif
  237. }
  238. #ifdef POINTLIGHT
  239. float GetPointShadow(float3 lightVec)
  240. {
  241. float3 axis = SampleCube(FaceSelectCubeMap, lightVec).rgb;
  242. float depth = abs(dot(lightVec, axis));
  243. // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
  244. // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
  245. // case filtering across faces is wrong
  246. const float factor = 1.0 / 256.0;
  247. lightVec += factor * axis * lightVec;
  248. // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
  249. float4 indirectPos = SampleCube(IndirectionCubeMap, lightVec);
  250. indirectPos.xy *= cShadowCubeAdjust.xy;
  251. indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
  252. float4 shadowPos = float4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
  253. return GetShadow(shadowPos);
  254. }
  255. #endif
  256. #ifdef DIRLIGHT
  257. float GetDirShadowFade(float inLight, float depth)
  258. {
  259. return saturate(inLight + saturate((depth - cShadowDepthFade.z) * cShadowDepthFade.w));
  260. }
  261. float GetDirShadow(const float4 iShadowPos[NUMCASCADES], float depth)
  262. {
  263. float4 shadowPos;
  264. if (depth < cShadowSplits.x)
  265. shadowPos = iShadowPos[0];
  266. else if (depth < cShadowSplits.y)
  267. shadowPos = iShadowPos[1];
  268. else if (depth < cShadowSplits.z)
  269. shadowPos = iShadowPos[2];
  270. else
  271. shadowPos = iShadowPos[3];
  272. return GetDirShadowFade(GetShadow(shadowPos), depth);
  273. }
  274. float GetDirShadowDeferred(float4 projWorldPos, float3 normal, float depth)
  275. {
  276. float4 shadowPos;
  277. #ifdef NORMALOFFSET
  278. float cosAngle = saturate(1.0 - dot(normal, cLightDirPS));
  279. if (depth < cShadowSplits.x)
  280. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.x * normal, 1.0), cLightMatricesPS[0]);
  281. else if (depth < cShadowSplits.y)
  282. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.y * normal, 1.0), cLightMatricesPS[1]);
  283. else if (depth < cShadowSplits.z)
  284. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.z * normal, 1.0), cLightMatricesPS[2]);
  285. else
  286. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.w * normal, 1.0), cLightMatricesPS[3]);
  287. #else
  288. if (depth < cShadowSplits.x)
  289. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  290. else if (depth < cShadowSplits.y)
  291. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  292. else if (depth < cShadowSplits.z)
  293. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  294. else
  295. shadowPos = mul(projWorldPos, cLightMatricesPS[3]);
  296. #endif
  297. return GetDirShadowFade(GetShadow(shadowPos), depth);
  298. }
  299. #endif
  300. float GetShadow(float4 iShadowPos[NUMCASCADES], float depth)
  301. {
  302. #if defined(DIRLIGHT)
  303. return GetDirShadow(iShadowPos, depth);
  304. #elif defined(SPOTLIGHT)
  305. return GetShadow(iShadowPos[0]);
  306. #else
  307. return GetPointShadow(iShadowPos[0].xyz);
  308. #endif
  309. }
  310. float GetShadowDeferred(float4 projWorldPos, float3 normal, float depth)
  311. {
  312. #ifdef DIRLIGHT
  313. return GetDirShadowDeferred(projWorldPos, normal, depth);
  314. #else
  315. #ifdef NORMALOFFSET
  316. float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPosPS.xyz - projWorldPos.xyz)));
  317. projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
  318. #endif
  319. #ifdef SPOTLIGHT
  320. float4 shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  321. return GetShadow(shadowPos);
  322. #else
  323. float3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
  324. return GetPointShadow(shadowPos);
  325. #endif
  326. #endif
  327. }
  328. #endif
  329. #endif