BsLight.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #include "BsLight.h"
  2. #include "BsLightRTTI.h"
  3. #include "BsRendererManager.h"
  4. #include "BsRenderer.h"
  5. #include "BsFrameAlloc.h"
  6. #include "BsSceneObject.h"
  7. #include "BsVertexDataDesc.h"
  8. #include "BsMesh.h"
  9. #include "BsShapeMeshes3D.h"
  10. namespace BansheeEngine
  11. {
  12. LightBase::LightBase()
  13. :mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
  14. mIntensity(5.0f), mSpotAngle(45), mSpotFalloffAngle(35.0f), mColor(Color::White), mIsActive(true)
  15. {
  16. mBounds = Sphere(mPosition, mRange);
  17. }
  18. LightBase::LightBase(LightType type, Color color,
  19. float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
  20. :mType(type), mCastsShadows(castsShadows), mRange(range), mSpotFalloffAngle(spotFalloffAngle),
  21. mIntensity(intensity), mSpotAngle(spotAngle), mColor(color), mIsActive(true)
  22. {
  23. mBounds = Sphere(mPosition, mRange);
  24. }
  25. float LightBase::getRadiance() const
  26. {
  27. switch (mType)
  28. {
  29. case LightType::Point:
  30. return mIntensity / (4 * Math::PI);
  31. case LightType::Spot:
  32. {
  33. float cosTotalAngle = Math::cos(mSpotAngle);
  34. float cosFalloffAngle = Math::cos(mSpotFalloffAngle);
  35. return mIntensity / (Math::TWO_PI * (1.0f - (cosFalloffAngle + cosTotalAngle) * 0.5f));
  36. }
  37. }
  38. return mIntensity;
  39. }
  40. void LightBase::updateBounds()
  41. {
  42. switch (mType)
  43. {
  44. case LightType::Directional:
  45. mBounds = Sphere(mPosition, std::numeric_limits<float>::infinity());
  46. break;
  47. case LightType::Point:
  48. mBounds = Sphere(mPosition, mRange);
  49. break;
  50. case LightType::Spot:
  51. {
  52. Degree angle = Math::clamp(mSpotAngle, Degree(-90), Degree(90));
  53. float coneRadius = Math::tan(angle) * mRange;
  54. float radius;
  55. Vector3 offset;
  56. if (coneRadius < mRange)
  57. {
  58. radius = (mRange * mRange + coneRadius * coneRadius) / (0.5f * mRange);
  59. offset = Vector3(0, 0, -(mRange - coneRadius));
  60. }
  61. else
  62. radius = coneRadius;
  63. Vector3 center = mPosition + mRotation.rotate(offset);
  64. mBounds = Sphere(center, radius);
  65. }
  66. break;
  67. }
  68. }
  69. const UINT32 LightCore::LIGHT_CONE_NUM_SIDES = 20;
  70. const UINT32 LightCore::LIGHT_CONE_NUM_SLICES = 10;
  71. LightCore::LightCore(LightType type, Color color,
  72. float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
  73. :LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle), mRendererId(0)
  74. {
  75. }
  76. LightCore::~LightCore()
  77. {
  78. gRenderer()->_notifyLightRemoved(this);
  79. }
  80. void LightCore::initialize()
  81. {
  82. updateBounds();
  83. gRenderer()->_notifyLightAdded(this);
  84. CoreObjectCore::initialize();
  85. }
  86. void LightCore::syncToCore(const CoreSyncData& data)
  87. {
  88. char* dataPtr = (char*)data.getBuffer();
  89. UINT32 dirtyFlags = 0;
  90. bool oldIsActive = mIsActive;
  91. LightType oldType = mType;
  92. dataPtr = rttiReadElem(mPosition, dataPtr);
  93. dataPtr = rttiReadElem(mRotation, dataPtr);
  94. dataPtr = rttiReadElem(mType, dataPtr);
  95. dataPtr = rttiReadElem(mCastsShadows, dataPtr);
  96. dataPtr = rttiReadElem(mColor, dataPtr);
  97. dataPtr = rttiReadElem(mRange, dataPtr);
  98. dataPtr = rttiReadElem(mIntensity, dataPtr);
  99. dataPtr = rttiReadElem(mSpotAngle, dataPtr);
  100. dataPtr = rttiReadElem(mSpotFalloffAngle, dataPtr);
  101. dataPtr = rttiReadElem(mIsActive, dataPtr);
  102. dataPtr = rttiReadElem(dirtyFlags, dataPtr);
  103. dataPtr = rttiReadElem(mBounds, dataPtr);
  104. updateBounds();
  105. if (dirtyFlags == (UINT32)LightDirtyFlag::Transform)
  106. {
  107. if (mIsActive)
  108. gRenderer()->_notifyLightUpdated(this);
  109. }
  110. else
  111. {
  112. if (oldIsActive != mIsActive)
  113. {
  114. if (mIsActive)
  115. gRenderer()->_notifyLightAdded(this);
  116. else
  117. {
  118. LightType newType = mType;
  119. mType = oldType;
  120. gRenderer()->_notifyLightRemoved(this);
  121. mType = newType;
  122. }
  123. }
  124. else
  125. {
  126. LightType newType = mType;
  127. mType = oldType;
  128. gRenderer()->_notifyLightRemoved(this);
  129. mType = newType;
  130. gRenderer()->_notifyLightAdded(this);
  131. }
  132. }
  133. }
  134. void LightCore::updateBounds()
  135. {
  136. LightBase::updateBounds();
  137. generateMesh();
  138. }
  139. void LightCore::generateMesh()
  140. {
  141. switch (mType)
  142. {
  143. case LightType::Directional:
  144. mMesh = nullptr;
  145. return;
  146. case LightType::Point:
  147. {
  148. SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
  149. vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  150. UINT32 numVertices = 0;
  151. UINT32 numIndices = 0;
  152. ShapeMeshes3D::getNumElementsSphere(1, numVertices, numIndices);
  153. MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
  154. UINT32* indexData = meshData->getIndices32();
  155. UINT8* positionData = meshData->getElementData(VES_POSITION);
  156. Sphere localSphere(Vector3::ZERO, 1.0f);
  157. ShapeMeshes3D::solidSphere(localSphere, positionData, nullptr, 0,
  158. vertexDesc->getVertexStride(), indexData, 0, 1);
  159. mMesh = MeshCore::create(meshData);
  160. }
  161. return;
  162. case LightType::Spot:
  163. {
  164. SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
  165. vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  166. UINT32 numVertices = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES * 2;
  167. UINT32 numIndices = ((LIGHT_CONE_NUM_SIDES * 2) * LIGHT_CONE_NUM_SLICES * 2) * 3;
  168. MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
  169. UINT32* indexData = meshData->getIndices32();
  170. UINT8* positionData = meshData->getElementData(VES_POSITION);
  171. UINT32 stride = vertexDesc->getVertexStride();
  172. // Dummy vertex positions, actual ones generated in shader
  173. for (UINT32 i = 0; i < numVertices; i++)
  174. {
  175. memcpy(positionData, &Vector3::ZERO, sizeof(Vector3));
  176. positionData += stride;
  177. }
  178. // Cone indices
  179. UINT32 curIdx = 0;
  180. for (UINT32 sliceIdx = 0; sliceIdx < (LIGHT_CONE_NUM_SLICES - 1); sliceIdx++)
  181. {
  182. for (UINT32 sideIdx = 0; sideIdx < LIGHT_CONE_NUM_SIDES; sideIdx++)
  183. {
  184. indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + sideIdx;
  185. indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
  186. indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
  187. indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
  188. indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
  189. indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
  190. }
  191. }
  192. // Sphere cap indices
  193. UINT32 coneOffset = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES;
  194. for (UINT32 sliceIdx = 0; sliceIdx < (LIGHT_CONE_NUM_SLICES - 1); sliceIdx++)
  195. {
  196. for (UINT32 sideIdx = 0; sideIdx < LIGHT_CONE_NUM_SIDES; sideIdx++)
  197. {
  198. indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + sideIdx;
  199. indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
  200. indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
  201. indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
  202. indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
  203. indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
  204. }
  205. }
  206. mMesh = MeshCore::create(meshData);
  207. }
  208. return;
  209. }
  210. }
  211. Light::Light()
  212. :mLastUpdateHash(0)
  213. {
  214. }
  215. Light::Light(LightType type, Color color,
  216. float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
  217. : LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle),
  218. mLastUpdateHash(0)
  219. {
  220. // Calling virtual method is okay here because this is the most derived type
  221. updateBounds();
  222. }
  223. SPtr<LightCore> Light::getCore() const
  224. {
  225. return std::static_pointer_cast<LightCore>(mCoreSpecific);
  226. }
  227. SPtr<Light> Light::create(LightType type, Color color,
  228. float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
  229. {
  230. Light* handler = new (bs_alloc<Light>())
  231. Light(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle);
  232. SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
  233. handlerPtr->_setThisPtr(handlerPtr);
  234. handlerPtr->initialize();
  235. return handlerPtr;
  236. }
  237. SPtr<Light> Light::createEmpty()
  238. {
  239. Light* handler = new (bs_alloc<Light>()) Light();
  240. SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
  241. handlerPtr->_setThisPtr(handlerPtr);
  242. return handlerPtr;
  243. }
  244. SPtr<CoreObjectCore> Light::createCore() const
  245. {
  246. LightCore* handler = new (bs_alloc<LightCore>())
  247. LightCore(mType, mColor, mIntensity, mRange, mCastsShadows, mSpotAngle, mSpotFalloffAngle);
  248. SPtr<LightCore> handlerPtr = bs_shared_ptr<LightCore>(handler);
  249. handlerPtr->_setThisPtr(handlerPtr);
  250. return handlerPtr;
  251. }
  252. CoreSyncData Light::syncToCore(FrameAlloc* allocator)
  253. {
  254. UINT32 size = 0;
  255. size += rttiGetElemSize(mPosition);
  256. size += rttiGetElemSize(mRotation);
  257. size += rttiGetElemSize(mType);
  258. size += rttiGetElemSize(mCastsShadows);
  259. size += rttiGetElemSize(mColor);
  260. size += rttiGetElemSize(mRange);
  261. size += rttiGetElemSize(mIntensity);
  262. size += rttiGetElemSize(mSpotAngle);
  263. size += rttiGetElemSize(mIsActive);
  264. size += rttiGetElemSize(mSpotFalloffAngle);
  265. size += rttiGetElemSize(getCoreDirtyFlags());
  266. size += rttiGetElemSize(mBounds);
  267. UINT8* buffer = allocator->alloc(size);
  268. char* dataPtr = (char*)buffer;
  269. dataPtr = rttiWriteElem(mPosition, dataPtr);
  270. dataPtr = rttiWriteElem(mRotation, dataPtr);
  271. dataPtr = rttiWriteElem(mType, dataPtr);
  272. dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
  273. dataPtr = rttiWriteElem(mColor, dataPtr);
  274. dataPtr = rttiWriteElem(mRange, dataPtr);
  275. dataPtr = rttiWriteElem(mIntensity, dataPtr);
  276. dataPtr = rttiWriteElem(mSpotAngle, dataPtr);
  277. dataPtr = rttiWriteElem(mSpotFalloffAngle, dataPtr);
  278. dataPtr = rttiWriteElem(mIsActive, dataPtr);
  279. dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
  280. dataPtr = rttiWriteElem(mBounds, dataPtr);
  281. return CoreSyncData(buffer, size);
  282. }
  283. void Light::_updateTransform(const HSceneObject& parent)
  284. {
  285. UINT32 curHash = parent->getTransformHash();
  286. if (curHash != _getLastModifiedHash())
  287. {
  288. setPosition(parent->getWorldPosition());
  289. setRotation(parent->getWorldRotation());
  290. _setLastModifiedHash(curHash);
  291. }
  292. }
  293. void Light::_markCoreDirty(LightDirtyFlag flag)
  294. {
  295. markCoreDirty((UINT32)flag);
  296. }
  297. RTTITypeBase* Light::getRTTIStatic()
  298. {
  299. return LightRTTI::instance();
  300. }
  301. RTTITypeBase* Light::getRTTI() const
  302. {
  303. return Light::getRTTIStatic();
  304. }
  305. }