PPBokehDOF.bsl 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #include "$ENGINE$\DepthOfFieldCommon.bslinc"
  2. #include "$ENGINE$\PerCameraData.bslinc"
  3. shader PPBokehDOF
  4. {
  5. mixin DepthOfFieldCommon;
  6. mixin PerCameraData;
  7. variations
  8. {
  9. DEPTH_OCCLUSION = { true, false };
  10. };
  11. depth
  12. {
  13. write = false;
  14. read = false;
  15. };
  16. blend
  17. {
  18. target
  19. {
  20. enabled = true;
  21. color = { one, one, add };
  22. alpha = { one, one, add };
  23. };
  24. };
  25. code
  26. {
  27. cbuffer Params
  28. {
  29. uint2 gTileCount;
  30. float2 gInvInputSize;
  31. float2 gInvOutputSize;
  32. float gAdaptiveThresholdColor;
  33. float gAdaptiveThresholdCOC;
  34. float2 gBokehSize;
  35. uint gLayerPixelOffset;
  36. float gInvDepthRange;
  37. };
  38. Texture2D gInputTex;
  39. SamplerState gInputSampler
  40. {
  41. AddressU = CLAMP;
  42. AddressV = CLAMP;
  43. AddressW = CLAMP;
  44. };
  45. struct VStoFS
  46. {
  47. float4 position : SV_POSITION;
  48. noperspective float2 uv0 : TEXCOORD0;
  49. nointerpolation float4 color : TEXCOORD1;
  50. #if DEPTH_OCCLUSION
  51. float2 screenUV : TEXCOORD2;
  52. nointerpolation float depth : TEXCOORD3;
  53. #endif
  54. };
  55. struct VertexInput
  56. {
  57. uint vertexId : SV_VertexID;
  58. uint instanceId : SV_InstanceID;
  59. float2 uv0 : TEXCOORD0;
  60. };
  61. VStoFS vsmain(VertexInput input)
  62. {
  63. uint vid = input.vertexId;
  64. uint iid = input.instanceId;
  65. // We group quads in tiles for perfomance reasons (less instances)
  66. // Additionally, we group the quads within the tiles into 2x2 blocks for adaptive rendering
  67. // (Generally a tile is 8 quads, meaning 2 blocks per tile)
  68. uint quadIdxInTile = vid / 4;
  69. uint quadIdxInBlock = quadIdxInTile % 4;
  70. // Find the top-left position of the current block, in pixels
  71. uint blocksPerTile = QUADS_PER_TILE / 4;
  72. // TODO - Since the way we're sampling below, should this be the block center?
  73. // - Then again maybe not, because the offset we apply to blockPos below seems similar?
  74. uint blocksInRow = gTileCount.x / (blocksPerTile * 2);
  75. float2 blockPos =
  76. float2(iid % blocksInRow, iid / blocksInRow)
  77. * uint2(blocksPerTile * 2, 2) // Each tile is 2 pixels (quads) high, with N blocks with 2 pixels (quads) wide
  78. + uint2((quadIdxInTile/4) * 2, 0); // Each block has N quads laid out in a row, and each block is 2 quads wide
  79. // Color in .rgb, linear depth in .a
  80. float4 samples[4];
  81. samples[0] = gInputTex.SampleLevel(gInputSampler, (blockPos + float2(-0.5f, -0.5f)) * gInvInputSize, 0);
  82. samples[1] = gInputTex.SampleLevel(gInputSampler, (blockPos + float2( 0.5f, -0.5f)) * gInvInputSize, 0);
  83. samples[2] = gInputTex.SampleLevel(gInputSampler, (blockPos + float2(-0.5f, 0.5f)) * gInvInputSize, 0);
  84. samples[3] = gInputTex.SampleLevel(gInputSampler, (blockPos + float2( 0.5f, 0.5f)) * gInvInputSize, 0);
  85. float4 minSamples = min(min(samples[0], samples[1]), min(samples[2], samples[3]));
  86. float4 maxSamples = max(max(samples[0], samples[1]), max(samples[2], samples[3]));
  87. bool needSeparateQuads = false;
  88. // Are the colors too different?
  89. float3 colorDiff = maxSamples.rgb - minSamples.rgb;
  90. if(dot(colorDiff, 1) > gAdaptiveThresholdColor)
  91. needSeparateQuads = true;
  92. // Do the samples fall on different layers?
  93. int minLayer = minSamples.a < gFocalPlaneDistance ? 0 :
  94. (minSamples.a > (gFocalPlaneDistance + gFocalLength) ? 2 : 1);
  95. int maxLayer = maxSamples.a < gFocalPlaneDistance ? 0 :
  96. (maxSamples.a > (gFocalPlaneDistance + gFocalLength) ? 2 : 1);
  97. if(minLayer != maxLayer)
  98. needSeparateQuads = true;
  99. // Don't skip small quads
  100. float avgDepth = (minSamples.a + maxSamples.a) * 0.5f;
  101. float avgCOC = circleOfConfusionPhysical(avgDepth);
  102. if(avgCOC < gAdaptiveThresholdCOC)
  103. needSeparateQuads = true;
  104. float4 colorAndDepth;
  105. if(needSeparateQuads)
  106. {
  107. colorAndDepth = samples[quadIdxInBlock];
  108. blockPos += float2(quadIdxInBlock % 2, quadIdxInBlock / 2) - 0.5f;
  109. }
  110. else
  111. colorAndDepth = (samples[0] + samples[1] + samples[2] + samples[3]) * 0.25f;
  112. float sceneDepth = colorAndDepth.a;
  113. float coc = circleOfConfusionPhysical(sceneDepth);
  114. // 2 pixel minimum size
  115. float2 cocPixelSize = max(coc * gBokehSize.xy, 2.0f);
  116. float4 color = float4(colorAndDepth.rgb, 1);
  117. float2 layer = computeLayerContributions(sceneDepth);
  118. color *= (sceneDepth < gFocalPlaneDistance) ? layer.r : layer.g;
  119. if(!needSeparateQuads)
  120. {
  121. // Make other three quads zero-sized
  122. if(quadIdxInBlock != 0)
  123. cocPixelSize = 0;
  124. }
  125. else
  126. color *= 0.25f;
  127. // Offset so we render both near and far fields in the same texture but with an offset
  128. float vertOffset = sceneDepth < gFocalPlaneDistance ? gLayerPixelOffset : 0;
  129. // Determine location of the vertex within the current quad
  130. uint vertexIdxInQuad = vid % 4;
  131. float2 localPos = float2(vertexIdxInQuad % 2, vertexIdxInQuad / 2);
  132. float2 screenPos = blockPos + (localPos - 0.5f) * cocPixelSize;
  133. float2 uvPos = (screenPos + float2(0, vertOffset)) * gInvOutputSize;
  134. float2 ndcPos = UVToNDC(uvPos);
  135. VStoFS output;
  136. output.position = float4(ndcPos, 0, 1);
  137. output.uv0 = input.uv0;
  138. output.color = color;
  139. #if DEPTH_OCCLUSION
  140. output.screenUV = screenPos * gInvInputSize;
  141. output.depth = sceneDepth;
  142. #endif
  143. return output;
  144. }
  145. Texture2D gBokehTex;
  146. SamplerState gBokehSampler;
  147. float4 fsmain(VStoFS input) : SV_Target0
  148. {
  149. float4 output = gBokehTex.Sample(gBokehSampler, input.uv0).r * input.color;
  150. #if DEPTH_OCCLUSION
  151. float spriteDepth = input.depth;
  152. float sceneDepth = gInputTex.SampleLevel(gInputSampler, input.screenUV, 0).a;
  153. float diff = spriteDepth - sceneDepth;
  154. float fade = 1.0f - saturate(diff * gInvDepthRange);
  155. output *= fade;
  156. #endif
  157. return output;
  158. }
  159. };
  160. };