DeferredPointLight.bsl 4.3 KB

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