| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- #include "BsLight.h"
- #include "BsLightRTTI.h"
- #include "BsRendererManager.h"
- #include "BsRenderer.h"
- #include "BsFrameAlloc.h"
- #include "BsSceneObject.h"
- #include "BsVertexDataDesc.h"
- #include "BsMesh.h"
- #include "BsShapeMeshes3D.h"
- namespace BansheeEngine
- {
- LightBase::LightBase()
- :mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
- mIntensity(5.0f), mSpotAngle(45), mSpotFalloffAngle(35.0f), mColor(Color::White), mIsActive(true)
- {
- mBounds = Sphere(mPosition, mRange);
- }
- LightBase::LightBase(LightType type, Color color,
- float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
- :mType(type), mCastsShadows(castsShadows), mRange(range), mSpotFalloffAngle(spotFalloffAngle),
- mIntensity(intensity), mSpotAngle(spotAngle), mColor(color), mIsActive(true)
- {
- mBounds = Sphere(mPosition, mRange);
- }
- float LightBase::getRadiance() const
- {
- switch (mType)
- {
- case LightType::Point:
- return mIntensity / (4 * Math::PI);
- case LightType::Spot:
- {
- float cosTotalAngle = Math::cos(mSpotAngle);
- float cosFalloffAngle = Math::cos(mSpotFalloffAngle);
- return mIntensity / (Math::TWO_PI * (1.0f - (cosFalloffAngle + cosTotalAngle) * 0.5f));
- }
- }
- return mIntensity;
- }
- void LightBase::updateBounds()
- {
- switch (mType)
- {
- case LightType::Directional:
- mBounds = Sphere(mPosition, std::numeric_limits<float>::infinity());
- break;
- case LightType::Point:
- mBounds = Sphere(mPosition, mRange);
- break;
- case LightType::Spot:
- {
- Degree angle = Math::clamp(mSpotAngle, Degree(-90), Degree(90));
- float coneRadius = Math::tan(angle) * mRange;
- float radius;
- Vector3 offset;
- if (coneRadius < mRange)
- {
- radius = (mRange * mRange + coneRadius * coneRadius) / (0.5f * mRange);
- offset = Vector3(0, 0, -(mRange - coneRadius));
- }
- else
- radius = coneRadius;
- Vector3 center = mPosition + mRotation.rotate(offset);
- mBounds = Sphere(center, radius);
- }
- break;
- }
- }
- const UINT32 LightCore::LIGHT_CONE_NUM_SIDES = 20;
- const UINT32 LightCore::LIGHT_CONE_NUM_SLICES = 10;
- LightCore::LightCore(LightType type, Color color,
- float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
- :LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle), mRendererId(0)
- {
- }
- LightCore::~LightCore()
- {
- gRenderer()->_notifyLightRemoved(this);
- }
- void LightCore::initialize()
- {
- updateBounds();
- gRenderer()->_notifyLightAdded(this);
- CoreObjectCore::initialize();
- }
- void LightCore::syncToCore(const CoreSyncData& data)
- {
- char* dataPtr = (char*)data.getBuffer();
- UINT32 dirtyFlags = 0;
- bool oldIsActive = mIsActive;
- LightType oldType = mType;
- dataPtr = rttiReadElem(mPosition, dataPtr);
- dataPtr = rttiReadElem(mRotation, dataPtr);
- dataPtr = rttiReadElem(mType, dataPtr);
- dataPtr = rttiReadElem(mCastsShadows, dataPtr);
- dataPtr = rttiReadElem(mColor, dataPtr);
- dataPtr = rttiReadElem(mRange, dataPtr);
- dataPtr = rttiReadElem(mIntensity, dataPtr);
- dataPtr = rttiReadElem(mSpotAngle, dataPtr);
- dataPtr = rttiReadElem(mSpotFalloffAngle, dataPtr);
- dataPtr = rttiReadElem(mIsActive, dataPtr);
- dataPtr = rttiReadElem(dirtyFlags, dataPtr);
- dataPtr = rttiReadElem(mBounds, dataPtr);
- updateBounds();
- if (dirtyFlags == (UINT32)LightDirtyFlag::Transform)
- {
- if (mIsActive)
- gRenderer()->_notifyLightUpdated(this);
- }
- else
- {
- if (oldIsActive != mIsActive)
- {
- if (mIsActive)
- gRenderer()->_notifyLightAdded(this);
- else
- {
- LightType newType = mType;
- mType = oldType;
- gRenderer()->_notifyLightRemoved(this);
- mType = newType;
- }
- }
- else
- {
- LightType newType = mType;
- mType = oldType;
- gRenderer()->_notifyLightRemoved(this);
- mType = newType;
- gRenderer()->_notifyLightAdded(this);
- }
- }
- }
- void LightCore::updateBounds()
- {
- LightBase::updateBounds();
- generateMesh();
- }
- void LightCore::generateMesh()
- {
- switch (mType)
- {
- case LightType::Directional:
- mMesh = nullptr;
- return;
- case LightType::Point:
- {
- SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
- vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
- UINT32 numVertices = 0;
- UINT32 numIndices = 0;
- ShapeMeshes3D::getNumElementsSphere(1, numVertices, numIndices);
- MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
- UINT32* indexData = meshData->getIndices32();
- UINT8* positionData = meshData->getElementData(VES_POSITION);
- Sphere localSphere(Vector3::ZERO, 1.0f);
- ShapeMeshes3D::solidSphere(localSphere, positionData, nullptr, 0,
- vertexDesc->getVertexStride(), indexData, 0, 1);
- mMesh = MeshCore::create(meshData);
- }
- return;
- case LightType::Spot:
- {
- SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
- vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
- UINT32 numVertices = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES * 2;
- UINT32 numIndices = ((LIGHT_CONE_NUM_SIDES * 2) * LIGHT_CONE_NUM_SLICES * 2) * 3;
- MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
- UINT32* indexData = meshData->getIndices32();
- UINT8* positionData = meshData->getElementData(VES_POSITION);
- UINT32 stride = vertexDesc->getVertexStride();
- // Dummy vertex positions, actual ones generated in shader
- for (UINT32 i = 0; i < numVertices; i++)
- {
- memcpy(positionData, &Vector3::ZERO, sizeof(Vector3));
- positionData += stride;
- }
- // Cone indices
- UINT32 curIdx = 0;
- for (UINT32 sliceIdx = 0; sliceIdx < (LIGHT_CONE_NUM_SLICES - 1); sliceIdx++)
- {
- for (UINT32 sideIdx = 0; sideIdx < LIGHT_CONE_NUM_SIDES; sideIdx++)
- {
- indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + sideIdx;
- indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
- indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
- indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
- indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
- indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
- }
- }
- // Sphere cap indices
- UINT32 coneOffset = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES;
- for (UINT32 sliceIdx = 0; sliceIdx < (LIGHT_CONE_NUM_SLICES - 1); sliceIdx++)
- {
- for (UINT32 sideIdx = 0; sideIdx < LIGHT_CONE_NUM_SIDES; sideIdx++)
- {
- indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + sideIdx;
- indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
- indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
- indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
- indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
- indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
- }
- }
- mMesh = MeshCore::create(meshData);
- }
- return;
- }
- }
- Light::Light()
- :mLastUpdateHash(0)
- {
-
- }
- Light::Light(LightType type, Color color,
- float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
- : LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle),
- mLastUpdateHash(0)
- {
- // Calling virtual method is okay here because this is the most derived type
- updateBounds();
- }
- SPtr<LightCore> Light::getCore() const
- {
- return std::static_pointer_cast<LightCore>(mCoreSpecific);
- }
- SPtr<Light> Light::create(LightType type, Color color,
- float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
- {
- Light* handler = new (bs_alloc<Light>())
- Light(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle);
- SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
- handlerPtr->_setThisPtr(handlerPtr);
- handlerPtr->initialize();
- return handlerPtr;
- }
- SPtr<Light> Light::createEmpty()
- {
- Light* handler = new (bs_alloc<Light>()) Light();
- SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
- handlerPtr->_setThisPtr(handlerPtr);
- return handlerPtr;
- }
- SPtr<CoreObjectCore> Light::createCore() const
- {
- LightCore* handler = new (bs_alloc<LightCore>())
- LightCore(mType, mColor, mIntensity, mRange, mCastsShadows, mSpotAngle, mSpotFalloffAngle);
- SPtr<LightCore> handlerPtr = bs_shared_ptr<LightCore>(handler);
- handlerPtr->_setThisPtr(handlerPtr);
- return handlerPtr;
- }
- CoreSyncData Light::syncToCore(FrameAlloc* allocator)
- {
- UINT32 size = 0;
- size += rttiGetElemSize(mPosition);
- size += rttiGetElemSize(mRotation);
- size += rttiGetElemSize(mType);
- size += rttiGetElemSize(mCastsShadows);
- size += rttiGetElemSize(mColor);
- size += rttiGetElemSize(mRange);
- size += rttiGetElemSize(mIntensity);
- size += rttiGetElemSize(mSpotAngle);
- size += rttiGetElemSize(mIsActive);
- size += rttiGetElemSize(mSpotFalloffAngle);
- size += rttiGetElemSize(getCoreDirtyFlags());
- size += rttiGetElemSize(mBounds);
- UINT8* buffer = allocator->alloc(size);
- char* dataPtr = (char*)buffer;
- dataPtr = rttiWriteElem(mPosition, dataPtr);
- dataPtr = rttiWriteElem(mRotation, dataPtr);
- dataPtr = rttiWriteElem(mType, dataPtr);
- dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
- dataPtr = rttiWriteElem(mColor, dataPtr);
- dataPtr = rttiWriteElem(mRange, dataPtr);
- dataPtr = rttiWriteElem(mIntensity, dataPtr);
- dataPtr = rttiWriteElem(mSpotAngle, dataPtr);
- dataPtr = rttiWriteElem(mSpotFalloffAngle, dataPtr);
- dataPtr = rttiWriteElem(mIsActive, dataPtr);
- dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
- dataPtr = rttiWriteElem(mBounds, dataPtr);
- return CoreSyncData(buffer, size);
- }
- void Light::_updateTransform(const HSceneObject& parent)
- {
- UINT32 curHash = parent->getTransformHash();
- if (curHash != _getLastModifiedHash())
- {
- setPosition(parent->getWorldPosition());
- setRotation(parent->getWorldRotation());
- _setLastModifiedHash(curHash);
- }
- }
- void Light::_markCoreDirty(LightDirtyFlag flag)
- {
- markCoreDirty((UINT32)flag);
- }
- RTTITypeBase* Light::getRTTIStatic()
- {
- return LightRTTI::instance();
- }
- RTTITypeBase* Light::getRTTI() const
- {
- return Light::getRTTIStatic();
- }
- }
|