如何使 OpenGL 视口具有渲染到其中的 QML 项目的确切大小和位置?
Posted
技术标签:
【中文标题】如何使 OpenGL 视口具有渲染到其中的 QML 项目的确切大小和位置?【英文标题】:How to make OpenGL viewport have the exact size and position of my QML item which renders into it? 【发布时间】:2019-06-24 22:34:37 【问题描述】:我正在尝试在 1280x720
窗口内渲染 640x360
红色方块。问题是 OpenGL 的视口不会自动进入 Qt 窗口系统的正方形占据的区域内。也就是说,如果我的视频对象具有 640x360
尺寸,则 OpenGL 视口仍然具有 1280x720
尺寸(为什么?)。
无论如何,我可以使用glViewport(this->x, this->y, this->width, this->height);
来解决这个问题。问题是在 OpenGL 中,坐标系的原点在左下角,this->x, this->y, this->width, this->height
来自 QML 语法中的对象坐标,原点在左上角。结果是这样的:
main.qml:
import QtQuick 2.0
import OpenGlVideoQtQuick2 1.0
Grid
columns: 2
spacing: 2
width: 1280
height: 720
OpenGlVideoQtQuick2
width: 640
height: 360
但是红色方块占据了第三格而不是第一格:
我可以轻松通过执行glViewport(this->x, WINDOW_HEIGHT-this->y, this->width, this->height);
来解决这个问题,其中WINDOW_HEIGHT
的值是720
,但是我认为我不应该相信 OpenGL 视口的大小始终为窗口,所以我应该得到 OpenGL 视口尺寸,但我认为这是不可能的。
我试过了
GLint dims[2] = 9999, 9999;
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, dims);
std::cout << "dimenson x:" << dims[0] << " dimenson y:" << dims[1] << std::endl;
这给了我dimenson x:8192 dimenson y:8192
,这对我来说毫无意义。
这里是OpenGL渲染代码:https://github.com/lucaszanella/QQuickPaintedItemBug/blob/0a8ef6b5229afa7113ec1e4e3838981042792329/OpenGlVideoQtQuick2.cpp
您可以在此处查看整个可构建项目:https://github.com/lucaszanella/QQuickPaintedItemBug/tree/0a8ef6b5229afa7113ec1e4e3838981042792329
【问题讨论】:
你看过Qt的例子吗? doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html @BenjaminT 据我了解,此示例将始终将视口置于坐标 (0,0) 中,并且将具有窗口*纵横比的大小,这不是我需要的。我需要它来显示我的 QML 项目的大小和位置 【参考方案1】:所以这里是伪代码的解决方案:
int w = item->width() * window->devicePixelRatio();
int h = item->height() * window->devicePixelRatio();
int x = item->x();
int y = window->height()* window->devicePixelRatio() - h - item->y()
glViewport(x, y, w, h);
我已经用 Qt Scene Graph - OpenGL Under QML 示例进行了测试。 以下是我所做的更改:
main.qml
Squircle
x: 80
y: 120
width: 160
height: 240
[...]
squircle.cpp
void Squircle::sync()
if (!m_renderer)
m_renderer = new SquircleRenderer();
connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection);
m_renderer->setViewportSize(this->size().toSize() * window()->devicePixelRatio());
m_renderer->setPosition(this->position().toPoint());
m_renderer->setT(m_t);
m_renderer->setWindow(window());
void SquircleRenderer::paint()
[...]
int y = (m_window->size()* m_window->devicePixelRatio()).height() - m_viewportSize.height() - m_position.y();
glViewport(m_position.x(), y, m_viewportSize.width(), m_viewportSize.height());
[...]
squircle.h
class SquircleRenderer : public QObject, protected QOpenGLFunctions
Q_OBJECT
public:
void setPosition(const QPoint &position) m_position = position;
[...]
private:
[...]
QPoint m_position;
;
结果如下:
【讨论】:
谢谢,它有点工作。但是您是否注意到窗口的其余部分仍然是黑色的?就像 OpenGL 仍在那个领域工作一样。你知道怎么去掉吗? @LucasZanella 它是黑色的,因为那里什么都没有。你希望它是什么样子? 但它隐藏了背景的颜色 @LucasZanella 它没有。在 Qt 完成任何渲染之前渲染您的 OpenGL 代码。所以事实上,如果你的应用程序中确实有一个明确的背景(例如,通过将 Grid 替换为 Rectangle),那么背景将呈现在你的 OpenGL 代码之上并隐藏它。让你感觉后台被隐藏的,是电话win->setClearBeforeRendering(false)
。此调用将阻止 Qt 呈现窗口的默认背景,但没有它,窗口背景将呈现在您的 OpenGL 之上。
@LucasZanella 我不认为你可以用你当前的设计来改进。另一种方法是将QSGSimpleMaterialShader
或QSGMaterialShader
与QSGGeometryNode
一起使用。有一个关于如何使用它的示例:doc.qt.io/qt-5/qtquick-scenegraph-simplematerial-example.html 如果你这样做,你的着色器应该像任何普通项目一样呈现在 QML 项目树内。您当前的设计无法做到这一点。以上是关于如何使 OpenGL 视口具有渲染到其中的 QML 项目的确切大小和位置?的主要内容,如果未能解决你的问题,请参考以下文章