From 62fd2d47a58ac497e8bf990ac6f0cd3f4ba30634 Mon Sep 17 00:00:00 2001 From: capostrophic Date: Sat, 10 Aug 2019 15:52:05 +0300 Subject: [PATCH] Rewrite flickering/pulsing to work more like vanilla (bug #4952) --- CHANGELOG.md | 1 + components/sceneutil/lightcontroller.cpp | 110 ++++++----------------- components/sceneutil/lightcontroller.hpp | 5 +- 3 files changed, 30 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e2d7a29f..df524903c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,7 @@ Bug #4945: Poor random magic magnitude distribution Bug #4947: Player character doesn't use lip animation Bug #4948: Footstep sounds while levitating on ground level + Bug #4952: Torches held by NPCs flicker too quickly Bug #4961: Flying creature combat engagement takes z-axis into account Bug #4963: Enchant skill progress is incorrect Bug #4964: Multiple effect spell projectile sounds play louder than vanilla diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index 199b408d7..c759fabc7 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -8,48 +8,16 @@ #include -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[i])*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) + , mPhase(0.25f + Misc::Rng::rollClosedProbability() * 0.75f) + , mBrightness(0.675f) + , mStartTime(0.0) , mLastTime(0.0) + , mTicksToAdvance(0.f) { } @@ -61,66 +29,40 @@ namespace SceneUtil void LightController::operator ()(osg::Node* node, osg::NodeVisitor* nv) { double time = nv->getFrameStamp()->getSimulationTime(); + if (mStartTime == 0) + mStartTime = time; // 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(time - mLastTime); - mLastTime = time; - - float brightness = 1.0f; - float cycle_time; - float time_distortion; - - if(mType == LT_Pulse || mType == LT_PulseSlow) + if (mType == LT_Normal) { - cycle_time = 2.0f * osg::PI; - time_distortion = 3.0f; + static_cast(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor); + traverse(node, nv); + return; } - else - { - static const float fa = osg::PI / 4.0f; - static const float phase_wavelength = 120.0f * osg::PI / fa; - cycle_time = 500.0f; - mPhase = std::fmod(mPhase + dt, phase_wavelength); - time_distortion = flickerFrequency(mPhase); - } + // Updating flickering at 15 FPS like vanilla. + constexpr float updateRate = 15.f; + mTicksToAdvance = static_cast(time - mStartTime - mLastTime) * updateRate * 0.25f + mTicksToAdvance * 0.75f; + mLastTime = time - mStartTime; - mDeltaCount += mDirection*dt*time_distortion; - if(mDirection > 0 && mDeltaCount > +cycle_time) - { - mDirection = -1.0f; - float extra = mDeltaCount - cycle_time; - mDeltaCount -= 2*extra; - } - if(mDirection < 0 && mDeltaCount < -cycle_time) - { - mDirection = +1.0f; - float extra = cycle_time - mDeltaCount; - mDeltaCount += 2*extra; - } - - static const float fast = 4.0f/1.0f; - static const float slow = 1.0f/1.0f; + float speed = (mType == LT_Flicker || mType == LT_Pulse) ? 0.1f : 0.05f; + if (mBrightness >= mPhase) + mBrightness -= mTicksToAdvance * speed; + else + mBrightness += mTicksToAdvance * speed; - // These formulas are just guesswork, but they work pretty well - if(mType == LT_Normal) + if (std::abs(mBrightness - mPhase) < speed) { - // Less than 1/255 light modifier for a constant light: - brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; + if (mType == LT_Flicker || mType == LT_FlickerSlow) + mPhase = 0.25f + Misc::Rng::rollClosedProbability() * 0.75f; + else // if (mType == LT_Pulse || mType == LT_PulseSlow) + mPhase = mPhase <= 0.5f ? 1.f : 0.25f; } - 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(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * brightness); + + static_cast(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * mBrightness); traverse(node, nv); } diff --git a/components/sceneutil/lightcontroller.hpp b/components/sceneutil/lightcontroller.hpp index 8f70af343..3292ae541 100644 --- a/components/sceneutil/lightcontroller.hpp +++ b/components/sceneutil/lightcontroller.hpp @@ -32,9 +32,10 @@ namespace SceneUtil LightType mType; osg::Vec4f mDiffuseColor; float mPhase; - float mDeltaCount; - int mDirection; + float mBrightness; + double mStartTime; double mLastTime; + float mTicksToAdvance; }; }