我需要制作它,这样我的Qml视图的一部分就被一些非Qt OpenGL渲染"接管"了,而且我在正确显示纹理方面遇到了问题,所以我想我只需要画一条线,然后再处理更复杂的代码。
对于那些不熟悉Qt5的人来说,整个窗口都是使用OpenGL绘制的,我正在使用QQuickWindow::beforeRendering((信号连接Qt的OpenGL绘制机制,这意味着我的绘制代码在每次重绘(每次垂直同步(时都会执行。
我取了Squircle样本代码(http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html(,并对其进行了轻微修改,使其能够绘制屏幕的指定部分(而不是整个屏幕(,这是完美的。然后,我只修改了renderer::paint((函数,最初画三条绿色线,2秒钟后改为画一条蓝色线:
void CtRenderer::paint()
{
static int n = 0;
if (n == 0)
{
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
// glClearColor(1, 0, 0, 1);
// glClear(GL_COLOR_BUFFER_BIT);
glLineWidth(10);
glColor4f(0.0, 1.0, 0.0, 1);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 1); glVertex3f(1, 0.5, 1);
glVertex3f(0.0, 0.0, 1); glVertex3f(0.5, 0.5, 1);
glVertex3f(0.0, 0.0, 1); glVertex3f(0.5, 1, 1);
glEnd();
}
else if (n == 120)
{
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
// glClearColor(1, 0, 0, 1);
// glClear(GL_COLOR_BUFFER_BIT);
glLineWidth(10);
glColor4f(0.0, 0.0, 1.0, 1);
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 1); glVertex3f(0.4, 0.8, 1);
glEnd();
}
n++;
return;
}`
相反,我得到的是三条灰色的线,它们不断闪烁,永远不会变成一条线。经过一些在线研究,我认为也许我不应该使用glBegin((/glEnd((,所以我更改了代码:
void CtRenderer::paint()
{
static bool bOnce = true;
if (bOnce)
{
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
float vertices[] = {-0.5f, -0.5f, 0.5f, 0.5f};
glLineWidth(10);
glColor4f(0.0, 1.0, 0.0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_LINES, 0, 2);
glDisableClientState(GL_VERTEX_ARRAY);
bOnce = false;
}
return;
}
这仍然给我一条闪烁的灰色线。
当我在Qt之外的一个简单的GLUT应用程序中尝试这个代码时,它运行得很好,所以OpenGL和Qt5-Qml之间似乎有一些交互。我下一步可以尝试什么?
附言:我在Linux Ubuntu盒子上使用Qt 5.3版本
p.p.s.为了回应一些评论,我更新了我的代码,如下所示:
void dumpGlErrors(int iLine)
{
for (;;)
{
GLenum err = glGetError();
if (err == GL_NO_ERROR)
return;
std::cout << "GL error " << err << " detected in line " << iLine << std::endl;
}
}
void CtRenderer::paint()
{
glPushMatrix();
glLoadIdentity();
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
dumpGlErrors(__LINE__);
glClearColor(1, 0, 1, 1); // Magenta
glClear(GL_COLOR_BUFFER_BIT);
bool bDepth = glIsEnabled(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);
bool bLighting = glIsEnabled(GL_LIGHTING);
glDisable(GL_LIGHTING);
bool bTexture = glIsEnabled(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_2D);
dumpGlErrors(__LINE__);
float vertices[] = { -0.5f, -0.5f, 0.1f, 0.5f, 0.5f, 0.1f, 0.5f, 0.5f, 1.0f, 0.5f, -0.5f, 1.0f };
float colors[] = { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f };
glLineWidth(10);
glColor4f(0.0, 0.0, 1.0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, colors);
dumpGlErrors(__LINE__);
glDrawArrays(GL_LINES, 0, 4); // 4, not 2.
dumpGlErrors(__LINE__);
// glFlush();
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
if (bTexture)
glEnable(GL_TEXTURE_2D);
if (bLighting)
glEnable(GL_LIGHTING);
if (bDepth)
glEnable(GL_DEPTH_TEST);
glPopMatrix();
dumpGlErrors(__LINE__);
// In case somebody else calls glClear()
glClearColor(0, 1, 1, 1); // Cyan
}
现在我得到了一个很好的品红色背景,我看到我的线闪烁了一次,然后它消失了,我只剩下品红色。
p.p.p.s.我尝试使用VBO类型的函数:
class Point
{
public:
float m_vertex[3];
float m_color[4];
};
void SquircleRenderer::drawBuffer()
{
QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
if (!m_bBufInit)
{
std::cout << "SquircleRenderer::drawBuffer()" << std::endl;
// Adding these two lines doesn't change anything
/*
glFuncs.initializeOpenGLFunctions();
glFuncs.glUseProgram(0);
*/
// Create a new VBO
glFuncs.glGenBuffers(1, &m_buf);
// Make the new VBO active
glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_buf);
static const Point points[4] = {
{ { -0.5f, -0.5f, 0.1f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
{ { 0.5f, 0.5f, 0.1f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
{ { 0.5f, 0.5f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } },
{ { 0.5f, -0.5f, 1.0f }, { 1.0f, 1.0f, 0.0f, 1.0f } }
};
// Upload vertex data to the video device
glFuncs.glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Point), points, GL_STATIC_DRAW);
dumpGlErrors(__LINE__);
m_bBufInit = true;
}
glPushMatrix();
glLoadIdentity();
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glClearColor(1, 1, 0, 1); // Yellow
glClear(GL_COLOR_BUFFER_BIT);
glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_buf);
dumpGlErrors(__LINE__);
/*
* "If a non-zero named buffer object is bound to the GL_ARRAY_BUFFER target
* (see glBindBuffer) while a vertex array is
* specified, pointer is treated as a byte offset into the buffer object's data store"
*/
glLineWidth(10);
glColor4f(0.0, 0.0, 1.0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Point), 0);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(Point), (void*)offsetof(Point, m_color));
dumpGlErrors(__LINE__);
glDrawArrays(GL_LINES, 0, 4); // 4, not 2.
dumpGlErrors(__LINE__);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// In case somebody else calls glClear()
glClearColor(0, 1, 1, 1); // Cyan
glPopMatrix();
dumpGlErrors(__LINE__);
}
和我所有的其他努力一样,我得到了一个黄色背景,我的线条出现了1/60秒,然后线条消失了,我只有黄色背景。
我发现了答案:我必须告诉Qt我正在使用旧的固定函数管道。在绘制任何图形之前调用一个函数就可以了:
QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
glFuncs.glUseProgram(0);
使用Qt Quick有三种方法可以混合OpenGL:
- 您可以在下绘制(整个(QML(请参阅http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html)
- 您可以在(整个(QML上绘制
- 您可以提供绘制在QML元素上的OpenGL纹理(请参见http://qt-project.org/doc/qt-5/qsgsimpletexturenode.html)
或者,您可以构建一个QWidget应用程序,并在QWidget窗口中使用OpenGL,在另一个窗口(QML窗口小部件窗口(中使用QML。
void SquircleRenderer::paint()
{
if (!m_program) {
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 aVertices;"
"attribute highp vec4 aColors;"
"varying highp vec4 vColors;"
"void main() {"
" gl_Position = aVertices;"
" vColors= aColors;"
"}");
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
"varying highp vec4 vColors;"
"void main() {"
" gl_FragColor = vColors;"
"}");
m_program->bindAttributeLocation("aVertices", 0);
m_program->bindAttributeLocation("aColors", 1);
m_program->link();
}
m_program->bind();
m_program->enableAttributeArray(0);
m_program->enableAttributeArray(1);
float vertices[] = {
-1, -1, //Diag bottom left to top right
1, 1,
-1, 1, //Diag top left to bottom right
1, -1,
-1, 0, //Horizontal line
1, 0
};
float colors[] = {
1, 1, 0, 1,
1, 0, 1, 1,
0, 1, 1, 1,
1, 0, 0, 1,
0, 0, 1, 1,
0, 1, 0, 1
};
m_program->setAttributeArray(0, GL_FLOAT, vertices, 2); //3rd to 0, 4th to 1 by default
m_program->setAttributeArray(1, GL_FLOAT, colors, 4);
glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
glDisable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
//Here I draw 3 lines, reduce to 2 instead of 6 to draw only one.
//Change second param to choose which line to draw
glDrawArrays(GL_LINES, 0, 6);
m_program->disableAttributeArray(0);
m_program->disableAttributeArray(1);
m_program->release();
}
我的结论是将OpenGL的遗留版本留在历史书中。即使是像这样的虚拟着色器,也可以省去管理任何矩阵的麻烦,而且您知道发生了什么。
附言:这个代码还没有经过测试,它只是Squircle代码的一个调整。如果有问题,请告诉我,但我宁愿从这段代码继续进行故障排除会话。