BsLightProbeVolume.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Renderer/BsLightProbeVolume.h"
  4. #include "RTTI/BsLightProbeVolumeRTTI.h"
  5. #include "Allocators/BsFrameAlloc.h"
  6. #include "Renderer/BsRenderer.h"
  7. #include "Renderer/BsLight.h"
  8. #include "Image/BsTexture.h"
  9. #include "Renderer/BsIBLUtility.h"
  10. #include "Scene/BsSceneObject.h"
  11. namespace bs
  12. {
  13. LightProbeVolume::LightProbeVolume()
  14. : mVolume(AABox::UNIT_BOX), mCellCount { 1, 1, 1 }
  15. { }
  16. LightProbeVolume::LightProbeVolume(const AABox& volume, const Vector3I& cellCount)
  17. :mVolume(volume), mCellCount(cellCount)
  18. {
  19. reset();
  20. }
  21. LightProbeVolume::~LightProbeVolume()
  22. {
  23. if (mRendererTask)
  24. mRendererTask->cancel();
  25. }
  26. UINT32 LightProbeVolume::addProbe(const Vector3& position)
  27. {
  28. UINT32 handle = mNextProbeId++;
  29. mProbes[handle] = ProbeInfo(LightProbeFlags::Clean, position);
  30. _markCoreDirty();
  31. return handle;
  32. }
  33. void LightProbeVolume::removeProbe(UINT32 handle)
  34. {
  35. auto iterFind = mProbes.find(handle);
  36. if (iterFind != mProbes.end() && mProbes.size() > 4)
  37. {
  38. iterFind->second.flags = LightProbeFlags::Removed;
  39. _markCoreDirty();
  40. }
  41. }
  42. void LightProbeVolume::setProbePosition(UINT32 handle, const Vector3& position)
  43. {
  44. auto iterFind = mProbes.find(handle);
  45. if (iterFind != mProbes.end())
  46. {
  47. iterFind->second.position = position;
  48. _markCoreDirty();
  49. }
  50. }
  51. Vector3 LightProbeVolume::getProbePosition(UINT32 handle) const
  52. {
  53. auto iterFind = mProbes.find(handle);
  54. if (iterFind != mProbes.end())
  55. return iterFind->second.position;
  56. return Vector3::ZERO;
  57. }
  58. Vector<LightProbeInfo> LightProbeVolume::getProbes() const
  59. {
  60. Vector<LightProbeInfo> output;
  61. for(auto& entry : mProbes)
  62. {
  63. if (entry.second.flags == LightProbeFlags::Removed || entry.second.flags == LightProbeFlags::Empty)
  64. continue;
  65. LightProbeInfo info;
  66. info.position = entry.second.position;
  67. info.handle = entry.first;
  68. info.shCoefficients = entry.second.coefficients;
  69. output.push_back(info);
  70. }
  71. return output;
  72. }
  73. void LightProbeVolume::resize(const AABox& volume, const Vector3I& cellCount)
  74. {
  75. UINT32 numProbesX = std::max(1, mCellCount.x) + 1;
  76. UINT32 numProbesY = std::max(1, mCellCount.y) + 1;
  77. UINT32 numProbesZ = std::max(1, mCellCount.z) + 1;
  78. Vector3 size = mVolume.getSize();
  79. for(UINT32 z = 0; z < numProbesZ; ++z)
  80. {
  81. for(UINT32 y = 0; y < numProbesY; ++y)
  82. {
  83. for(UINT32 x = 0; x < numProbesX; ++x)
  84. {
  85. Vector3 position = mVolume.getMin();
  86. position.x += size.x * (x / (float)numProbesX);
  87. position.y += size.y * (y / (float)numProbesY);
  88. position.z += size.z * (z / (float)numProbesZ);
  89. if (mVolume.contains(position))
  90. continue;
  91. addProbe(position);
  92. }
  93. }
  94. }
  95. mVolume = volume;
  96. mCellCount = cellCount;
  97. _markCoreDirty();
  98. }
  99. void LightProbeVolume::reset()
  100. {
  101. UINT32 numProbesX = std::max(1, mCellCount.x) + 1;
  102. UINT32 numProbesY = std::max(1, mCellCount.y) + 1;
  103. UINT32 numProbesZ = std::max(1, mCellCount.z) + 1;
  104. UINT32 numProbes = numProbesX * numProbesY * numProbesZ;
  105. // Make sure there are adequate number of probes to fill the volume
  106. while((UINT32)mProbes.size() < numProbes)
  107. addProbe(Vector3::ZERO);
  108. UINT32 idx = 0;
  109. UINT32 rowPitch = numProbesX;
  110. UINT32 slicePitch = numProbesX * numProbesY;
  111. Vector3 size = mVolume.getSize();
  112. auto iter = mProbes.begin();
  113. while (iter != mProbes.end())
  114. {
  115. UINT32 x = idx % numProbesX;
  116. UINT32 y = (idx / rowPitch) % numProbesY;
  117. UINT32 z = (idx / slicePitch);
  118. Vector3 position = mVolume.getMin();
  119. position.x += size.x * (x / (float)(numProbesX - 1));
  120. position.y += size.y * (y / (float)(numProbesY - 1));
  121. position.z += size.z * (z / (float)(numProbesZ - 1));
  122. iter->second.position = position;
  123. iter->second.flags = LightProbeFlags::Clean;
  124. ++idx;
  125. ++iter;
  126. if (idx >= numProbes)
  127. break;
  128. }
  129. // Set remaining probes to removed state
  130. while(iter != mProbes.end())
  131. {
  132. iter->second.flags = LightProbeFlags::Removed;
  133. ++iter;
  134. }
  135. _markCoreDirty();
  136. }
  137. void LightProbeVolume::clip()
  138. {
  139. for (auto& entry : mProbes)
  140. {
  141. if (!mVolume.contains(entry.second.position))
  142. entry.second.flags = LightProbeFlags::Removed;
  143. }
  144. _markCoreDirty();
  145. }
  146. void LightProbeVolume::renderProbe(UINT32 handle)
  147. {
  148. auto iterFind = mProbes.find(handle);
  149. if (iterFind != mProbes.end())
  150. {
  151. if (iterFind->second.flags == LightProbeFlags::Clean)
  152. {
  153. iterFind->second.flags = LightProbeFlags::Dirty;
  154. _markCoreDirty();
  155. runRenderProbeTask();
  156. }
  157. }
  158. }
  159. void LightProbeVolume::renderProbes()
  160. {
  161. bool anyModified = false;
  162. for(auto& entry : mProbes)
  163. {
  164. if (entry.second.flags == LightProbeFlags::Clean)
  165. {
  166. entry.second.flags = LightProbeFlags::Dirty;
  167. anyModified = true;
  168. }
  169. }
  170. if (anyModified)
  171. {
  172. _markCoreDirty();
  173. runRenderProbeTask();
  174. }
  175. }
  176. void LightProbeVolume::runRenderProbeTask()
  177. {
  178. // If a task is already running cancel it
  179. // Note: If the task is just about to start processing, cancelling it will skip the update this frame
  180. // (which might be fine if we just changed positions of dirty probes it was about to update, but it might also
  181. // waste a frame if those positions needed to be updated anyway). For now I'm ignoring it as it seems like a rare
  182. // enough situation, plus it's one that will only happen during development time.
  183. if (mRendererTask)
  184. mRendererTask->cancel();
  185. auto renderComplete = [this]()
  186. {
  187. mRendererTask = nullptr;
  188. };
  189. SPtr<ct::LightProbeVolume> coreProbeVolume = getCore();
  190. auto renderProbes = [coreProbeVolume]()
  191. {
  192. return coreProbeVolume->renderProbes(3);
  193. };
  194. mRendererTask = ct::RendererTask::create("RenderLightProbes", renderProbes);
  195. mRendererTask->onComplete.connect(renderComplete);
  196. ct::gRenderer()->addTask(mRendererTask);
  197. }
  198. void LightProbeVolume::updateCoefficients()
  199. {
  200. // Ensure all light probe coefficients are generated
  201. if (mRendererTask)
  202. mRendererTask->wait();
  203. ct::LightProbeVolume* coreVolume = getCore().get();
  204. Vector<LightProbeCoefficientInfo> coeffInfo;
  205. auto getSaveData = [coreVolume, &coeffInfo]()
  206. {
  207. coreVolume->getProbeCoefficients(coeffInfo);
  208. };
  209. gCoreThread().queueCommand(getSaveData);
  210. gCoreThread().submit(true);
  211. for(auto& entry : coeffInfo)
  212. {
  213. auto iterFind = mProbes.find(entry.handle);
  214. if (iterFind == mProbes.end())
  215. continue;
  216. iterFind->second.coefficients = entry.coefficients;
  217. }
  218. }
  219. SPtr<ct::LightProbeVolume> LightProbeVolume::getCore() const
  220. {
  221. return std::static_pointer_cast<ct::LightProbeVolume>(mCoreSpecific);
  222. }
  223. SPtr<LightProbeVolume> LightProbeVolume::create(const AABox& volume, const Vector3I& cellCount)
  224. {
  225. LightProbeVolume* probeVolume = new (bs_alloc<LightProbeVolume>()) LightProbeVolume(volume, cellCount);
  226. SPtr<LightProbeVolume> probeVolumePtr = bs_core_ptr<LightProbeVolume>(probeVolume);
  227. probeVolumePtr->_setThisPtr(probeVolumePtr);
  228. probeVolumePtr->initialize();
  229. return probeVolumePtr;
  230. }
  231. SPtr<LightProbeVolume> LightProbeVolume::createEmpty()
  232. {
  233. LightProbeVolume* probeVolume = new (bs_alloc<LightProbeVolume>()) LightProbeVolume();
  234. SPtr<LightProbeVolume> probleVolumePtr = bs_core_ptr<LightProbeVolume>(probeVolume);
  235. probleVolumePtr->_setThisPtr(probleVolumePtr);
  236. return probleVolumePtr;
  237. }
  238. SPtr<ct::CoreObject> LightProbeVolume::createCore() const
  239. {
  240. ct::LightProbeVolume* handler = new (bs_alloc<ct::LightProbeVolume>()) ct::LightProbeVolume(mProbes);
  241. SPtr<ct::LightProbeVolume> handlerPtr = bs_shared_ptr<ct::LightProbeVolume>(handler);
  242. handlerPtr->_setThisPtr(handlerPtr);
  243. return handlerPtr;
  244. }
  245. CoreSyncData LightProbeVolume::syncToCore(FrameAlloc* allocator)
  246. {
  247. UINT32 size = 0;
  248. UINT8* buffer = nullptr;
  249. bs_frame_mark();
  250. {
  251. FrameVector<std::pair<UINT32, ProbeInfo>> dirtyProbes;
  252. FrameVector<UINT32> removedProbes;
  253. for (auto& probe : mProbes)
  254. {
  255. if (probe.second.flags == LightProbeFlags::Dirty)
  256. {
  257. dirtyProbes.push_back(std::make_pair(probe.first, probe.second));
  258. probe.second.flags = LightProbeFlags::Clean;
  259. }
  260. else if (probe.second.flags == LightProbeFlags::Removed)
  261. {
  262. removedProbes.push_back(probe.first);
  263. probe.second.flags = LightProbeFlags::Empty;
  264. }
  265. }
  266. for (auto& probe : removedProbes)
  267. mProbes.erase(probe);
  268. UINT32 numDirtyProbes = (UINT32)dirtyProbes.size();
  269. UINT32 numRemovedProbes = (UINT32)removedProbes.size();
  270. size += getActorSyncDataSize();
  271. size += rttiGetElemSize(numDirtyProbes);
  272. size += rttiGetElemSize(numRemovedProbes);
  273. size += (sizeof(UINT32) + sizeof(Vector3) + sizeof(LightProbeFlags)) * numDirtyProbes;
  274. size += sizeof(UINT32) * numRemovedProbes;
  275. buffer = allocator->alloc(size);
  276. char* dataPtr = (char*)buffer;
  277. dataPtr = syncActorTo(dataPtr);
  278. dataPtr = rttiWriteElem(numDirtyProbes, dataPtr);
  279. dataPtr = rttiWriteElem(numRemovedProbes, dataPtr);
  280. for (auto& entry : dirtyProbes)
  281. {
  282. dataPtr = rttiWriteElem(entry.first, dataPtr);
  283. dataPtr = rttiWriteElem(entry.second.position, dataPtr);
  284. dataPtr = rttiWriteElem(entry.second.flags, dataPtr);
  285. }
  286. for(auto& entry : removedProbes)
  287. dataPtr = rttiWriteElem(entry, dataPtr);
  288. }
  289. bs_frame_clear();
  290. return CoreSyncData(buffer, size);
  291. }
  292. void LightProbeVolume::_markCoreDirty(ActorDirtyFlag dirtyFlag)
  293. {
  294. markCoreDirty((UINT32)dirtyFlag);
  295. }
  296. RTTITypeBase* LightProbeVolume::getRTTIStatic()
  297. {
  298. return LightProbeVolumeRTTI::instance();
  299. }
  300. RTTITypeBase* LightProbeVolume::getRTTI() const
  301. {
  302. return LightProbeVolume::getRTTIStatic();
  303. }
  304. namespace ct
  305. {
  306. LightProbeVolume::LightProbeVolume(const UnorderedMap<UINT32, bs::LightProbeVolume::ProbeInfo>& probes)
  307. {
  308. mInitCoefficients.resize(probes.size());
  309. mProbePositions.resize(probes.size());
  310. mProbeInfos.resize(probes.size());
  311. UINT32 probeIdx = 0;
  312. for(auto& entry : probes)
  313. {
  314. mProbeMap[entry.first] = probeIdx;
  315. mProbePositions[probeIdx] = entry.second.position;
  316. LightProbeInfo probeInfo;
  317. probeInfo.flags = LightProbeFlags::Dirty;
  318. probeInfo.bufferIdx = probeIdx;
  319. probeInfo.handle = entry.first;
  320. mProbeInfos[probeIdx] = probeInfo;
  321. mInitCoefficients[probeIdx] = entry.second.coefficients;
  322. probeIdx++;
  323. }
  324. }
  325. LightProbeVolume::~LightProbeVolume()
  326. {
  327. gRenderer()->notifyLightProbeVolumeRemoved(this);
  328. }
  329. void LightProbeVolume::initialize()
  330. {
  331. // Set SH coefficients loaded from the file
  332. UINT32 numCoefficients = (UINT32)mInitCoefficients.size();
  333. assert(mInitCoefficients.size() == mProbeMap.size());
  334. resizeCoefficientTexture(std::max(32U, numCoefficients));
  335. SPtr<PixelData> coeffData = mCoefficients->getProperties().allocBuffer(0, 0);
  336. UINT32 probesPerRow = coeffData->getWidth() / 9;
  337. UINT32 probeIdx = 0;
  338. for(UINT32 y = 0; y < coeffData->getHeight(); ++y)
  339. {
  340. for(UINT32 x = 0; x < probesPerRow; ++x)
  341. {
  342. if(probeIdx >= numCoefficients)
  343. break;
  344. for(UINT32 i = 0; i < 9; i++)
  345. {
  346. Color value;
  347. value.r = mInitCoefficients[probeIdx].coeffsR[i];
  348. value.g = mInitCoefficients[probeIdx].coeffsG[i];
  349. value.b = mInitCoefficients[probeIdx].coeffsB[i];
  350. coeffData->setColorAt(value, x * 9, y);
  351. }
  352. probeIdx++;
  353. }
  354. }
  355. mCoefficients->writeData(*coeffData, 0, 0, true);
  356. mInitCoefficients.clear();
  357. gRenderer()->notifyLightProbeVolumeAdded(this);
  358. CoreObject::initialize();
  359. }
  360. bool LightProbeVolume::renderProbes(UINT32 maxProbes)
  361. {
  362. // Probe map only contains active probes
  363. UINT32 numUsedProbes = (UINT32)mProbeMap.size();
  364. if(numUsedProbes > mCoeffBufferSize)
  365. resizeCoefficientTexture(std::max(32U, numUsedProbes * 2));
  366. UINT32 numProbeUpdates = 0;
  367. for (; mFirstDirtyProbe < (UINT32)mProbeInfos.size(); ++mFirstDirtyProbe)
  368. {
  369. LightProbeInfo& probeInfo = mProbeInfos[mFirstDirtyProbe];
  370. if(probeInfo.flags == LightProbeFlags::Dirty)
  371. {
  372. TEXTURE_DESC cubemapDesc;
  373. cubemapDesc.type = TEX_TYPE_CUBE_MAP;
  374. cubemapDesc.format = PF_RGBA16F;
  375. cubemapDesc.width = 256; // Note: Test different sizes and their effect on quality
  376. cubemapDesc.height = 256;
  377. cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
  378. SPtr<Texture> cubemap = Texture::create(cubemapDesc);
  379. Vector3 localPos = mProbePositions[mFirstDirtyProbe];
  380. const Transform& tfrm = getTransform();
  381. const Vector3& position = tfrm.getPosition();
  382. const Quaternion& rotation = tfrm.getRotation();
  383. Vector3 transformedPos = rotation.rotate(localPos) + position;
  384. gRenderer()->captureSceneCubeMap(cubemap, transformedPos, CaptureSettings());
  385. gIBLUtility().filterCubemapForIrradiance(cubemap, mCoefficients, probeInfo.bufferIdx);
  386. probeInfo.flags = LightProbeFlags::Clean;
  387. numProbeUpdates++;
  388. }
  389. if (maxProbes != 0 && numProbeUpdates >= maxProbes)
  390. break;
  391. }
  392. gRenderer()->notifyLightProbeVolumeUpdated(this);
  393. return mFirstDirtyProbe == (UINT32)mProbeInfos.size();
  394. }
  395. void LightProbeVolume::syncToCore(const CoreSyncData& data)
  396. {
  397. char* dataPtr = (char*)data.getBuffer();
  398. bool oldIsActive = mActive;
  399. dataPtr = syncActorFrom(dataPtr);
  400. UINT32 numDirtyProbes, numRemovedProbes;
  401. dataPtr = rttiReadElem(numDirtyProbes, dataPtr);
  402. dataPtr = rttiReadElem(numRemovedProbes, dataPtr);
  403. for (UINT32 i = 0; i < numDirtyProbes; ++i)
  404. {
  405. UINT32 handle;
  406. dataPtr = rttiReadElem(handle, dataPtr);
  407. Vector3 position;
  408. dataPtr = rttiReadElem(position, dataPtr);
  409. LightProbeFlags flags;
  410. dataPtr = rttiReadElem(flags, dataPtr);
  411. auto iterFind = mProbeMap.find(handle);
  412. if(iterFind != mProbeMap.end())
  413. {
  414. // Update existing probe information
  415. UINT32 compactIdx = iterFind->second;
  416. mProbeInfos[compactIdx].flags = LightProbeFlags::Dirty;
  417. mProbePositions[compactIdx] = position;
  418. mFirstDirtyProbe = std::min(compactIdx, mFirstDirtyProbe);
  419. }
  420. else // Add a new probe
  421. {
  422. // Empty slots always start at a specific index because we always move them to the back of the array
  423. UINT32 emptyProbeStartIdx = (UINT32)mProbeMap.size();
  424. UINT32 numProbes = (UINT32)mProbeInfos.size();
  425. // Find an empty slot to place the probe information at
  426. UINT32 compactIdx = -1;
  427. for(UINT32 j = emptyProbeStartIdx; j < numProbes; ++j)
  428. {
  429. if(mProbeInfos[j].flags == LightProbeFlags::Empty)
  430. {
  431. compactIdx = j;
  432. break;
  433. }
  434. }
  435. // Found an empty slot
  436. if (compactIdx == (UINT32)-1)
  437. {
  438. compactIdx = (UINT32)mProbeInfos.size();
  439. LightProbeInfo info;
  440. info.flags = LightProbeFlags::Dirty;
  441. info.bufferIdx = compactIdx;
  442. info.handle = handle;
  443. mProbeInfos.push_back(info);
  444. mProbePositions.push_back(position);
  445. }
  446. else // No empty slot, add a new one
  447. {
  448. LightProbeInfo& info = mProbeInfos[compactIdx];
  449. info.flags = LightProbeFlags::Dirty;
  450. info.handle = handle;
  451. mProbePositions[compactIdx] = position;
  452. }
  453. mProbeMap[handle] = compactIdx;
  454. mFirstDirtyProbe = std::min(compactIdx, mFirstDirtyProbe);
  455. }
  456. }
  457. // Mark slots for removed probes as empty, and move them back to the end of the array
  458. for (UINT32 i = 0; i < numRemovedProbes; ++i)
  459. {
  460. UINT32 idx;
  461. dataPtr = rttiReadElem(idx, dataPtr);
  462. auto iterFind = mProbeMap.find(idx);
  463. if(iterFind != mProbeMap.end())
  464. {
  465. UINT32 compactIdx = iterFind->second;
  466. LightProbeInfo& info = mProbeInfos[compactIdx];
  467. info.flags = LightProbeFlags::Empty;
  468. // Move the empty info to the back of the array so all non-empty probes are contiguous
  469. // Search from back to current index, and find first non-empty probe to switch switch
  470. UINT32 lastSearchIdx = (UINT32)mProbeInfos.size() - 1;
  471. while (lastSearchIdx >= (UINT32)compactIdx)
  472. {
  473. LightProbeFlags flags = mProbeInfos[lastSearchIdx].flags;
  474. if (flags != LightProbeFlags::Empty)
  475. {
  476. std::swap(mProbeInfos[i], mProbeInfos[lastSearchIdx]);
  477. std::swap(mProbePositions[i], mProbePositions[lastSearchIdx]);
  478. mProbeMap[mProbeInfos[lastSearchIdx].handle] = i;
  479. break;
  480. }
  481. lastSearchIdx--;
  482. }
  483. mProbeMap.erase(iterFind);
  484. }
  485. }
  486. if (oldIsActive != mActive)
  487. {
  488. if (mActive)
  489. gRenderer()->notifyLightProbeVolumeAdded(this);
  490. else
  491. gRenderer()->notifyLightProbeVolumeRemoved(this);
  492. }
  493. }
  494. void LightProbeVolume::getProbeCoefficients(Vector<LightProbeCoefficientInfo>& output) const
  495. {
  496. UINT32 numActiveProbes = (UINT32)mProbeMap.size();
  497. if (numActiveProbes == 0)
  498. return;
  499. output.resize(numActiveProbes);
  500. LightProbeSHCoefficients* coefficients = bs_stack_alloc<LightProbeSHCoefficients>(numActiveProbes);
  501. SPtr<PixelData> coeffData = mCoefficients->getProperties().allocBuffer(0, 0);
  502. mCoefficients->readData(*coeffData);
  503. UINT32 probesPerRow = coeffData->getWidth() / 9;
  504. UINT32 probeIdx = 0;
  505. for(UINT32 y = 0; y < coeffData->getHeight(); ++y)
  506. {
  507. for(UINT32 x = 0; x < probesPerRow; ++x)
  508. {
  509. if(probeIdx >= numActiveProbes)
  510. break;
  511. for(UINT32 i = 0; i < 9; i++)
  512. {
  513. Color value = coeffData->getColorAt(x * 9, y);
  514. coefficients[probeIdx].coeffsR[i] = value.r;
  515. coefficients[probeIdx].coeffsG[i] = value.g;
  516. coefficients[probeIdx].coeffsB[i] = value.b;
  517. }
  518. probeIdx++;
  519. }
  520. }
  521. for(UINT32 i = 0; i < numActiveProbes; ++i)
  522. {
  523. output[i].coefficients = coefficients[mProbeInfos[i].bufferIdx];
  524. output[i].handle = mProbeInfos[i].handle;
  525. }
  526. bs_stack_free(coefficients);
  527. }
  528. void LightProbeVolume::resizeCoefficientTexture(UINT32 count)
  529. {
  530. Vector2I texSize = IBLUtility::getSHCoeffTextureSize(count, 3);
  531. TEXTURE_DESC desc;
  532. desc.width = (UINT32)texSize.x;
  533. desc.height = (UINT32)texSize.y;
  534. desc.usage = TU_LOADSTORE | TU_RENDERTARGET;
  535. desc.format = PF_RGBA32F;
  536. SPtr<Texture> newTexture = Texture::create(desc);
  537. if (mCoefficients)
  538. mCoefficients->copy(newTexture);
  539. mCoefficients = newTexture;
  540. mCoeffBufferSize = count;
  541. }
  542. }}