You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.7 KiB
C++
134 lines
3.7 KiB
C++
#include "lightcontroller.hpp"
|
|
|
|
#include <cmath>
|
|
|
|
#include <osg/NodeVisitor>
|
|
|
|
#include <components/sceneutil/lightmanager.hpp>
|
|
|
|
#include <components/misc/rng.hpp>
|
|
|
|
namespace
|
|
{
|
|
|
|
float pulseAmplitude(float time)
|
|
{
|
|
return std::sin(time);
|
|
}
|
|
|
|
float flickerAmplitude(float time)
|
|
{
|
|
static const float fb = 1.17024f;
|
|
static const float f[3] = { 1.5708f, 4.18774f, 5.19934f };
|
|
static const float o[3] = { 0.804248f, 2.11115f, 3.46832f };
|
|
static const float m[3] = { 1.0f, 0.785f, 0.876f };
|
|
static const float s = 0.394f;
|
|
|
|
float v = 0.0f;
|
|
for(int i = 0;i < 3;++i)
|
|
v += std::sin(fb*time*f[i] + o[1])*m[i];
|
|
return v * s;
|
|
}
|
|
|
|
float flickerFrequency(float phase)
|
|
{
|
|
static const float fa = 0.785398f;
|
|
static const float tdo = 0.94f;
|
|
static const float tdm = 2.48f;
|
|
|
|
return tdo + tdm*std::sin(fa * phase);
|
|
}
|
|
|
|
}
|
|
|
|
namespace SceneUtil
|
|
{
|
|
|
|
LightController::LightController()
|
|
: mType(LT_Normal)
|
|
, mPhase((Misc::Rng::rollClosedProbability() * 2.f - 1.f) * 500.f)
|
|
, mDeltaCount(0.f)
|
|
, mDirection(1.f)
|
|
, mLastTime(0.0)
|
|
{
|
|
}
|
|
|
|
void LightController::setType(LightController::LightType type)
|
|
{
|
|
mType = type;
|
|
}
|
|
|
|
void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv)
|
|
{
|
|
double time = nv->getFrameStamp()->getSimulationTime();
|
|
|
|
// disabled early out, light state needs to be set every frame regardless of change, due to the double buffering
|
|
//if (time == mLastTime)
|
|
// return;
|
|
|
|
float dt = static_cast<float>(time - mLastTime);
|
|
mLastTime = time;
|
|
|
|
float brightness = 1.0f;
|
|
float cycle_time;
|
|
float time_distortion;
|
|
|
|
const float pi = 3.14159265359;
|
|
|
|
if(mType == LT_Pulse || mType == LT_PulseSlow)
|
|
{
|
|
cycle_time = 2.0f * pi;
|
|
time_distortion = mType == LT_Pulse ? 20.0f : 4.f;
|
|
}
|
|
else
|
|
{
|
|
static const float fa = 0.785398f;
|
|
static const float phase_wavelength = 120.0f * pi / fa;
|
|
|
|
cycle_time = 500.0f;
|
|
mPhase = std::fmod(mPhase + dt, phase_wavelength);
|
|
time_distortion = flickerFrequency(mPhase);
|
|
}
|
|
|
|
mDeltaCount += mDirection*dt*time_distortion;
|
|
if(mDirection > 0 && mDeltaCount > +cycle_time)
|
|
{
|
|
mDirection = -1.0f;
|
|
mDeltaCount = 2.0f*cycle_time - mDeltaCount;
|
|
}
|
|
if(mDirection < 0 && mDeltaCount < -cycle_time)
|
|
{
|
|
mDirection = +1.0f;
|
|
mDeltaCount = -2.0f*cycle_time - mDeltaCount;
|
|
}
|
|
|
|
static const float fast = 4.0f/1.0f;
|
|
static const float slow = 1.0f/1.0f;
|
|
|
|
// These formulas are just guesswork, but they work pretty well
|
|
if(mType == LT_Normal)
|
|
{
|
|
// Less than 1/255 light modifier for a constant light:
|
|
brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f;
|
|
}
|
|
else if(mType == LT_Flicker)
|
|
brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f;
|
|
else if(mType == LT_FlickerSlow)
|
|
brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f;
|
|
else if(mType == LT_Pulse)
|
|
brightness = 0.7f + pulseAmplitude(mDeltaCount*fast)*0.3f;
|
|
else if(mType == LT_PulseSlow)
|
|
brightness = 0.7f + pulseAmplitude(mDeltaCount*slow)*0.3f;
|
|
|
|
static_cast<SceneUtil::LightSource*>(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * brightness);
|
|
|
|
traverse(node, nv);
|
|
}
|
|
|
|
void LightController::setDiffuse(const osg::Vec4f& color)
|
|
{
|
|
mDiffuseColor = color;
|
|
}
|
|
|
|
}
|