Lighting.hlsl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. lightDir = cLightDirPS;
  131. return saturate(dot(normal, lightDir));
  132. }
  133. float GetAttenPoint(float3 normal, float3 worldPos, out float3 lightDir)
  134. {
  135. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  136. float lightDist = length(lightVec);
  137. float falloff = pow(saturate(1.0 - pow(lightDist / 1.0, 4.0)), 2.0) * 3.14159265358979323846 / (4 * 3.14159265358979323846)*(pow(lightDist, 2.0) + 1.0);
  138. lightDir = lightVec / lightDist;
  139. return saturate(dot(normal, lightDir)) * falloff;
  140. }
  141. float GetAttenSpot(float3 normal, float3 worldPos, out float3 lightDir)
  142. {
  143. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  144. float lightDist = length(lightVec);
  145. float falloff = pow(saturate(1.0 - pow(lightDist / 1.0, 4.0)), 2.0) / (pow(lightDist, 2.0) + 1.0);
  146. lightDir = lightVec / lightDist;
  147. return saturate(dot(normal, lightDir)) * falloff;
  148. }
  149. float GetDiffuseVolumetric(float3 worldPos)
  150. {
  151. #ifdef DIRLIGHT
  152. return 1.0;
  153. #else
  154. float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
  155. float lightDist = length(lightVec);
  156. return Sample2D(LightRampMap, float2(lightDist, 0.0)).r;
  157. #endif
  158. }
  159. float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularPower)
  160. {
  161. float3 halfVec = normalize(normalize(eyeVec) + lightDir);
  162. return saturate(pow(dot(normal, halfVec), specularPower));
  163. }
  164. float GetIntensity(float3 color)
  165. {
  166. return dot(color, float3(0.299, 0.587, 0.114));
  167. }
  168. #ifdef SHADOW
  169. #ifdef DIRLIGHT
  170. #define NUMCASCADES 4
  171. #else
  172. #define NUMCASCADES 1
  173. #endif
  174. #ifdef VSM_SHADOW
  175. float ReduceLightBleeding(float min, float p_max)
  176. {
  177. return clamp((p_max - min) / (1.0 - min), 0.0, 1.0);
  178. }
  179. float Chebyshev(float2 Moments, float depth)
  180. {
  181. //One-tailed inequality valid if depth > Moments.x
  182. float p = float(depth <= Moments.x);
  183. //Compute variance.
  184. float Variance = Moments.y - (Moments.x * Moments.x);
  185. float minVariance = cVSMShadowParams.x;
  186. Variance = max(Variance, minVariance);
  187. //Compute probabilistic upper bound.
  188. float d = depth - Moments.x;
  189. float p_max = Variance / (Variance + d*d);
  190. // Prevent light bleeding
  191. p_max = ReduceLightBleeding(cVSMShadowParams.y, p_max);
  192. return max(p, p_max);
  193. }
  194. #endif
  195. float GetShadow(float4 shadowPos)
  196. {
  197. #if defined(SIMPLE_SHADOW)
  198. // Take one sample
  199. #ifdef D3D11
  200. shadowPos.xyz /= shadowPos.w;
  201. #endif
  202. float inLight = SampleShadow(ShadowMap, shadowPos).r;
  203. #ifndef SHADOWCMP
  204. return cShadowIntensity.y + cShadowIntensity.x * inLight;
  205. #else
  206. #ifndef POINTLIGHT
  207. return cShadowIntensity.y + cShadowIntensity.x * (inLight * shadowPos.w > shadowPos.z);
  208. #else
  209. return cShadowIntensity.y + cShadowIntensity.x * (inLight > shadowPos.z);
  210. #endif
  211. #endif
  212. #elif defined(PCF_SHADOW)
  213. // Take four samples and average them
  214. // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
  215. #ifdef D3D11
  216. shadowPos.xyz /= shadowPos.w;
  217. #endif
  218. #if !defined(POINTLIGHT) && !defined(D3D11)
  219. float2 offsets = cShadowMapInvSize * shadowPos.w;
  220. #else
  221. float2 offsets = cShadowMapInvSize;
  222. #endif
  223. float4 shadowPos2 = float4(shadowPos.x + offsets.x, shadowPos.yzw);
  224. float4 shadowPos3 = float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw);
  225. float4 shadowPos4 = float4(shadowPos.xy + offsets.xy, shadowPos.zw);
  226. float4 inLight = float4(
  227. SampleShadow(ShadowMap, shadowPos).r,
  228. SampleShadow(ShadowMap, shadowPos2).r,
  229. SampleShadow(ShadowMap, shadowPos3).r,
  230. SampleShadow(ShadowMap, shadowPos4).r
  231. );
  232. #ifndef SHADOWCMP
  233. return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
  234. #else
  235. #ifndef POINTLIGHT
  236. return cShadowIntensity.y + dot(inLight * shadowPos.w > shadowPos.z, cShadowIntensity.x);
  237. #else
  238. return cShadowIntensity.y + dot(inLight > shadowPos.z, cShadowIntensity.x);
  239. #endif
  240. #endif
  241. #elif defined(VSM_SHADOW)
  242. float2 samples = Sample2D(ShadowMap, shadowPos.xy / shadowPos.w).rg;
  243. return cShadowIntensity.y + cShadowIntensity.x * Chebyshev(samples, shadowPos.z/shadowPos.w);
  244. #endif
  245. }
  246. #ifdef POINTLIGHT
  247. float GetPointShadow(float3 lightVec)
  248. {
  249. float3 axis = SampleCube(FaceSelectCubeMap, lightVec).rgb;
  250. float depth = abs(dot(lightVec, axis));
  251. // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
  252. // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
  253. // case filtering across faces is wrong
  254. const float factor = 1.0 / 256.0;
  255. lightVec += factor * axis * lightVec;
  256. // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
  257. float4 indirectPos = SampleCube(IndirectionCubeMap, lightVec);
  258. indirectPos.xy *= cShadowCubeAdjust.xy;
  259. indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
  260. float4 shadowPos = float4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
  261. return GetShadow(shadowPos);
  262. }
  263. #endif
  264. #ifdef DIRLIGHT
  265. float GetDirShadowFade(float inLight, float depth)
  266. {
  267. return saturate(inLight + saturate((depth - cShadowDepthFade.z) * cShadowDepthFade.w));
  268. }
  269. float GetDirShadow(const float4 iShadowPos[NUMCASCADES], float depth)
  270. {
  271. float4 shadowPos;
  272. if (depth < cShadowSplits.x)
  273. shadowPos = iShadowPos[0];
  274. else if (depth < cShadowSplits.y)
  275. shadowPos = iShadowPos[1];
  276. else if (depth < cShadowSplits.z)
  277. shadowPos = iShadowPos[2];
  278. else
  279. shadowPos = iShadowPos[3];
  280. return GetDirShadowFade(GetShadow(shadowPos), depth);
  281. }
  282. float GetDirShadowDeferred(float4 projWorldPos, float3 normal, float depth)
  283. {
  284. float4 shadowPos;
  285. #ifdef NORMALOFFSET
  286. float cosAngle = saturate(1.0 - dot(normal, cLightDirPS));
  287. if (depth < cShadowSplits.x)
  288. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.x * normal, 1.0), cLightMatricesPS[0]);
  289. else if (depth < cShadowSplits.y)
  290. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.y * normal, 1.0), cLightMatricesPS[1]);
  291. else if (depth < cShadowSplits.z)
  292. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.z * normal, 1.0), cLightMatricesPS[2]);
  293. else
  294. shadowPos = mul(float4(projWorldPos.xyz + cosAngle * cNormalOffsetScalePS.w * normal, 1.0), cLightMatricesPS[3]);
  295. #else
  296. if (depth < cShadowSplits.x)
  297. shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
  298. else if (depth < cShadowSplits.y)
  299. shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  300. else if (depth < cShadowSplits.z)
  301. shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
  302. else
  303. shadowPos = mul(projWorldPos, cLightMatricesPS[3]);
  304. #endif
  305. return GetDirShadowFade(GetShadow(shadowPos), depth);
  306. }
  307. #endif
  308. float GetShadow(float4 iShadowPos[NUMCASCADES], float depth)
  309. {
  310. #if defined(DIRLIGHT)
  311. return GetDirShadow(iShadowPos, depth);
  312. #elif defined(SPOTLIGHT)
  313. return GetShadow(iShadowPos[0]);
  314. #else
  315. return GetPointShadow(iShadowPos[0].xyz);
  316. #endif
  317. }
  318. float GetShadowDeferred(float4 projWorldPos, float3 normal, float depth)
  319. {
  320. #ifdef DIRLIGHT
  321. return GetDirShadowDeferred(projWorldPos, normal, depth);
  322. #else
  323. #ifdef NORMALOFFSET
  324. float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPosPS.xyz - projWorldPos.xyz)));
  325. projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
  326. #endif
  327. #ifdef SPOTLIGHT
  328. float4 shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
  329. return GetShadow(shadowPos);
  330. #else
  331. float3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
  332. return GetPointShadow(shadowPos);
  333. #endif
  334. #endif
  335. }
  336. #endif
  337. #endif