Fix viewport icon rendering on high DPI devices (#1006)

* Clarify ViewportWorldToScreen being in widget space and add DeviceScalingFactor

* -Fix viewport icons being draw wrong on high DPI displays
-Fix loading viewport icons from absolute paths, which

* Address review feedback, fix build
This commit is contained in:
Nicholas Van Sickle
2021-05-27 16:31:30 -07:00
committed by GitHub
parent 16286fb43b
commit 5e87250f67
8 changed files with 53 additions and 20 deletions
@@ -41,6 +41,7 @@ namespace AzManipulatorTestFramework
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override;
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(
const AzFramework::ScreenPoint& screenPosition) override;
float DeviceScalingFactor() override;
private:
// ViewportInteractionRequestBus ...
bool GridSnappingEnabled();
@@ -127,4 +127,9 @@ namespace AzManipulatorTestFramework
{
return {};
}
} // namespace AzManipulatorTestFramework
float ViewportInteraction::DeviceScalingFactor()
{
return 1.0f;
}
}// namespace AzManipulatorTestFramework
@@ -165,15 +165,18 @@ namespace AzToolsFramework
virtual bool AngleSnappingEnabled() = 0;
/// Return the angle snapping/step size.
virtual float AngleStep() = 0;
/// Transform a point in world space to screen space coordinates.
/// Transform a point in world space to screen space coordinates in Qt Widget space.
/// Multiply by DeviceScalingFactor to get the position in viewport pixel space.
virtual AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) = 0;
/// Transform a point in screen space coordinates to a vector in world space based on clip space depth.
/// Transform a point from Qt widget screen space to world space based on the given clip space depth.
/// Depth specifies a relative camera depth to project in the range of [0.f, 1.f].
/// Returns the world space position if successful.
virtual AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) = 0;
/// Casts a point in screen space to a ray in world space originating from the viewport camera frustum's near plane.
/// Returns a ray containing the ray's origin and a direction normal, if successful.
virtual AZStd::optional<ProjectedViewportRay> ViewportScreenToWorldRay(const AzFramework::ScreenPoint& screenPosition) = 0;
/// Gets the DPI scaling factor that translates Qt widget space into viewport pixel space.
virtual float DeviceScalingFactor() = 0;
protected:
~ViewportInteractionRequests() = default;
+1
View File
@@ -200,6 +200,7 @@ public:
{
return {};
}
float DeviceScalingFactor() override { return 1.0f; }
// AzToolsFramework::ViewportFreezeRequestBus
bool IsViewportInputFrozen() override;
@@ -98,6 +98,7 @@ namespace AtomToolsFramework
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override;
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(
const AzFramework::ScreenPoint& screenPosition) override;
float DeviceScalingFactor() override;
//! Set interface for providing viewport specific settings (e.g. snapping properties).
void SetViewportSettings(const AzToolsFramework::ViewportInteraction::ViewportSettings* viewportSettings);
@@ -313,8 +313,7 @@ namespace AtomToolsFramework
// Scale the size by the DPI of the platform to
// get the proper size in pixels.
const QSize uiWindowSize = size();
const qreal deficePixelRatio = devicePixelRatioF();
const QSize windowSize = uiWindowSize * deficePixelRatio;
const QSize windowSize = uiWindowSize * devicePixelRatioF();
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
@@ -465,6 +464,11 @@ namespace AtomToolsFramework
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
}
float RenderViewportWidget::DeviceScalingFactor()
{
return aznumeric_cast<float>(devicePixelRatioF());
}
AzFramework::ScreenPoint RenderViewportWidget::ViewportCursorScreenPosition()
{
return AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(m_mousePosition.toPoint());
@@ -18,6 +18,7 @@
#include <AzCore/std/containers/array.h>
#include <AzFramework/Asset/AssetSystemBus.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
@@ -145,12 +146,24 @@ namespace AZ::Render
}
// Initialize our shader
auto viewportSize = viewportContext->GetViewportSize();
AZ::Vector2 viewportSize;
{
AzFramework::WindowSize viewportWindowSize = viewportContext->GetViewportSize();
viewportSize = AZ::Vector2{aznumeric_cast<float>(viewportWindowSize.m_width), aznumeric_cast<float>(viewportWindowSize.m_height)};
}
AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> drawSrg = dynamicDraw->NewDrawSrg();
drawSrg->SetConstant(m_viewportSizeIndex, AZ::Vector2(aznumeric_cast<float>(viewportSize.m_width), aznumeric_cast<float>(viewportSize.m_height)));
drawSrg->SetConstant(m_viewportSizeIndex,viewportSize);
drawSrg->SetImageView(m_textureParameterIndex, image->GetImageView());
drawSrg->Compile();
// Scale icons by screen DPI
float scalingFactor = 1.0f;
{
using ViewportRequestBus = AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus;
ViewportRequestBus::EventResult(
scalingFactor, drawParameters.m_viewport, &ViewportRequestBus::Events::DeviceScalingFactor);
}
AZ::Vector3 screenPosition;
if (drawParameters.m_positionSpace == CoordinateSpace::ScreenSpace)
{
@@ -158,9 +171,11 @@ namespace AZ::Render
}
else if (drawParameters.m_positionSpace == CoordinateSpace::WorldSpace)
{
using ViewportRequestBus = AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus;
AzFramework::ScreenPoint position;
ViewportRequestBus::EventResult(position, drawParameters.m_viewport, &ViewportRequestBus::Events::ViewportWorldToScreen, drawParameters.m_position);
// Calculate our screen space position using the viewport size
// We want this instead of RenderViewportWidget::WorldToScreen which works in QWidget virtual coordinate space
AzFramework::ScreenPoint position = AzFramework::WorldToScreen(
drawParameters.m_position, viewportContext->GetCameraViewMatrix(), viewportContext->GetCameraProjectionMatrix(),
viewportSize);
screenPosition.SetX(aznumeric_cast<float>(position.m_x));
screenPosition.SetY(aznumeric_cast<float>(position.m_y));
}
@@ -179,8 +194,8 @@ namespace AZ::Render
{
Vertex vertex;
screenPosition.StoreToFloat3(vertex.m_position);
vertex.m_position[0] += offsetX * drawParameters.m_size.GetX();
vertex.m_position[1] += offsetY * drawParameters.m_size.GetY();
vertex.m_position[0] += offsetX * drawParameters.m_size.GetX() * scalingFactor;
vertex.m_position[1] += offsetY * drawParameters.m_size.GetY() * scalingFactor;
vertex.m_color = drawParameters.m_color.ToU32();
vertex.m_uv[0] = u;
vertex.m_uv[1] = v;
@@ -197,8 +212,15 @@ namespace AZ::Render
dynamicDraw->DrawIndexed(&vertices, vertices.size(), &indices, indices.size(), RHI::IndexFormat::Uint16, drawSrg);
}
QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& sourceRelativePath) const
QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& path) const
{
// If we get an absolute path, just use it.
QFileInfo pathInfo(path);
if (pathInfo.isAbsolute())
{
return path;
}
bool found = false;
AZStd::vector<AZStd::string> scanFolders;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
@@ -212,9 +234,9 @@ namespace AZ::Render
for (const auto& folder : scanFolders)
{
QDir dir(folder.data());
if (dir.exists(sourceRelativePath))
if (dir.exists(path))
{
return dir.absoluteFilePath(sourceRelativePath);
return dir.absoluteFilePath(path);
}
}
@@ -256,10 +278,6 @@ namespace AZ::Render
AzToolsFramework::EditorViewportIconDisplayInterface::IconId AtomViewportDisplayIconsSystemComponent::GetOrLoadIconForPath(
AZStd::string_view path)
{
AZ_Error(
"AtomViewportDisplayIconsSystemComponent", AzFramework::StringFunc::Path::IsRelative(path.data()),
"GetOrLoadIconForPath assumes that it will always be given a relative path, but got '%s'", path.data());
// Check our cache to see if the image is already loaded
auto existingEntryIt = AZStd::find_if(m_iconData.begin(), m_iconData.end(), [&path](const auto& iconData)
{
@@ -61,7 +61,7 @@ namespace AZ
static constexpr QSize MinimumRenderedSvgSize = QSize(128, 128);
static constexpr QImage::Format QtImageFormat = QImage::Format_RGBA8888;
QString FindAssetPath(const QString& sourceRelativePath) const;
QString FindAssetPath(const QString& path) const;
QImage RenderSvgToImage(const QString& svgPath) const;
AZ::Data::Instance<AZ::RPI::Image> ConvertToAtomImage(AZ::Uuid assetId, QImage image) const;