在Qml场景下使用OpenGL渲染时出现奇怪的错误

时间:2014-02-19 02:46:17

标签: c++ qt opengl qml

作为一个爱好,我正在尝试使用OpenGL并使用Qt + OpenGL编写自己的愚蠢引擎。最后的成功是构建实体系统框架,它可以使用附加的物理引擎(BulletPhysics)渲染具有阴影的场景(通过渲染到纹理到RenderBuffer)。

之后我更新到Qt 5.2并完全由Qml表达(之前没有尝试使用它)。我对2d qml图形进行了一些实验,并决定使用qml作为用户界面,但拒绝2d项目并返回3d。我创建了新的qml项目,尝试在qml下呈现一些内容,如Scene Graph - OpenGL Under QML示例中所示。之后,我将旧代码从3d项目移动到新项目,进行了一些小的重构(不应该影响任何东西)。

在这一刻我厌倦了一些奇怪的虫子。似乎第一帧是根据需要渲染的,但之后就出现了问题。

Scene view 这是一个更少或更常规的框架(在任何移动之前)

在左上角我是输出深度缓冲区(阴影贴图)。在右上角我用qml制作一些自定义滚动条。我正在使用这个滚轮更改阴影贴图旋转和移动相机。当滚动条居中时,没有任何动作。当我改变某些东西时,场景变得难看,我不知道为什么。

Scene view after some shadow map rotate 这是一些阴影贴图旋转后的帧

我看到阴影贴图深度缓冲区未更改(为什么?o_0)并且场景中的阴影出错。但是,在将旧代码重构为qml项目后,不仅阴影失败了。当我移动相机时,错误变得更加奇怪。

Scene after moving camera down (-Z) 这是向下移动相机后的帧(-Z)

使用以下命令在qml下呈现场景:

connect(window, &QQuickWindow::beforeRendering, this, &MyApp::renderScene, Qt::DirectConnection);

在renderScene中我:

  • 做一些OpenGL传送带设置(以防止Qml Scene Graph的更改,可能会过量);

    glViewport(0, 0, window->width(), window->height());
    
    glClearColor(0, 0, 0, 1);
    glClearDepth(1);
    glDepthRange(0,1);
    glDepthFunc(GL_LEQUAL);
    
  • 调用BulletPhysics计算物理(在测试场景中 - 两个下落的立方体)

  • 渲染阴影贴图(仅限深度)至RenderBuffer(2048x2048纹理,GL_DEPTH_COMPONENT24)
  • 将场景渲染为RenderBuffer(两个GL_RGBA8纹理用于颜色和法线,一个GL_DEPTH_COMPONENT24用于深度)
  • 渲染两个2d四边形 - 全屏(使用渲染缓冲区中的所有纹理进行场景渲染以使用阴影渲染)和侧面屏幕(深度缓冲区的左上角纹理)

我很想去捕捉正在发生的事情。 glGetError没有显示任何内容。

Scene with camera moved 通过XY轴再次移动相机。男人的角形轮廓仍然可见,并产生奇怪的效果

更多屏幕截图:

Old project 旧项目(不含qml)

Old project - big screenshot 旧项目(大截图)

Broken resize 在新项目中,窗口调整大小也被破坏

它有什么用?

环境:Qt Creator 3.0.0,Qt 5.2.0,Linux(Kubuntu 13.10)64位,HD 7750

OpenGL:在旧项目中我设置了3.3,新项目使用4.3(据我记得)

P.S。深度贴图失真,因为我在着色器中使用了一些额外的失真来改善场景中心的阴影。

1 个答案:

答案 0 :(得分:4)

在一天没有回答和许多前几天之后,我得到了灵感!

我怀疑深度缓冲区出了问题,并尝试输出调试用于渲染到用于渲染到全屏四边形的纹理ID。我尝试关闭渲染到纹理缓冲区交换等等。但我甚至不认为真正的问题出在Qml那边。

    glDepthMask(GL_TRUE); // 42!

这一行就像42 - 回答所有问题。似乎Qml在第一个渲染帧之前调用glDepthMask(GL_FALSE);(但是在发出&QQuickWindow::beforeRendering信号之后)。这个调用的结果是只有第一个我的帧真正渲染了写入深度缓冲区。为什么我认为glDepthMask(GL_FALSE);只被调用一次?因为插入“42”后FPS明显减少,并且在我用于渲染场景的插槽末尾插入glDepthMask(GL_FALSE);后增加了。

现在我可以自由旋转“太阳”(阴影)并在没有任何视觉错误的情况下移动相机。

yippee的!

Result in new project

相关问题