中望3D 2025 Linux版在4k高分辨率屏下3D渲染异常

名片

vowstar

中望学前班lv1

需求:

BUG:

已完成:

进行中:

BUG 热度

  • 需求ID: SUP-78320
  • 需求状态: 进行中 已完成

产品版本:中望3D 2025 Linux版

BUG复现步骤:

1. 使用Linux系统,并同时使用4k分辨率的屏幕,设置到高分辨率(3840×2160)。

2. 设置全局环境变量QT_AUTO_SCREEN_SCALE_FACTOR=1,使得QT应用程序自适应当前分辨率。

3. 打开中望3D 2025 Linux版(zw3d-2025.0.3.0),随意打开一个3D设计文件。

4. 此时,界面其他部分显示正常,但是渲染的图像只显示在左下角,占整个渲染区域的 1/4 左右。

期望结果:

渲染区域正确显示。

技术背景:

该问题是QT与openGL开发常见的已知问题,即QT OpenGLWidget高分屏适配时出现的问题。见参考文档。

为了解决4K屏幕显示QT界面时出现窗口变小分辨率不匹配的问题,我们可以设置环境变量QT_AUTO_SCREEN_SCALE_FACTOR=1 (它将使能Qt::AA_EnableHighDpiScaling), 或者在 QApplication a(argc, argv); 这句之前添加:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

Constant Value Description
Qt::AA_EnableHighDpiScaling 20 Enables high-DPI scaling in Qt on supported platforms (see also High DPI Displays). Supported platforms are X11, Windows and Android. Enabling makes Qt scale the main (device independent) coordinate system according to display scale factors provided by the operating system. This corresponds to setting the QT_AUTO_SCREEN_SCALE_FACTOR environment variable to 1. This attribute must be set before QGuiApplication is constructed. This value was added in Qt 5.6.
运行结果显示其他界面均运行正常,但是在 QOpenGLWidget 内,渲染的图像只显示在左下角,占整个渲染区域的 1/4 左右。
其原因是启用 AA_EnableHighDpiScaling 后,QOpenGLWidget 内部的 OpenGL 不归属于 QT 的缩放范围,所以我们需要自己缩放 QOpenGLWidget 内的像素尺寸。
解决方案:
解决的方法就是自行获取 devicePixelRatio,手动进行缩放。实现的方式大致有两种,具体取决于你 QOpenGLWidget 裁剪的方式。ratio 可以通过 QApplication::desktop()->devicePixelRatio(); 获取。
如果是通过 resizeGL(int width, int height) 裁剪,缩放就应写在其中。
以下代码参考了博文 https://blog.csdn.net/genispan/article/details/107864829
void QOpenGLWidget::resizeGL(int width, int height)
{
makeCurrent();
//参数X,Y指定了视见区域的左下角在窗口中的位置,一般情况下为(0,0),Width和Height指定了视见区域的宽度和高度。
    int ratio = QApplication::desktop()->devicePixelRatio();
glViewport(0, 0, (GLint)width*ratio, (GLint)height*ratio);
/*
glMatrixMode设置当前矩阵模式:
GL_MODEVIEW,对模型视景矩阵堆栈应用随后的矩阵操作。
GL_PROJECTION,对投影矩阵应用随后的矩阵操作。
GLTEXTURE,对纹理矩阵堆栈应用随后的矩阵操作。
*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glOrtho 参数分别代表(左下角x坐标,右上角x坐标,左下角y坐标,右上角y坐标)——坐标全相对于窗口左下角--原点)
glOrtho(0, width*ratio, -height*ratio, 0, 0, 1); ///防止图像上下翻转
glMatrixMode(GL_MODELVIEW);
recalculatePosition();
emit imageSizeChanged(mRenderWidth, mRenderHeight);
updateScene();
}
裁剪实现在对输入纹理的处理的话,相应的代码应该写到 paintGL() 内:
void QOpenGLWidget::initializeGL(){
    …
    QScreen *pScreen = QApplication::desktop()->screen(screenNum)->screen();
static const qreal NORMAL_DPI = 95.863739404014453;
auto xFactor = pScreen->logicalDotsPerInchX() / NORMAL_DPI;
auto yFactor = pScreen->logicalDotsPerInchY() / NORMAL_DPI;
auto ratio = pScreen->devicePixelRatio();
_xRatio = xFactor * ratio;
_yRatio = yFactor * ratio;
}
void QOpenGLWidget::paintGL() {
    …
    widgetWidth *= _xRatio;
widgetHeight *= _yRatio;
    //QImage对象img即为输入纹理
    auto img = currImg;
if (!currImg.isNull()) {
img = img.scaled(widgetWidth, widgetHeight, Qt::KeepAspectRatio);
img = img.copy((img.width() – widgetWidth) / 2, (img.height() – widgetHeight) / 2, widgetWidth, widgetHeight);
    }
    …
}
裁剪过后QOpenGLWidget应该就能正常显示了。
参考链接1:https://doc.qt.io/qt-5/qt.html#ApplicationAttribute-enum
参考链接2: https://www.cnblogs.com/zhxmdefj/p/14062243.html
3 条评论 A文章作者 M管理员
  1. Jasmine

    收到!非常详尽!感谢!请问可以提供一下软件版本号吗?

    • vowstar

      版本 : 中望3D 2025(29.05) VERNUM:12/11/2024(134631:b728853d73_Dev)

    • Jasmine

      收到!感谢!我立即向研发反馈!

购物车
优惠劵
今日签到
有新私信 私信列表
搜索
复制链接
微信扫码
已复制到剪贴板