PageRenderTime 1755ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Hieroglyph3/Applications/Data/Shaders/Lights.hlsl

#
Unknown | 273 lines | 236 code | 37 blank | 0 comment | 0 complexity | b06e75a62bfc3b66612182eb0505bfbb MD5 | raw file
Possible License(s): MIT
  1. //--------------------------------------------------------------------------------
  2. // Lights
  3. //
  4. // Vertex shaders and pixel shaders for performing the lighting pass of a
  5. // classic deferred renderer
  6. //--------------------------------------------------------------------------------
  7. //-------------------------------------------------------------------------------------------------
  8. // Constants
  9. //-------------------------------------------------------------------------------------------------
  10. cbuffer LightParams
  11. {
  12. float3 LightPos;
  13. float3 LightColor;
  14. float3 LightDirection;
  15. float2 SpotlightAngles;
  16. float4 LightRange;
  17. };
  18. cbuffer CameraParams
  19. {
  20. float3 CameraPos;
  21. matrix ProjMatrix;
  22. matrix InvProjMatrix;
  23. }
  24. cbuffer Transforms
  25. {
  26. matrix WorldMatrix;
  27. matrix WorldViewMatrix;
  28. matrix WorldViewProjMatrix;
  29. };
  30. // This macro indicates whether we're currently rendering a volume
  31. #define VOLUMERENDERING ( ( POINTLIGHT || SPOTLIGHT ) && LIGHTVOLUMES )
  32. // This indicates the number of MSAA samples
  33. #if MSAA
  34. #define NUMSUBSAMPLES 4
  35. #else
  36. #define NUMSUBSAMPLES 1
  37. #endif
  38. //-------------------------------------------------------------------------------------------------
  39. // Input/output structs
  40. //-------------------------------------------------------------------------------------------------
  41. struct VSInput
  42. {
  43. float4 Position : POSITION;
  44. };
  45. struct VSOutput
  46. {
  47. float4 PositionCS : SV_Position;
  48. float3 ViewRay : VIEWRAY;
  49. };
  50. struct PSOutput
  51. {
  52. float4 Color : SV_Target0;
  53. };
  54. //-------------------------------------------------------------------------------------------------
  55. // Textures
  56. //-------------------------------------------------------------------------------------------------
  57. #if MSAA
  58. Texture2DMS<float4, 4> NormalTexture : register( t0 );
  59. Texture2DMS<float4, 4> DiffuseAlbedoTexture : register( t1 );
  60. Texture2DMS<float4, 4> SpecularAlbedoTexture : register( t2 );
  61. Texture2DMS<float4, 4> PositionTexture : register( t3 );
  62. Texture2DMS<float, 4> DepthTexture : register( t3 );
  63. #else
  64. Texture2D NormalTexture : register( t0 );
  65. Texture2D DiffuseAlbedoTexture : register( t1 );
  66. Texture2D SpecularAlbedoTexture : register( t2 );
  67. Texture2D PositionTexture : register( t3 );
  68. Texture2D DepthTexture : register( t3 );
  69. #endif
  70. //-------------------------------------------------------------------------------------------------
  71. // Vertex shader entry point
  72. //-------------------------------------------------------------------------------------------------
  73. VSOutput VSMain( in VSInput input )
  74. {
  75. VSOutput output;
  76. #if VOLUMERENDERING
  77. // Apply the world * view * projection
  78. output.PositionCS = mul( input.Position, WorldViewProjMatrix );
  79. // Calculate the view space vertex position, and output that as the view ray
  80. float3 positionVS = mul( input.Position, WorldViewMatrix ).xyz;
  81. output.ViewRay = positionVS;
  82. #else
  83. // Just copy the position
  84. output.PositionCS = input.Position;
  85. // For a quad we can clamp in the vertex shader, since we only interpolate in the XY direction
  86. float3 positionVS = mul( input.Position, InvProjMatrix ).xyz;
  87. output.ViewRay = float3( positionVS.xy / positionVS.z, 1.0f );
  88. #endif
  89. return output;
  90. }
  91. //-------------------------------------------------------------------------------------------------
  92. // Decodes a spheremap-encoded normal
  93. //-------------------------------------------------------------------------------------------------
  94. float3 SpheremapDecode( float2 encoded )
  95. {
  96. float4 nn = float4( encoded, 1, -1 );
  97. float l = dot( nn.xyz, -nn.xyw );
  98. nn.z = l;
  99. nn.xy *= sqrt( l );
  100. return nn.xyz * 2 + float3( 0, 0, -1 );
  101. }
  102. //-------------------------------------------------------------------------------------------------
  103. // Converts a depth buffer value to view-space position
  104. //-------------------------------------------------------------------------------------------------
  105. float3 PositionFromDepth( in float zBufferDepth, in float3 viewRay )
  106. {
  107. #if VOLUMERENDERING
  108. // Clamp the view space position to the plane at Z = 1
  109. viewRay = float3( viewRay.xy / viewRay.z, 1.0f );
  110. #else
  111. // For a quad we already clamped in the vertex shader
  112. viewRay = viewRay.xyz;
  113. #endif
  114. // Convert to a linear depth value using the projection matrix
  115. float linearDepth = ProjMatrix[3][2] / ( zBufferDepth - ProjMatrix[2][2] );
  116. return viewRay * linearDepth;
  117. }
  118. //-------------------------------------------------------------------------------------------------
  119. // Helper function for extracting G-Buffer attributes
  120. //-------------------------------------------------------------------------------------------------
  121. void GetGBufferAttributes( in float2 screenPos, in float3 viewRay, in int subSampleIndex, out float3 normal,
  122. out float3 position, out float3 diffuseAlbedo, out float3 specularAlbedo,
  123. out float specularPower )
  124. {
  125. // Determine our coordinate for sampling the texture based on the current screen position
  126. int3 sampleCoord = int3( screenPos.xy, 0 );
  127. #if GBUFFEROPTIMIZATIONS
  128. #if MSAA
  129. diffuseAlbedo = DiffuseAlbedoTexture.Load( sampleCoord.xy, subSampleIndex ).xyz;
  130. normal = SpheremapDecode( NormalTexture.Load( sampleCoord.xy, subSampleIndex ).xy );
  131. float4 spec = SpecularAlbedoTexture.Load( sampleCoord.xy, subSampleIndex );
  132. position = PositionFromDepth( DepthTexture.Load( sampleCoord.xy, subSampleIndex ).x, viewRay );
  133. #else
  134. normal = SpheremapDecode( NormalTexture.Load( sampleCoord ).xy );
  135. diffuseAlbedo = DiffuseAlbedoTexture.Load( sampleCoord ).xyz;
  136. float4 spec = SpecularAlbedoTexture.Load( sampleCoord );
  137. position = PositionFromDepth( DepthTexture.Load( sampleCoord ).x, viewRay );
  138. #endif
  139. specularAlbedo = spec.xyz;
  140. specularPower = spec.w * 255.0f;
  141. #else
  142. #if MSAA
  143. normal = NormalTexture.Load( sampleCoord.xy, subSampleIndex ).xyz;
  144. position = PositionTexture.Load( sampleCoord.xy, subSampleIndex ).xyz;
  145. diffuseAlbedo = DiffuseAlbedoTexture.Load( sampleCoord.xy, subSampleIndex ).xyz;
  146. float4 spec = SpecularAlbedoTexture.Load( sampleCoord.xy, subSampleIndex );
  147. #else
  148. normal = NormalTexture.Load( sampleCoord ).xyz;
  149. position = PositionTexture.Load( sampleCoord ).xyz;
  150. diffuseAlbedo = DiffuseAlbedoTexture.Load( sampleCoord ).xyz;
  151. float4 spec = SpecularAlbedoTexture.Load( sampleCoord );
  152. #endif
  153. specularAlbedo = spec.xyz;
  154. specularPower = spec.w;
  155. #endif
  156. }
  157. //-------------------------------------------------------------------------------------------------
  158. // Calculates the lighting term for a single G-Buffer texel
  159. //-------------------------------------------------------------------------------------------------
  160. float3 CalcLighting( in float3 normal, in float3 position, in float3 diffuseAlbedo,
  161. in float3 specularAlbedo, in float specularPower )
  162. {
  163. // Calculate the diffuse term
  164. float3 L = 0;
  165. float attenuation = 1.0f;
  166. #if POINTLIGHT || SPOTLIGHT
  167. // Base the the light vector on the light position
  168. L = LightPos - position;
  169. // Calculate attenuation based on distance from the light source
  170. float dist = length( L );
  171. attenuation = max( 0, 1.0f - ( dist / LightRange.x ) );
  172. L /= dist;
  173. #elif DIRECTIONALLIGHT
  174. // Light direction is explicit for directional lights
  175. L = -LightDirection;
  176. #endif
  177. #if SPOTLIGHT
  178. // Also add in the spotlight attenuation factor
  179. float3 L2 = LightDirection;
  180. float rho = dot( -L, L2 );
  181. attenuation *= saturate( ( rho - SpotlightAngles.y ) / ( SpotlightAngles.x - SpotlightAngles.y ) );
  182. #endif
  183. const float DiffuseNormalizationFactor = 1.0f / 3.14159265f;
  184. float nDotL = saturate( dot( normal, L ) );
  185. float3 diffuse = nDotL * LightColor * diffuseAlbedo * DiffuseNormalizationFactor;
  186. #if GBUFFEROPTIMIZATIONS
  187. // In view space camera position is (0, 0, 0)
  188. float3 camPos = 0.0f;
  189. #else
  190. float3 camPos = CameraPos;
  191. #endif
  192. // Calculate the specular term
  193. float3 V = camPos - position;
  194. float3 H = normalize( L + V );
  195. float specNormalizationFactor = ( ( specularPower + 8.0f ) / ( 8.0f * 3.14159265f ) );
  196. float3 specular = pow( saturate( dot( normal, H ) ), specularPower ) * specNormalizationFactor * LightColor * specularAlbedo.xyz * nDotL;
  197. // Final value is the sum of the albedo and diffuse with attenuation applied
  198. return ( diffuse + specular ) * attenuation;
  199. }
  200. //-------------------------------------------------------------------------------------------------
  201. // Light pixel shader
  202. //-------------------------------------------------------------------------------------------------
  203. PSOutput PSMain( in VSOutput input, in float4 screenPos : SV_Position, in uint coverage : SV_Coverage )
  204. {
  205. PSOutput output;
  206. float3 lighting = 0;
  207. float3 normal;
  208. float3 position;
  209. float3 diffuseAlbedo;
  210. float3 specularAlbedo;
  211. float specularPower;
  212. #if MSAA
  213. // Calculate lighting for MSAA samples
  214. float numSamplesApplied = 0.0f;
  215. for ( int i = 0; i < NUMSUBSAMPLES; ++i )
  216. {
  217. // We only want to calculate lighting for a sample if the light volume is covered.
  218. // We determine this using the input coverage mask.
  219. if ( coverage & ( 1 << i ) )
  220. {
  221. GetGBufferAttributes( screenPos.xy, input.ViewRay, i, normal, position, diffuseAlbedo,
  222. specularAlbedo, specularPower );
  223. lighting += CalcLighting( normal, position, diffuseAlbedo, specularAlbedo, specularPower );
  224. ++numSamplesApplied;
  225. }
  226. }
  227. lighting /= numSamplesApplied;
  228. #else
  229. // Calculate lighting for a single G-Buffer sample
  230. GetGBufferAttributes( screenPos.xy, input.ViewRay, 0, normal, position, diffuseAlbedo,
  231. specularAlbedo, specularPower );
  232. lighting = CalcLighting( normal, position, diffuseAlbedo, specularAlbedo, specularPower );
  233. #endif
  234. output.Color = float4( lighting, 1.0f );
  235. return output;
  236. }