Qt 3D的研究(二)
上一篇文章给大家看了很多Qt 3D的例子,如果大家有Qt 3D的源代码,就会发现,开发这些例子,花费的代码还真不少。这就是不一样的地方,Qt 3D毕竟和三维图形打交道,多了一个维度,问题的难度变得更大了。
蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/details/43801957。欢迎同行前来探讨。
研究了多日的Qt 3D,我了解到为了适应跨平台、不同的着色器编译器标准、多重渲染目标,Qt 3D提出了很多的方案,创新了许多的概念,这多多少少让初学者感到困难重重。在与Qt开发者经过jira以及IRC等交流后,我了解到了如何使用Qt 3D构建一个简单的程序。
这个程序呢,虽然说简单,但是是Qt 3D中精简的最少代码了。让我们首先看看main.qml。
import Qt3D 2.0 import Qt3D.Render 2.0 Entity { components: FrameGraph { ForwardRenderer { clearColor: Qt.rgba( 0.2, 0, 0, 1 ) } } }
Qt 3D和其它的库不一样,它的main.qml放的是Entity,而不是我们常见的Window或者ApplicationWindow。其次,我们看到他里面没有QtQuick的引用。这个可能因为Qt3D不直接建立在QtQuick上,而是建立在了QtQml模块上,所以提供了QML的语法,但是我们看不见常见的QtQuick类型比如说Item什么的。这两个变化是第一眼看出来比较明显的。
接下来介绍一下Qt 3D的FrameGraph,前段时间我为了深入研究QtQuick的渲染,曾经研究了Qt的SceneGraph框架。后面发现在SceneGraph下进行渲染,还是有种种限制,无法更好地渲染出漂亮的3D图形出来。于是,我开始离开Scene Graph,转向使用原生OpenGL进行渲染,以及开始接触Qt3D的FrameGraph。在介绍Qt3D的英文博客中,作者更是说明,SceneGraph能让我们用数据驱动的方式告诉我们要渲染什么东西,而Frame Graph能让我们用数据驱动的方式告诉我们怎样渲染。这是一个比较大,也比较难的转变。尝试做一个Qt 3D框架的人都有此感。想要拥有一个什么都可以configurable(可配置)的框架,自己制作起来是多么难。FrameGraph,则是告诉底层渲染器,我们需要怎样渲染,效果是怎么样的。在FrameGraph中,只有ForwardRenderer,告诉我们按照普通前向渲染的方式进行。里面我们指定了一个刷新的颜色。估计是采用glClearColor这个API指定的吧。
接下来我们转向C++。C++这边也和普通的Quick程序不一样了。
#include <QApplication> #include <QDesktopWidget> #include <QQmlApplicationEngine> #include <Window> #include <QRenderAspect> #include <QInputAspect> #include <QQmlAspectEngine> int main(int argc, char *argv[]) { QApplication app(argc, argv); Qt3D::Window window; Qt3D::Quick::QQmlAspectEngine engine; engine.aspectEngine( )->registerAspect( new Qt3D::QRenderAspect ); engine.aspectEngine( )->registerAspect( new Qt3D::QInputAspect ); engine.aspectEngine( )->initialize( ); QVariantMap data; data.insert( QStringLiteral( "surface" ), QVariant::fromValue( static_cast<QSurface*>( &window ) ) ); data.insert( QStringLiteral( "eventSource" ), QVariant::fromValue( &window ) ); engine.aspectEngine( )->setData( data ); engine.aspectEngine( )->initialize( ); engine.setSource( QUrl( "qrc:/main.qml" ) ); // 让窗口以一定的大小居中显示 int clientWidth = app.desktop( )->availableGeometry( ).width( ); int clientHeight = app.desktop( )->availableGeometry( ).height( ); int windowWidth = 480; int windowHeight = 320; window.setGeometry( ( clientWidth - windowWidth ) / 2, ( clientHeight - windowHeight ) / 2, windowWidth, windowHeight ); window.show( ); return app.exec( ); }
我们使用的引擎不是简单的QQmlApplicationEngine类,而是Qt3D::Quick::QqmlAspectEngine类。这里有一个重要的概念——面向方面。所以在其中你看到很多Aspect字眼。这是因为我们将一个实体(Entity)分成很多组件(Component),其中有很多组件组合起来成为一个方面,剩下的组成另外一个方面。比如说Qt 3D有核心方面、渲染方面、声音方面、输入方面、Quick渲染方面。它们被组成一个个库,根据用户的需求来链接。
当然,作为Qt 3D的核心,Qt 3D必须要一个窗口来显示。Qt3D自己封装了一个窗口,名叫Qt3D::Window,它也不继承QQuickWindow,而是继承它的父类QWindow。目前window的信息,还是需要显式写入引擎的data中。最后引擎设置一下qml文件,接下来设置一下窗口大小和方位就可以正常显示了。
程序的截图如下所示:
虽然不是那么激动人心,但是这的确是能运行Qt 3D程序最少的代码了。
想要了解更多Qt 3D的介绍,推荐大家看KDAB的博客。
原文:http://blog.csdn.net/gamesdev/article/details/43801957