ImGui histogram container improvements (#4630)

* Added auto scale mode that uses a running average to expand and shrink the visible vertical range.
* Added option to set the move direction and either push new values to the front of the buffer (left) and make the histogram move to the right or the inverse.
* Changed the camera monitor to use auto scaling as well as the current one was not showing anything because of an outlier.
* Pre-fill the histogram with zeros so that the first pushed sample moves in without horizontal scaling effects which made it hard to read out any information from the histogram.

Signed-off-by: Benjamin Jillich <jillich@amazon.com>
This commit is contained in:
Benjamin Jillich
2021-10-13 09:57:15 +02:00
committed by GitHub
parent 2b79abb8c4
commit da1fde8314
3 changed files with 120 additions and 30 deletions
@@ -18,8 +18,7 @@ namespace ImGui
namespace LYImGuiUtils
{
/**
* A small class to help manage values for an ImGui Histogram ( ImGui doesn't want to manage the values itself ).
* Nothing crazy, just helps reduce boiler plate if you are ImGui::PlotHistogram()'ing
* A small class to help manage values for an ImGui Histogram (ImGui is not managing values itself).
*/
class HistogramContainer
{
@@ -40,9 +39,24 @@ namespace ImGui
// Static Type to String function
static const char* ViewTypeToString(ViewType viewType);
//! Horizontal move direction of the histogram when pushing new values.
enum MoveDirection : AZ::u8
{
PushLeftMoveRight = 0, //! Push new values to the front of the buffer, which corresponds to the left side, and make the histogram move to the right.
PushRightMoveLeft = 1, //! Push new values to the back of the buffer, which corresponds to the right side, and make the histogram move to the left.
};
//! Mode determining the min and max values for the visible range of the vertical axis for the histogram.
enum ScaleMode : AZ::u8
{
NoAutoScale = 0, //! Use the min and max values given by Init() as visible range.
AutoExpand = 1, //! Expand scale in case a sample is out of the current bounds. Does only expand the scale but not decrease it back again.
AutoScale = 2, //! Use a running average to expand and shrink the visible range.
};
// Do all of the set up via Init
void Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale
, bool autoExpandScale, bool startCollapsed = false, bool drawMostRecentValue = true);
void Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale,
ScaleMode scaleMode = AutoScale, bool startCollapsed = false, bool drawMostRecentValue = true);
// How many values are in the container currently
int GetSize() { return static_cast<int>(m_values.size()); }
@@ -50,9 +64,6 @@ namespace ImGui
// What is the max size of the container
int GetMaxSize() { return m_maxSize; }
// Set the Max Size and clear the container
void SetMaxSize(int size) { m_values.clear(); m_maxSize = size; }
// Push a value to this histogram container
void PushValue(float val);
@@ -65,7 +76,18 @@ namespace ImGui
// Draw this histogram with ImGui
void Draw(float histogramWidth, float histogramHeight);
//! Adjust the scale mode to determine the min and max values for the visible range of the vertical axis for the histogram.
void SetScaleMode(ScaleMode scaleMode) { m_scaleMode = scaleMode; }
//! Adjust the horizontal move direction of the histogram when pushing new values.
void SetMoveDirection(MoveDirection moveDirection) { m_moveDirection = moveDirection; }
//! Calculate the min and maximum values for the present samples.
void CalcMinMaxValues(float& outMin, float& outMax);
private:
// Set the Max Size and clear the container
void SetMaxSize(int size);
AZStd::string m_histogramName;
AZStd::deque<float> m_values;
@@ -73,8 +95,10 @@ namespace ImGui
ViewType m_viewType = ViewType::Histogram;
float m_minScale;
float m_maxScale;
MoveDirection m_moveDirection = PushLeftMoveRight; //! Specify if values will be added on the left and the histogram moves right or the other way around.
bool m_dispalyOverlays;
bool m_autoExpandScale;
ScaleMode m_scaleMode; //! Determines if the vertical range of the histogram will be manually specified, auto-expanded or automatically scaled based on the samples.
float m_autoScaleSpeed = 0.05f; //! Indicates how fast the min max values and the visible vertical range are adapting to new samples.
bool m_collapsed;
bool m_drawMostRecentValueText;
};
@@ -34,13 +34,13 @@ namespace ImGui
ImGuiCameraMonitorRequestBus::Handler::BusConnect();
// Init Histogram Containers
m_dofMinZHisto.Init( "DOF Min Z", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true);
m_dofMinZBlendMultHisto.Init( "DOF Min Z Blend Mult", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f, true);
m_dofMinZScaleHisto.Init( "DOF Min Z Scale", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f, true);
m_dofMinZHisto.Init( "DOF Min Z", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f);
m_dofMinZBlendMultHisto.Init( "DOF Min Z Blend Mult", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f);
m_dofMinZScaleHisto.Init( "DOF Min Z Scale", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f);
m_globalActiveCamInfo.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f, true);
m_globalActiveCamInfo.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true);
m_globalActiveCamInfo.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true);
m_globalActiveCamInfo.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f);
m_globalActiveCamInfo.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f);
m_globalActiveCamInfo.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f);
}
void ImGuiLYCameraMonitor::Shutdown()
@@ -214,7 +214,7 @@ namespace ImGui
}
// save this cam off as the current one
m_currentCamera = newCamId;
// create a new empty CameraInfo in the queue
m_cameraHistory.push_front(CameraInfo());
@@ -224,9 +224,9 @@ namespace ImGui
AZ::ComponentApplicationBus::BroadcastResult(newCam.m_camName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_currentCamera);
newCam.m_activeTime = 0.0f;
newCam.m_activeFrames = 0;
newCam.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f, true);
newCam.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true);
newCam.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true);
newCam.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f);
newCam.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f);
newCam.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f);
// reset a few variables on the global camera info
m_globalActiveCamInfo.m_camId = newCam.m_camId;
@@ -16,45 +16,92 @@ namespace ImGui
{
namespace LYImGuiUtils
{
void HistogramContainer::Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale
, bool autoExpandScale, bool startCollapsed/* = false*/, bool drawMostRecentValue/* = true*/)
void HistogramContainer::Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale,
ScaleMode scaleMode, bool startCollapsed/* = false*/, bool drawMostRecentValue/* = true*/)
{
m_histogramName = histogramName;
m_minScale = minScale;
m_maxScale = maxScale;
m_viewType = viewType;
m_dispalyOverlays = displayOverlays;
m_autoExpandScale = autoExpandScale;
m_scaleMode = scaleMode;
m_collapsed = startCollapsed;
m_drawMostRecentValueText = drawMostRecentValue;
SetMaxSize(maxValueCountSize);
}
void HistogramContainer::PushValue(float val)
void HistogramContainer::SetMaxSize(int size)
{
m_values.resize(size);
m_maxSize = size;
// Pre-fill the histogram with zeros so that the bars do not fill the space and
// scale horizontally when there are not enough samples yet.
for (float& value : m_values)
{
value = 0.0f;
}
}
void HistogramContainer::PushValue(float value)
{
if (m_maxSize == 0)
{
return;
}
if (m_values.size() == m_maxSize)
{
m_values.pop_back();
if (m_moveDirection == PushLeftMoveRight)
{
m_values.pop_back();
}
else
{
m_values.pop_front();
}
}
else if (m_values.size() > m_maxSize)
{
m_values.erase(m_values.begin() + (m_maxSize - 1), m_values.end());
}
m_values.push_front(val);
if (m_autoExpandScale)
if (m_moveDirection == PushLeftMoveRight)
{
if (val < m_minScale)
m_values.push_front(value);
}
else
{
m_values.push_back(value);
}
switch (m_scaleMode)
{
case AutoExpand:
{
m_minScale = val;
if (value < m_minScale)
{
m_minScale = value;
}
else if (value > m_maxScale)
{
m_maxScale = value;
}
break;
}
else if (val > m_maxScale)
case AutoScale:
{
m_maxScale = val;
float min = 0.0f;
float max = 0.0f;
CalcMinMaxValues(min, max);
m_minScale = AZ::Lerp(m_minScale, min, m_autoScaleSpeed);
m_maxScale = AZ::Lerp(m_maxScale, max, m_autoScaleSpeed);
break;
}
default:
{
break;
}
}
}
@@ -86,7 +133,6 @@ namespace ImGui
ImGui::DragInt("History Size", &m_maxSize, 1, 1, 1000, "%f");
ImGui::DragFloat("Max Scale", &m_maxScale, 0.0001f, -100.0f, 100.0f);
ImGui::DragFloat("Min Scale", &m_minScale, 0.0001f, -100.0f, 100.0f);
ImGui::Checkbox("Auto Expand Scale", &m_autoExpandScale);
ImGui::EndPopup();
}
@@ -157,6 +203,26 @@ namespace ImGui
return "Lines";
}
}
void HistogramContainer::CalcMinMaxValues(float& outMin, float& outMax)
{
// Use the manually set min and max scale values in case there are no samples.
if (m_values.empty())
{
outMin = m_minScale;
outMax = m_maxScale;
return;
}
outMin = +AZ::Constants::FloatMax;
outMax = -AZ::Constants::FloatMax;
for (const float x : m_values)
{
outMin = AZ::GetMin(outMin, x);
outMax = AZ::GetMax(outMax, x);
}
}
}
}
#endif // #ifdef IMGUI_ENABLED