mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-21 09:53:50 +00:00
flickering lights
This commit is contained in:
parent
e443455612
commit
4ce83badc9
5 changed files with 122 additions and 37 deletions
|
@ -192,19 +192,43 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
|
||||||
Ogre::Light *light = mRenderer.getScene()->createLight();
|
Ogre::Light *light = mRenderer.getScene()->createLight();
|
||||||
light->setDiffuseColour (r, g, b);
|
light->setDiffuseColour (r, g, b);
|
||||||
|
|
||||||
|
ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
|
||||||
|
ptr.get<ESM::Light>();
|
||||||
|
|
||||||
LightInfo info;
|
LightInfo info;
|
||||||
info.name = light->getName();
|
info.name = light->getName();
|
||||||
info.radius = radius;
|
info.radius = radius;
|
||||||
info.colour = Ogre::ColourValue(r, g, b);
|
info.colour = Ogre::ColourValue(r, g, b);
|
||||||
mLights.push_back(info);
|
|
||||||
|
|
||||||
|
if (ref->base->data.flags & ESM::Light::Negative)
|
||||||
|
info.colour *= -1;
|
||||||
|
|
||||||
|
info.interior = (ptr.getCell()->cell->data.flags & ESM::Cell::Interior);
|
||||||
|
|
||||||
|
if (ref->base->data.flags & ESM::Light::Flicker)
|
||||||
|
info.type = LT_Flicker;
|
||||||
|
else if (ref->base->data.flags & ESM::Light::FlickerSlow)
|
||||||
|
info.type = LT_FlickerSlow;
|
||||||
|
else if (ref->base->data.flags & ESM::Light::Pulse)
|
||||||
|
info.type = LT_Pulse;
|
||||||
|
else if (ref->base->data.flags & ESM::Light::PulseSlow)
|
||||||
|
info.type = LT_PulseSlow;
|
||||||
|
else
|
||||||
|
info.type = LT_Normal;
|
||||||
|
|
||||||
|
// random starting phase for the animation
|
||||||
|
info.time = Ogre::Math::RangeRandom(0, 2 * M_PI);
|
||||||
|
|
||||||
|
// adjust the lights depending if we're in an interior or exterior cell
|
||||||
|
// quadratic means the light intensity falls off quite fast, resulting in a
|
||||||
|
// dark, atmospheric environment (perfect for exteriors)
|
||||||
|
// for interiors, we want more "warm" lights, so use linear attenuation.
|
||||||
bool quadratic = false;
|
bool quadratic = false;
|
||||||
if (!lightOutQuadInLin)
|
if (!lightOutQuadInLin)
|
||||||
quadratic = lightQuadratic;
|
quadratic = lightQuadratic;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
quadratic = !mInterior;
|
quadratic = !info.interior;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!quadratic)
|
if (!quadratic)
|
||||||
|
@ -221,6 +245,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
|
||||||
}
|
}
|
||||||
|
|
||||||
insert->attachObject(light);
|
insert->attachObject(light);
|
||||||
|
mLights.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
||||||
|
@ -329,17 +354,8 @@ void Objects::disableLights()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::setInterior(const bool interior)
|
|
||||||
{
|
|
||||||
mInterior = interior;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Objects::update(const float dt)
|
void Objects::update(const float dt)
|
||||||
{
|
{
|
||||||
// adjust the lights depending if we're in an interior or exterior cell
|
|
||||||
// quadratic means the light intensity falls off quite fast, resulting in a
|
|
||||||
// dark, atmospheric environment (perfect for exteriors)
|
|
||||||
// for interiors, we want more "warm" lights, so use linear attenuation.
|
|
||||||
std::vector<LightInfo>::iterator it = mLights.begin();
|
std::vector<LightInfo>::iterator it = mLights.begin();
|
||||||
while (it != mLights.end())
|
while (it != mLights.end())
|
||||||
{
|
{
|
||||||
|
@ -347,26 +363,77 @@ void Objects::update(const float dt)
|
||||||
{
|
{
|
||||||
Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name);
|
Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name);
|
||||||
|
|
||||||
bool quadratic = false;
|
// Light animation (pulse & flicker)
|
||||||
if (!lightOutQuadInLin)
|
it->time += dt;
|
||||||
quadratic = lightQuadratic;
|
const float phase = std::fmod(it->time, (32 * 2 * M_PI)) * 20;
|
||||||
else
|
float pulseConstant;
|
||||||
{
|
|
||||||
quadratic = !mInterior;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!quadratic)
|
// These formulas are just guesswork, but they work pretty well
|
||||||
|
if (it->type == LT_Normal)
|
||||||
{
|
{
|
||||||
float radius = it->radius * lightLinearRadiusMult;
|
// Less than 1/255 light modifier for a constant light:
|
||||||
float attenuation = lightLinearValue / it->radius;
|
pulseConstant = (const float)(1.0 + sin(phase) / 255.0 );
|
||||||
light->setAttenuation(radius*10, 0, attenuation, 0);
|
}
|
||||||
|
else if (it->type == LT_Flicker)
|
||||||
|
{
|
||||||
|
// Let's do a 50% -> 100% sine wave pulse over 1 second:
|
||||||
|
// This is 75% +/- 25%
|
||||||
|
pulseConstant = (const float)(0.75 + sin(phase) * 0.25);
|
||||||
|
|
||||||
|
// Then add a 25% flicker variation:
|
||||||
|
it->resetTime -= dt;
|
||||||
|
if (it->resetTime < 0)
|
||||||
|
{
|
||||||
|
it->flickerVariation = (rand() % 1000) / 1000 * 0.25;
|
||||||
|
it->resetTime = 0.5;
|
||||||
|
}
|
||||||
|
if (it->resetTime > 0.25)
|
||||||
|
{
|
||||||
|
pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime * 2.0f) + pulseConstant * it->resetTime * 2.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime * 2.0f) + pulseConstant * (1-it->resetTime * 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (it->type == LT_FlickerSlow)
|
||||||
|
{
|
||||||
|
// Let's do a 50% -> 100% sine wave pulse over 1 second:
|
||||||
|
// This is 75% +/- 25%
|
||||||
|
pulseConstant = (const float)(0.75 + sin(phase / 4.0) * 0.25);
|
||||||
|
|
||||||
|
// Then add a 25% flicker variation:
|
||||||
|
it->resetTime -= dt;
|
||||||
|
if (it->resetTime < 0)
|
||||||
|
{
|
||||||
|
it->flickerVariation = (rand() % 1000) / 1000 * 0.25;
|
||||||
|
it->resetTime = 0.5;
|
||||||
|
}
|
||||||
|
if (it->resetTime > 0.5)
|
||||||
|
{
|
||||||
|
pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime) + pulseConstant * it->resetTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime) + pulseConstant * (1-it->resetTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (it->type == LT_Pulse)
|
||||||
|
{
|
||||||
|
// Let's do a 75% -> 125% sine wave pulse over 1 second:
|
||||||
|
// This is 100% +/- 25%
|
||||||
|
pulseConstant = (const float)(1.0 + sin(phase) * 0.25);
|
||||||
|
}
|
||||||
|
else if (it->type == LT_PulseSlow)
|
||||||
|
{
|
||||||
|
// Let's do a 75% -> 125% sine wave pulse over 1 second:
|
||||||
|
// This is 100% +/- 25%
|
||||||
|
pulseConstant = (const float)(1.0 + sin(phase / 4.0) * 0.25);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
assert(0 && "Invalid light type");
|
||||||
float radius = it->radius * lightQuadraticRadiusMult;
|
|
||||||
float attenuation = lightQuadraticValue / pow(it->radius, 2);
|
light->setDiffuseColour( it->colour * pulseConstant );
|
||||||
light->setAttenuation(radius*10, 0, 0, attenuation);
|
|
||||||
}
|
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,37 @@
|
||||||
namespace MWRender{
|
namespace MWRender{
|
||||||
|
|
||||||
/// information about light needed for rendering
|
/// information about light needed for rendering
|
||||||
|
enum LightType
|
||||||
|
{
|
||||||
|
// These are all mutually exclusive
|
||||||
|
LT_Normal=0,
|
||||||
|
LT_Flicker=1,
|
||||||
|
LT_FlickerSlow=2,
|
||||||
|
LT_Pulse=3,
|
||||||
|
LT_PulseSlow=4
|
||||||
|
};
|
||||||
|
|
||||||
struct LightInfo
|
struct LightInfo
|
||||||
{
|
{
|
||||||
|
// Constants
|
||||||
std::string name; // ogre handle
|
std::string name; // ogre handle
|
||||||
Ogre::ColourValue colour;
|
Ogre::ColourValue colour;
|
||||||
float radius;
|
float radius;
|
||||||
|
bool interior; // Does this light belong to an interior or exterior cell
|
||||||
|
LightType type;
|
||||||
|
|
||||||
|
// Runtime variables
|
||||||
|
float flickerVariation; // 25% flicker variation, reset once every 0.5 seconds
|
||||||
|
float flickerSlowVariation; // 25% flicker variation, reset once every 1.0 seconds
|
||||||
|
float resetTime;
|
||||||
|
long double time;
|
||||||
|
|
||||||
|
|
||||||
|
LightInfo() :
|
||||||
|
flickerVariation(0), resetTime(0.5),
|
||||||
|
flickerSlowVariation(0), time(0), interior(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Objects{
|
class Objects{
|
||||||
|
@ -38,13 +64,11 @@ class Objects{
|
||||||
|
|
||||||
static bool lightOutQuadInLin;
|
static bool lightOutQuadInLin;
|
||||||
|
|
||||||
bool mInterior;
|
|
||||||
|
|
||||||
void clearSceneNode (Ogre::SceneNode *node);
|
void clearSceneNode (Ogre::SceneNode *node);
|
||||||
///< Remove all movable objects from \a node.
|
///< Remove all movable objects from \a node.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mInterior(true) {}
|
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer) {}
|
||||||
~Objects(){}
|
~Objects(){}
|
||||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||||
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
|
@ -56,9 +80,6 @@ public:
|
||||||
void update (const float dt);
|
void update (const float dt);
|
||||||
///< per-frame update
|
///< per-frame update
|
||||||
|
|
||||||
void setInterior(const bool interior);
|
|
||||||
///< call this to switch from interior to exterior or vice versa
|
|
||||||
|
|
||||||
Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*);
|
Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*);
|
||||||
///< get a bounding box that encloses all objects in the specified cell
|
///< get a bounding box that encloses all objects in the specified cell
|
||||||
|
|
||||||
|
|
|
@ -510,13 +510,11 @@ Shadows* RenderingManager::getShadows()
|
||||||
|
|
||||||
void RenderingManager::switchToInterior()
|
void RenderingManager::switchToInterior()
|
||||||
{
|
{
|
||||||
mObjects.setInterior(true);
|
|
||||||
mRendering.getScene()->setCameraRelativeRendering(false);
|
mRendering.getScene()->setCameraRelativeRendering(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::switchToExterior()
|
void RenderingManager::switchToExterior()
|
||||||
{
|
{
|
||||||
mObjects.setInterior(false);
|
|
||||||
mRendering.getScene()->setCameraRelativeRendering(true);
|
mRendering.getScene()->setCameraRelativeRendering(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -522,7 +522,6 @@ void WeatherManager::update(float duration)
|
||||||
// re-scale to 100 percent
|
// re-scale to 100 percent
|
||||||
const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard;
|
const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard;
|
||||||
|
|
||||||
srand(time(NULL));
|
|
||||||
float random = ((rand()%100)/100.f) * total;
|
float random = ((rand()%100)/100.f) * total;
|
||||||
|
|
||||||
//if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear)
|
//if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear)
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct Light
|
||||||
{
|
{
|
||||||
Dynamic = 0x001,
|
Dynamic = 0x001,
|
||||||
Carry = 0x002, // Can be carried
|
Carry = 0x002, // Can be carried
|
||||||
Negative = 0x004, // Negative light?
|
Negative = 0x004, // Negative light - i.e. darkness
|
||||||
Flicker = 0x008,
|
Flicker = 0x008,
|
||||||
Fire = 0x010,
|
Fire = 0x010,
|
||||||
OffDefault = 0x020, // Off by default
|
OffDefault = 0x020, // Off by default
|
||||||
|
|
Loading…
Reference in a new issue