2
0

BsImageBasedLighting.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsImageBasedLighting.h"
  4. #include "BsMaterial.h"
  5. #include "BsShader.h"
  6. #include "BsGpuBuffer.h"
  7. #include "BsReflectionProbe.h"
  8. #include "BsLightProbeCache.h"
  9. #include "BsGpuParamsSet.h"
  10. #include "BsRenderTargets.h"
  11. #include "BsRenderBeast.h"
  12. #include "BsRendererUtility.h"
  13. namespace bs { namespace ct
  14. {
  15. static const UINT32 BUFFER_INCREMENT = 16 * sizeof(ReflProbeData);
  16. ReflProbeParamsParamDef gReflProbeParamsParamDef;
  17. TiledImageBasedLightingParamDef gTiledImageBasedLightingParamDef;
  18. GPUReflProbeData::GPUReflProbeData()
  19. :mNumProbes(0)
  20. { }
  21. void GPUReflProbeData::setProbes(const Vector<ReflProbeData>& probeData, UINT32 numProbes)
  22. {
  23. mNumProbes = numProbes;
  24. UINT32 size = numProbes * sizeof(ReflProbeData);
  25. UINT32 curBufferSize;
  26. if (mProbeBuffer != nullptr)
  27. curBufferSize = mProbeBuffer->getSize();
  28. else
  29. curBufferSize = 0;
  30. if (size > curBufferSize || curBufferSize == 0)
  31. {
  32. // Allocate at least one block even if no probes, to avoid issues with null buffers
  33. UINT32 bufferSize = std::max(1, Math::ceilToInt(size / (float)BUFFER_INCREMENT)) * BUFFER_INCREMENT;
  34. GPU_BUFFER_DESC bufferDesc;
  35. bufferDesc.type = GBT_STRUCTURED;
  36. bufferDesc.elementCount = bufferSize / sizeof(ReflProbeData);
  37. bufferDesc.elementSize = sizeof(ReflProbeData);
  38. bufferDesc.format = BF_UNKNOWN;
  39. mProbeBuffer = GpuBuffer::create(bufferDesc);
  40. }
  41. if (size > 0)
  42. mProbeBuffer->writeData(0, size, probeData.data(), BWT_DISCARD);
  43. }
  44. RendererReflectionProbe::RendererReflectionProbe(ReflectionProbe* probe)
  45. :probe(probe)
  46. {
  47. arrayIdx = -1;
  48. texture = nullptr;
  49. customTexture = probe->getCustomTexture() != nullptr;
  50. textureDirty = LightProbeCache::instance().isRadianceDirty(probe->getUUID());
  51. arrayDirty = true;
  52. errorFlagged = false;
  53. }
  54. void RendererReflectionProbe::getParameters(ReflProbeData& output) const
  55. {
  56. output.type = probe->getType() == ReflectionProbeType::Sphere ? 0
  57. : probe->getType() == ReflectionProbeType::Box ? 1 : 2;
  58. output.position = probe->getPosition();
  59. output.boxExtents = probe->getExtents();
  60. if (probe->getType() == ReflectionProbeType::Sphere)
  61. output.radius = probe->getRadius();
  62. else
  63. output.radius = output.boxExtents.length();
  64. output.transitionDistance = probe->getTransitionDistance();
  65. output.cubemapIdx = arrayIdx;
  66. output.invBoxTransform.setInverseTRS(output.position, probe->getRotation(), output.boxExtents);
  67. }
  68. // Note: Using larger tiles than in tiled deferred lighting since we use AABB for intersections, which is more
  69. // expensive to compute than frustums. This way we amortize the cost even though other parts of the shader might suffer
  70. // due to increased thread group load.
  71. const UINT32 TiledDeferredImageBasedLighting::TILE_SIZE = 32;
  72. TiledDeferredImageBasedLighting::TiledDeferredImageBasedLighting(const SPtr<Material>& material,
  73. const SPtr<GpuParamsSet>& paramsSet, UINT32 sampleCount)
  74. :mSampleCount(sampleCount), mMaterial(material), mParamsSet(paramsSet)
  75. {
  76. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  77. auto& texParams = mMaterial->getShader()->getTextureParams();
  78. for (auto& entry : texParams)
  79. {
  80. if (entry.second.rendererSemantic == RPS_GBufferA)
  81. params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferA);
  82. else if (entry.second.rendererSemantic == RPS_GBufferB)
  83. params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferB);
  84. else if (entry.second.rendererSemantic == RPS_GBufferC)
  85. params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferC);
  86. else if (entry.second.rendererSemantic == RPS_GBufferDepth)
  87. params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferDepth);
  88. }
  89. if (mSampleCount > 1)
  90. {
  91. params->getBufferParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorBufferParam);
  92. params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
  93. }
  94. else
  95. {
  96. params->getTextureParam(GPT_COMPUTE_PROGRAM, "gInColor", mInColorTextureParam);
  97. params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
  98. }
  99. mParamBuffer = gTiledImageBasedLightingParamDef.createBuffer();
  100. mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
  101. // Sky
  102. params->getTextureParam(GPT_COMPUTE_PROGRAM, "gSkyReflectionTex", mSkyReflectionsParam);
  103. params->getTextureParam(GPT_COMPUTE_PROGRAM, "gSkyIrradianceTex", mSkyIrradianceParam);
  104. // Reflections
  105. params->getTextureParam(GPT_COMPUTE_PROGRAM, "gReflProbeCubemaps", mReflectionProbeCubemapsParam);
  106. params->getTextureParam(GPT_COMPUTE_PROGRAM, "gPreintegratedEnvBRDF", mPreintegratedEnvBRDFParam);
  107. params->getBufferParam(GPT_COMPUTE_PROGRAM, "gReflectionProbes", mReflectionProbesParam);
  108. mReflectionsParamBuffer = gReflProbeParamsParamDef.createBuffer();
  109. mParamsSet->setParamBlockBuffer("ReflProbeParams", mReflectionsParamBuffer);
  110. SAMPLER_STATE_DESC reflSamplerDesc;
  111. reflSamplerDesc.magFilter = FO_LINEAR;
  112. reflSamplerDesc.minFilter = FO_LINEAR;
  113. reflSamplerDesc.mipFilter = FO_LINEAR;
  114. mReflectionSamplerState = SamplerState::create(reflSamplerDesc);
  115. params->setSamplerState(GPT_COMPUTE_PROGRAM, "gSkyReflectionSamp", mReflectionSamplerState);
  116. params->setSamplerState(GPT_COMPUTE_PROGRAM, "gReflProbeSamp", mReflectionSamplerState);
  117. }
  118. void TiledDeferredImageBasedLighting::execute(const SPtr<RenderTargets>& renderTargets,
  119. const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<Texture>& preintegratedGF)
  120. {
  121. Vector2I framebufferSize;
  122. framebufferSize[0] = renderTargets->getWidth();
  123. framebufferSize[1] = renderTargets->getHeight();
  124. gTiledImageBasedLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
  125. mParamBuffer->flushToGPU();
  126. mReflectionsParamBuffer->flushToGPU();
  127. mGBufferA.set(renderTargets->getGBufferA());
  128. mGBufferB.set(renderTargets->getGBufferB());
  129. mGBufferC.set(renderTargets->getGBufferC());
  130. mGBufferDepth.set(renderTargets->getSceneDepth());
  131. mPreintegratedEnvBRDFParam.set(preintegratedGF);
  132. mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
  133. if (mSampleCount > 1)
  134. {
  135. mInColorBufferParam.set(renderTargets->getLightAccumulationBuffer());
  136. mOutputBufferParam.set(renderTargets->getSceneColorBuffer());
  137. }
  138. else
  139. {
  140. mInColorTextureParam.set(renderTargets->getLightAccumulation());
  141. mOutputTextureParam.set(renderTargets->getSceneColor());
  142. }
  143. UINT32 width = renderTargets->getWidth();
  144. UINT32 height = renderTargets->getHeight();
  145. UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
  146. UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
  147. gRendererUtility().setComputePass(mMaterial, 0);
  148. gRendererUtility().setPassParams(mParamsSet);
  149. RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
  150. }
  151. void TiledDeferredImageBasedLighting::setReflectionProbes(const GPUReflProbeData& probeData,
  152. const SPtr<Texture>& reflectionCubemaps)
  153. {
  154. mReflectionProbesParam.set(probeData.getProbeBuffer());
  155. mReflectionProbeCubemapsParam.set(reflectionCubemaps);
  156. gReflProbeParamsParamDef.gNumProbes.set(mReflectionsParamBuffer, probeData.getNumProbes());
  157. UINT32 numMips = 0;
  158. if (reflectionCubemaps != nullptr)
  159. numMips = reflectionCubemaps->getProperties().getNumMipmaps() + 1;
  160. gReflProbeParamsParamDef.gReflCubemapNumMips.set(mReflectionsParamBuffer, numMips);
  161. }
  162. void TiledDeferredImageBasedLighting::setSky(const SPtr<Texture>& skyReflections, const SPtr<Texture>& skyIrradiance,
  163. float brightness)
  164. {
  165. mSkyReflectionsParam.set(skyReflections);
  166. mSkyIrradianceParam.set(skyIrradiance);
  167. UINT32 skyReflectionsAvailable = 0;
  168. UINT32 numMips = 0;
  169. if (skyReflections != nullptr)
  170. {
  171. numMips = skyReflections->getProperties().getNumMipmaps() + 1;
  172. skyReflectionsAvailable = 1;
  173. }
  174. gReflProbeParamsParamDef.gSkyCubemapNumMips.set(mReflectionsParamBuffer, numMips);
  175. gReflProbeParamsParamDef.gSkyCubemapAvailable.set(mReflectionsParamBuffer, skyReflectionsAvailable);
  176. gReflProbeParamsParamDef.gSkyBrightness.set(mReflectionsParamBuffer, brightness);
  177. }
  178. // Reverse bits functions used for Hammersley sequence
  179. float reverseBits(UINT32 bits)
  180. {
  181. bits = (bits << 16u) | (bits >> 16u);
  182. bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
  183. bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
  184. bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
  185. bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
  186. return (float)(double(bits) / (double)0x100000000LL);
  187. }
  188. void hammersleySequence(UINT32 i, UINT32 count, float& e0, float& e1)
  189. {
  190. e0 = i / (float)count;
  191. e1 = reverseBits(i);
  192. }
  193. Vector3 sphericalToCartesian(float cosTheta, float sinTheta, float phi)
  194. {
  195. Vector3 output;
  196. output.x = sinTheta * cos(phi);
  197. output.y = sinTheta * sin(phi);
  198. output.z = cosTheta;
  199. return output;
  200. }
  201. // Generates an angle in spherical coordinates, importance sampled for the specified roughness based on some uniformly
  202. // distributed random variables in range [0, 1].
  203. void importanceSampleGGX(float e0, float e1, float roughness4, float& cosTheta, float& phi)
  204. {
  205. // See GGXImportanceSample.nb for derivation (essentially, take base GGX, normalize it, generate PDF, split PDF into
  206. // marginal probability for theta and conditional probability for phi. Plug those into the CDF, invert it.)
  207. cosTheta = sqrt((1.0f - e0) / (1.0f + (roughness4 - 1.0f) * e0));
  208. phi = 2.0f * Math::PI * e1;
  209. }
  210. float calcMicrofacetShadowingSmithGGX(float roughness4, float NoV, float NoL)
  211. {
  212. // Note: See lighting shader for derivation. Includes microfacet BRDF divisor.
  213. float g1V = NoV + sqrt(NoV * (NoV - NoV * roughness4) + roughness4);
  214. float g1L = NoL + sqrt(NoL * (NoL - NoL * roughness4) + roughness4);
  215. return 1.0f / (g1V * g1L);
  216. }
  217. SPtr<Texture> TiledDeferredImageBasedLighting::generatePreintegratedEnvBRDF()
  218. {
  219. TEXTURE_DESC desc;
  220. desc.type = TEX_TYPE_2D;
  221. desc.format = PF_FLOAT16_RG;
  222. desc.width = 128;
  223. desc.height = 32;
  224. SPtr<Texture> texture = Texture::create(desc);
  225. PixelData pixelData = texture->lock(GBL_WRITE_ONLY_DISCARD);
  226. for (UINT32 y = 0; y < desc.height; y++)
  227. {
  228. float roughness = (float)(y + 0.5f) / desc.height;
  229. float m = roughness * roughness;
  230. float m2 = m*m;
  231. for (UINT32 x = 0; x < desc.width; x++)
  232. {
  233. float NoV = (float)(x + 0.5f) / desc.width;
  234. Vector3 V;
  235. V.x = sqrt(1.0f - NoV * NoV); // sine
  236. V.y = 0.0f;
  237. V.z = NoV;
  238. // These are the two integrals resulting from the second part of the split-sum approximation. Described in
  239. // Epic's 2013 paper:
  240. // http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
  241. float scale = 0.0f;
  242. float offset = 0.0f;
  243. // We use the same importance sampling function we use for reflection cube importance sampling, only we
  244. // sample G and F, instead of D factors of the microfactet BRDF. See GGXImportanceSample.nb for derivation.
  245. constexpr UINT32 NumSamples = 128;
  246. for (UINT32 i = 0; i < NumSamples; i++)
  247. {
  248. float e0, e1;
  249. hammersleySequence(i, NumSamples, e0, e1);
  250. float cosTheta, phi;
  251. importanceSampleGGX(e0, e1, m2, cosTheta, phi);
  252. float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
  253. Vector3 H = sphericalToCartesian(cosTheta, sinTheta, phi);
  254. Vector3 L = 2.0f * Vector3::dot(V, H) * H - V;
  255. float VoH = std::max(Vector3::dot(V, H), 0.0f);
  256. float NoL = std::max(L.z, 0.0f); // N assumed (0, 0, 1)
  257. float NoH = std::max(H.z, 0.0f); // N assumed (0, 0, 1)
  258. // Set second part of the split sum integral is split into two parts:
  259. // F0*I[G * (1 - (1 - v.h)^5) * cos(theta)] + I[G * (1 - v.h)^5 * cos(theta)] (F0 * scale + bias)
  260. // We calculate the fresnel scale (1 - (1 - v.h)^5) and bias ((1 - v.h)^5) parts
  261. float fc = pow(1.0f - VoH, 5.0f);
  262. float fresnelScale = 1.0f - fc;
  263. float fresnelOffset = fc;
  264. // We calculate the G part
  265. float G = calcMicrofacetShadowingSmithGGX(m2, NoV, NoL);
  266. // When we factor out G and F, then divide D by PDF, this is what's left
  267. // Note: This is based on PDF: D * NoH / (4 * VoH). (4 * VoH) factor comes from the Jacobian of the
  268. // transformation from half vector to light vector
  269. float pdfFactor = 4.0f * VoH / NoH;
  270. if (NoL > 0.0f)
  271. {
  272. scale += NoL * pdfFactor * G * fresnelScale;
  273. offset += NoL * pdfFactor * G * fresnelOffset;
  274. }
  275. }
  276. scale /= NumSamples;
  277. offset /= NumSamples;
  278. Color color;
  279. color.r = Math::clamp01(scale);
  280. color.g = Math::clamp01(offset);
  281. pixelData.setColorAt(color, x, y);
  282. }
  283. }
  284. texture->unlock();
  285. return texture;
  286. }
  287. template<int MSAA_COUNT, bool CapturingReflections>
  288. TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::TTiledDeferredImageBasedLightingMat()
  289. :mInternal(mMaterial, mParamsSet, MSAA_COUNT)
  290. {
  291. }
  292. template<int MSAA_COUNT, bool CapturingReflections>
  293. void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::_initDefines(ShaderDefines& defines)
  294. {
  295. defines.set("TILE_SIZE", TiledDeferredImageBasedLighting::TILE_SIZE);
  296. defines.set("MSAA_COUNT", MSAA_COUNT);
  297. defines.set("CAPTURING_REFLECTIONS", CapturingReflections);
  298. }
  299. template<int MSAA_COUNT, bool CapturingReflections>
  300. void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::execute(const SPtr<RenderTargets>& gbuffer,
  301. const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<Texture>& preintegratedGF)
  302. {
  303. mInternal.execute(gbuffer, perCamera, preintegratedGF);
  304. }
  305. template<int MSAA_COUNT, bool CapturingReflections>
  306. void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::setReflectionProbes(
  307. const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps)
  308. {
  309. mInternal.setReflectionProbes(probeData, reflectionCubemaps);
  310. }
  311. template<int MSAA_COUNT, bool CapturingReflections>
  312. void TTiledDeferredImageBasedLightingMat<MSAA_COUNT, CapturingReflections>::setSky(const SPtr<Texture>& skyReflections,
  313. const SPtr<Texture>& skyIrradiance, float brightness)
  314. {
  315. mInternal.setSky(skyReflections, skyIrradiance, brightness);
  316. }
  317. TiledDeferredImageBasedLightingMaterials::TiledDeferredImageBasedLightingMaterials()
  318. {
  319. mInstances[0] = bs_new<TTiledDeferredImageBasedLightingMat<1, false>>();
  320. mInstances[1] = bs_new<TTiledDeferredImageBasedLightingMat<2, false>>();
  321. mInstances[2] = bs_new<TTiledDeferredImageBasedLightingMat<4, false>>();
  322. mInstances[3] = bs_new<TTiledDeferredImageBasedLightingMat<8, false>>();
  323. mInstances[4] = bs_new<TTiledDeferredImageBasedLightingMat<1, true>>();
  324. mInstances[5] = bs_new<TTiledDeferredImageBasedLightingMat<2, true>>();
  325. mInstances[6] = bs_new<TTiledDeferredImageBasedLightingMat<4, true>>();
  326. mInstances[7] = bs_new<TTiledDeferredImageBasedLightingMat<8, true>>();
  327. }
  328. TiledDeferredImageBasedLightingMaterials::~TiledDeferredImageBasedLightingMaterials()
  329. {
  330. for (UINT32 i = 0; i < 8; i++)
  331. bs_delete(mInstances[i]);
  332. }
  333. ITiledDeferredImageBasedLightingMat* TiledDeferredImageBasedLightingMaterials::get(UINT32 msaa, bool capturingReflections)
  334. {
  335. if (!capturingReflections)
  336. {
  337. if (msaa == 1)
  338. return mInstances[0];
  339. else if (msaa == 2)
  340. return mInstances[1];
  341. else if (msaa == 4)
  342. return mInstances[2];
  343. else
  344. return mInstances[3];
  345. }
  346. else
  347. {
  348. if (msaa == 1)
  349. return mInstances[4];
  350. else if (msaa == 2)
  351. return mInstances[5];
  352. else if (msaa == 4)
  353. return mInstances[6];
  354. else
  355. return mInstances[7];
  356. }
  357. }
  358. }}