BsReflectionProbe.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Renderer/BsReflectionProbe.h"
  4. #include "RTTI/BsReflectionProbeRTTI.h"
  5. #include "Scene/BsSceneObject.h"
  6. #include "Allocators/BsFrameAlloc.h"
  7. #include "Image/BsTexture.h"
  8. #include "Renderer/BsRenderer.h"
  9. #include "Utility/BsUUID.h"
  10. #include "Renderer/BsIBLUtility.h"
  11. namespace bs
  12. {
  13. ReflectionProbeBase::ReflectionProbeBase()
  14. : mPosition(BsZero), mRotation(BsIdentity), mScale(1.0f, 1.0f, 1.0f), mType(ReflectionProbeType::Box), mRadius(1.0f)
  15. , mExtents(1.0f, 1.0f, 1.0f), mTransitionDistance(1.0f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
  16. { }
  17. ReflectionProbeBase::ReflectionProbeBase(ReflectionProbeType type, float radius, const Vector3& extents)
  18. : mPosition(BsZero), mRotation(BsIdentity), mScale(1.0f, 1.0f, 1.0f), mType(type), mRadius(radius)
  19. , mExtents(extents), mTransitionDistance(1.0f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
  20. { }
  21. void ReflectionProbeBase::updateBounds()
  22. {
  23. switch (mType)
  24. {
  25. case ReflectionProbeType::Sphere:
  26. mBounds = Sphere(mPosition, mRadius * std::max(std::max(mScale.x, mScale.y), mScale.z));
  27. break;
  28. case ReflectionProbeType::Box:
  29. mBounds = Sphere(mPosition, (mExtents * mScale).length());
  30. break;
  31. }
  32. }
  33. ReflectionProbe::ReflectionProbe()
  34. :mLastUpdateHash(0)
  35. {
  36. }
  37. ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents)
  38. : ReflectionProbeBase(type, radius, extents), mLastUpdateHash(0)
  39. {
  40. // Calling virtual method is okay here because this is the most derived type
  41. updateBounds();
  42. }
  43. ReflectionProbe::~ReflectionProbe()
  44. {
  45. if (mRendererTask)
  46. mRendererTask->cancel();
  47. }
  48. void ReflectionProbe::capture()
  49. {
  50. if (mCustomTexture != nullptr)
  51. return;
  52. captureAndFilter();
  53. }
  54. void ReflectionProbe::filter()
  55. {
  56. if (mCustomTexture == nullptr)
  57. return;
  58. captureAndFilter();
  59. }
  60. void ReflectionProbe::captureAndFilter()
  61. {
  62. // If previous rendering task exists, cancel it
  63. if (mRendererTask != nullptr)
  64. mRendererTask->cancel();
  65. TEXTURE_DESC cubemapDesc;
  66. cubemapDesc.type = TEX_TYPE_CUBE_MAP;
  67. cubemapDesc.format = PF_RG11B10F;
  68. cubemapDesc.width = ct::IBLUtility::REFLECTION_CUBEMAP_SIZE;
  69. cubemapDesc.height = ct::IBLUtility::REFLECTION_CUBEMAP_SIZE;
  70. cubemapDesc.numMips = PixelUtil::getMaxMipmaps(cubemapDesc.width, cubemapDesc.height, 1, cubemapDesc.format);
  71. cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
  72. mFilteredTexture = Texture::_createPtr(cubemapDesc);
  73. auto renderComplete = [this]()
  74. {
  75. mRendererTask = nullptr;
  76. };
  77. SPtr<ct::ReflectionProbe> coreProbe = getCore();
  78. SPtr<ct::Texture> coreTexture = mFilteredTexture->getCore();
  79. if (mCustomTexture == nullptr)
  80. {
  81. auto renderReflProbe = [coreTexture, coreProbe]()
  82. {
  83. float radius = coreProbe->mType == ReflectionProbeType::Sphere ? coreProbe->mRadius :
  84. coreProbe->mExtents.length();
  85. ct::CaptureSettings settings;
  86. settings.encodeDepth = true;
  87. settings.depthEncodeNear = radius;
  88. settings.depthEncodeFar = radius + 1; // + 1 arbitrary, make it a customizable value?
  89. ct::gRenderer()->captureSceneCubeMap(coreTexture, coreProbe->getPosition(), settings);
  90. ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
  91. coreProbe->mFilteredTexture = coreTexture;
  92. ct::gRenderer()->notifyReflectionProbeUpdated(coreProbe.get(), true);
  93. return true;
  94. };
  95. mRendererTask = ct::RendererTask::create("ReflProbeRender", renderReflProbe);
  96. }
  97. else
  98. {
  99. SPtr<ct::Texture> coreCustomTex = mCustomTexture->getCore();
  100. auto filterReflProbe = [coreCustomTex, coreTexture, coreProbe]()
  101. {
  102. ct::gIBLUtility().scaleCubemap(coreCustomTex, 0, coreTexture, 0);
  103. ct::gIBLUtility().filterCubemapForSpecular(coreTexture, nullptr);
  104. coreProbe->mFilteredTexture = coreTexture;
  105. ct::gRenderer()->notifyReflectionProbeUpdated(coreProbe.get(), true);
  106. return true;
  107. };
  108. mRendererTask = ct::RendererTask::create("ReflProbeRender", filterReflProbe);
  109. }
  110. mRendererTask->onComplete.connect(renderComplete);
  111. ct::gRenderer()->addTask(mRendererTask);
  112. }
  113. SPtr<ct::ReflectionProbe> ReflectionProbe::getCore() const
  114. {
  115. return std::static_pointer_cast<ct::ReflectionProbe>(mCoreSpecific);
  116. }
  117. SPtr<ReflectionProbe> ReflectionProbe::createSphere(float radius)
  118. {
  119. ReflectionProbe* probe = new (bs_alloc<ReflectionProbe>()) ReflectionProbe(ReflectionProbeType::Sphere, radius, Vector3::ZERO);
  120. SPtr<ReflectionProbe> probePtr = bs_core_ptr<ReflectionProbe>(probe);
  121. probePtr->_setThisPtr(probePtr);
  122. probePtr->mUUID = UUIDGenerator::generateRandom();
  123. probePtr->initialize();
  124. return probePtr;
  125. }
  126. SPtr<ReflectionProbe> ReflectionProbe::createBox(const Vector3& extents)
  127. {
  128. ReflectionProbe* probe = new (bs_alloc<ReflectionProbe>()) ReflectionProbe(ReflectionProbeType::Box, 0.0f, extents);
  129. SPtr<ReflectionProbe> probePtr = bs_core_ptr<ReflectionProbe>(probe);
  130. probePtr->_setThisPtr(probePtr);
  131. probePtr->mUUID = UUIDGenerator::generateRandom();
  132. probePtr->initialize();
  133. return probePtr;
  134. }
  135. SPtr<ReflectionProbe> ReflectionProbe::createEmpty()
  136. {
  137. ReflectionProbe* probe = new (bs_alloc<ReflectionProbe>()) ReflectionProbe();
  138. SPtr<ReflectionProbe> probePtr = bs_core_ptr<ReflectionProbe>(probe);
  139. probePtr->_setThisPtr(probePtr);
  140. return probePtr;
  141. }
  142. SPtr<ct::CoreObject> ReflectionProbe::createCore() const
  143. {
  144. SPtr<ct::Texture> filteredTexture;
  145. if (mFilteredTexture != nullptr)
  146. filteredTexture = mFilteredTexture->getCore();
  147. ct::ReflectionProbe* probe = new (bs_alloc<ct::ReflectionProbe>()) ct::ReflectionProbe(mType, mRadius, mExtents,
  148. filteredTexture);
  149. SPtr<ct::ReflectionProbe> probePtr = bs_shared_ptr<ct::ReflectionProbe>(probe);
  150. probePtr->mUUID = mUUID;
  151. probePtr->_setThisPtr(probePtr);
  152. return probePtr;
  153. }
  154. CoreSyncData ReflectionProbe::syncToCore(FrameAlloc* allocator)
  155. {
  156. UINT32 size = 0;
  157. size += rttiGetElemSize(mPosition);
  158. size += rttiGetElemSize(mRotation);
  159. size += rttiGetElemSize(mScale);
  160. size += rttiGetElemSize(mType);
  161. size += rttiGetElemSize(mRadius);
  162. size += rttiGetElemSize(mExtents);
  163. size += rttiGetElemSize(mTransitionDistance);
  164. size += rttiGetElemSize(mIsActive);
  165. size += rttiGetElemSize(getCoreDirtyFlags());
  166. size += rttiGetElemSize(mBounds);
  167. size += sizeof(SPtr<ct::Texture>);
  168. size += rttiGetElemSize(mUUID);
  169. UINT8* buffer = allocator->alloc(size);
  170. char* dataPtr = (char*)buffer;
  171. dataPtr = rttiWriteElem(mPosition, dataPtr);
  172. dataPtr = rttiWriteElem(mRotation, dataPtr);
  173. dataPtr = rttiWriteElem(mScale, dataPtr);
  174. dataPtr = rttiWriteElem(mType, dataPtr);
  175. dataPtr = rttiWriteElem(mRadius, dataPtr);
  176. dataPtr = rttiWriteElem(mExtents, dataPtr);
  177. dataPtr = rttiWriteElem(mTransitionDistance, dataPtr);
  178. dataPtr = rttiWriteElem(mIsActive, dataPtr);
  179. dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
  180. dataPtr = rttiWriteElem(mBounds, dataPtr);
  181. dataPtr = rttiWriteElem(mUUID, dataPtr);
  182. return CoreSyncData(buffer, size);
  183. }
  184. void ReflectionProbe::_updateTransform(const HSceneObject& parent)
  185. {
  186. UINT32 curHash = parent->getTransformHash();
  187. if (curHash != _getLastModifiedHash())
  188. {
  189. setPosition(parent->getWorldPosition());
  190. setRotation(parent->getWorldRotation());
  191. setScale(parent->getWorldScale());
  192. _setLastModifiedHash(curHash);
  193. }
  194. }
  195. void ReflectionProbe::_markCoreDirty(ReflectionProbeDirtyFlag flags)
  196. {
  197. markCoreDirty((UINT32)flags);
  198. }
  199. RTTITypeBase* ReflectionProbe::getRTTIStatic()
  200. {
  201. return ReflectionProbeRTTI::instance();
  202. }
  203. RTTITypeBase* ReflectionProbe::getRTTI() const
  204. {
  205. return ReflectionProbe::getRTTIStatic();
  206. }
  207. namespace ct
  208. {
  209. ReflectionProbe::ReflectionProbe(ReflectionProbeType type, float radius, const Vector3& extents,
  210. const SPtr<Texture>& filteredTexture)
  211. : ReflectionProbeBase(type, radius, extents), mRendererId(0), mFilteredTexture(filteredTexture)
  212. {
  213. }
  214. ReflectionProbe::~ReflectionProbe()
  215. {
  216. gRenderer()->notifyReflectionProbeRemoved(this);
  217. }
  218. void ReflectionProbe::initialize()
  219. {
  220. updateBounds();
  221. gRenderer()->notifyReflectionProbeAdded(this);
  222. CoreObject::initialize();
  223. }
  224. void ReflectionProbe::syncToCore(const CoreSyncData& data)
  225. {
  226. char* dataPtr = (char*)data.getBuffer();
  227. UINT32 dirtyFlags = 0;
  228. bool oldIsActive = mIsActive;
  229. ReflectionProbeType oldType = mType;
  230. dataPtr = rttiReadElem(mPosition, dataPtr);
  231. dataPtr = rttiReadElem(mRotation, dataPtr);
  232. dataPtr = rttiReadElem(mScale, dataPtr);
  233. dataPtr = rttiReadElem(mType, dataPtr);
  234. dataPtr = rttiReadElem(mRadius, dataPtr);
  235. dataPtr = rttiReadElem(mExtents, dataPtr);
  236. dataPtr = rttiReadElem(mTransitionDistance, dataPtr);
  237. dataPtr = rttiReadElem(mIsActive, dataPtr);
  238. dataPtr = rttiReadElem(dirtyFlags, dataPtr);
  239. dataPtr = rttiReadElem(mBounds, dataPtr);
  240. dataPtr = rttiReadElem(mUUID, dataPtr);
  241. updateBounds();
  242. if (dirtyFlags == (UINT32)ReflectionProbeDirtyFlag::Transform)
  243. {
  244. if (mIsActive)
  245. gRenderer()->notifyReflectionProbeUpdated(this, false);
  246. }
  247. else
  248. {
  249. if (oldIsActive != mIsActive)
  250. {
  251. if (mIsActive)
  252. gRenderer()->notifyReflectionProbeAdded(this);
  253. else
  254. {
  255. ReflectionProbeType newType = mType;
  256. mType = oldType;
  257. gRenderer()->notifyReflectionProbeRemoved(this);
  258. mType = newType;
  259. }
  260. }
  261. else
  262. {
  263. ReflectionProbeType newType = mType;
  264. mType = oldType;
  265. gRenderer()->notifyReflectionProbeRemoved(this);
  266. mType = newType;
  267. gRenderer()->notifyReflectionProbeAdded(this);
  268. }
  269. }
  270. }
  271. }}