DeferredPointLight.bsl 4.9 KB

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