DeferredPointLight.bsl 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #if MSAA
  2. #define MSAA_COUNT 2
  3. #else
  4. #define MSAA_COUNT 1
  5. #endif
  6. #include "$ENGINE$\DeferredLightCommon.bslinc"
  7. technique DeferredPointLight
  8. {
  9. mixin DeferredLightCommon;
  10. variations
  11. {
  12. MSAA = { true, false };
  13. INSIDE_GEOMETRY = { true, false };
  14. MSAA_RESOLVE_0TH = { true, false };
  15. };
  16. #if MSAA
  17. stencil
  18. {
  19. enabled = true;
  20. readmask = 0x80;
  21. #if INSIDE_GEOMETRY
  22. back = { keep, keep, keep, eq };
  23. #else
  24. front = { keep, keep, keep, eq };
  25. #endif
  26. #if MSAA_RESOLVE_0TH
  27. reference = 0;
  28. #else
  29. reference = 0x80;
  30. #endif
  31. };
  32. #endif
  33. code
  34. {
  35. struct VStoFS
  36. {
  37. float4 position : SV_POSITION;
  38. float4 screenPos : TEXCOORD0;
  39. };
  40. struct VertexInput
  41. {
  42. float3 position : POSITION;
  43. uint vertexIdx : SV_VERTEXID;
  44. };
  45. VStoFS vsmain(VertexInput input)
  46. {
  47. VStoFS output;
  48. float3 worldPosition;
  49. uint numSides = gLightGeometry.x;
  50. if(numSides > 0) // Generate spot light geometry
  51. {
  52. uint numSlices = gLightGeometry.y;
  53. float radius = gLightGeometry.w;
  54. float angle = gLightSpotAnglesAndSqrdInvAttRadius.x;
  55. // Extra scale to ensure edges lie on the circle, not inside it
  56. // TODO - These can be precomputed
  57. float extraRadiusScale = 1.0f / cos(PI / (float)numSides);
  58. float angleTan = tan(angle);
  59. float height = radius / angleTan;
  60. uint sphereStartIdx = numSides * numSlices;
  61. // Cone vertices
  62. if (input.vertexIdx < sphereStartIdx)
  63. {
  64. uint sliceIdx = input.vertexIdx / numSides;
  65. uint sideIdx = input.vertexIdx % numSides;
  66. float curAngle = sideIdx * 2 * PI / (float)numSides;
  67. float sliceOffset = height * sliceIdx / (float)(numSlices - 1);
  68. float sliceRadius = sliceOffset * angleTan * extraRadiusScale;
  69. float4 localPos = float4(sliceRadius * cos(curAngle),
  70. sliceRadius * sin(curAngle), -sliceOffset, 1.0f);
  71. worldPosition = (mul(gMatConeTransform, localPos)).xyz;
  72. }
  73. else // Sphere cap vertices
  74. {
  75. uint sphereVertexIdx = input.vertexIdx - sphereStartIdx;
  76. uint sliceIdx = sphereVertexIdx / numSides;
  77. uint sideIdx = sphereVertexIdx % numSides;
  78. float curAngle = sideIdx * 2 * PI / (float)numSides;
  79. float sliceOffset = radius * sliceIdx / (float)(numSlices - 1);
  80. float sliceRadius = sqrt(max(0.0f, radius * radius - sliceOffset * sliceOffset)) * extraRadiusScale;
  81. float4 localPos = float4(sliceRadius * cos(curAngle),
  82. sliceRadius * sin(curAngle), -height - sliceOffset, 1.0f);
  83. worldPosition = (mul(gMatConeTransform, localPos)).xyz;
  84. }
  85. }
  86. else // Scale and position pre-generated sphere geometry
  87. {
  88. worldPosition = input.position * gLightGeometry.z + gLightPositionAndSrcRadius.xyz;
  89. }
  90. output.screenPos = mul(gMatViewProj, float4(worldPosition, 1));
  91. output.position = output.screenPos;
  92. return output;
  93. }
  94. float4 fsmain(VStoFS input
  95. #if MSAA_COUNT > 1 && !MSAA_RESOLVE_0TH
  96. , uint sampleIdx : SV_SampleIndex
  97. #endif
  98. ) : SV_Target0
  99. {
  100. float2 ndcPos = input.screenPos.xy / input.screenPos.w;
  101. uint2 pixelPos = NDCToScreen(ndcPos);
  102. #if MSAA_COUNT > 1
  103. #if MSAA_RESOLVE_0TH
  104. SurfaceData surfaceData = getGBufferData(pixelPos, 0);
  105. #else
  106. SurfaceData surfaceData = getGBufferData(pixelPos, sampleIdx);
  107. #endif
  108. #else
  109. SurfaceData surfaceData = getGBufferData(pixelPos);
  110. #endif
  111. if(surfaceData.worldNormal.w > 0.0f)
  112. {
  113. // x, y are now in clip space, z, w are in view space
  114. // We multiply them by a special inverse view-projection matrix, that had the projection entries that effect
  115. // z, w eliminated (since they are already in view space)
  116. // Note: Multiply by depth should be avoided if using ortographic projection
  117. float4 mixedSpacePos = float4(ndcPos.xy * -surfaceData.depth, surfaceData.depth, 1);
  118. float4 worldPosition4D = mul(gMatScreenToWorld, mixedSpacePos);
  119. float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
  120. float3 V = normalize(gViewOrigin - worldPosition);
  121. float3 N = surfaceData.worldNormal.xyz;
  122. float3 R = 2 * dot(V, N) * N - V;
  123. float3 specR = getSpecularDominantDir(N, R, surfaceData.roughness);
  124. float roughness2 = max(surfaceData.roughness, 0.08f);
  125. roughness2 *= roughness2;
  126. LightData lightData = getLightData();
  127. #if MSAA_COUNT > 1
  128. #if MSAA_RESOLVE_0TH
  129. float occlusion = gLightOcclusionTex.Load(pixelPos, 0).r;
  130. #else
  131. float occlusion = gLightOcclusionTex.Load(pixelPos, sampleIdx).r;
  132. #endif
  133. #else
  134. float occlusion = gLightOcclusionTex.Load(int3(pixelPos, 0)).r;
  135. #endif
  136. // Reverse the sqrt we did when storing it
  137. occlusion *= occlusion;
  138. occlusion = 1.0f - occlusion;
  139. bool isSpot = gShiftedLightPositionAndType.w > 0.5f;
  140. if(isSpot)
  141. return float4(getLuminanceSpot(lightData, worldPosition, V, R, roughness2, surfaceData) * occlusion, 1.0f);
  142. else // Radial
  143. return float4(getLuminanceRadial(lightData, worldPosition, V, R, roughness2, surfaceData) * occlusion, 1.0f);
  144. }
  145. else
  146. return float4(0.0f, 0.0f, 0.0f, 0.0f);
  147. }
  148. };
  149. };