Qt3D教程(二)初步顯示3D的內容
前一篇非常簡單,完全就沒有牽涉到3D的內容,它只是我們搭建3D應用的基本框架而已,而這一篇,我們將要利用它來初步地顯示3D的內容了!本次目的是將程序中間的內容替換成3D的視圖,而這一切也不過十幾行代碼。要不我們來試一試吧!
蔣彩陽原創文章,首發地址:http://blog.csdn.net/gamesdev/article/details/47131099。歡迎同行前來探討。
首先我們需要對我們的MainWindow.cpp文件進行修改,在此基礎上添加一些內容:
#include <QQmlAspectEngine>
#include <QRenderAspect>
#include <QInputAspect>
#include <QQmlContext>
#include <QWindow>
#include "MainWindow.h"
#include "ui_MainWindow.h"
class View3D: public QWindow
{
public:
View3D( QScreen* targetScreen = Q_NULLPTR ): QWindow( targetScreen )
{
setSurfaceType( QSurface::OpenGLSurface );
QSurfaceFormat format;
format.setSamples( 4 );
setFormat( format );
create( );
}
};
Settings::Settings( QObject* parent ): QObject( parent )
{
m_showModel = true;
}
void Settings::setShowModel( bool showModel )
{
if ( m_showModel == showModel ) return;
m_showModel = showModel;
emit showModelChanged( );
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
using namespace Qt3D;
using namespace Qt3D::Quick;
// 創建一個3D的視圖
// 1
View3D* view3D = new View3D;
// 2
QQmlAspectEngine* engine = new QQmlAspectEngine( this );
engine->aspectEngine( )->registerAspect( new QRenderAspect );
engine->aspectEngine( )->registerAspect( new QInputAspect );
// 3
QVariantMap data;
data.insert( QStringLiteral( "surface" ),
QVariant::fromValue( static_cast<QSurface*>( view3D ) ) );
data.insert( QStringLiteral( "eventSource" ),
QVariant::fromValue( view3D ) );
engine->aspectEngine( )->setData( data );
// 4
engine->qmlEngine( )->rootContext( )->setContextProperty( "_settings", &m_settings );
// 5
engine->aspectEngine( )->initialize( );
engine->setSource( QUrl( "qrc:/qml/main.qml" ) );
QVBoxLayout* l = qobject_cast<QVBoxLayout*>( ui->centralwidget->layout( ) );
l->insertWidget( 0, QWidget::createWindowContainer( view3D ) );
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_showModelButton_clicked()
{
bool show = m_settings.showModel( );
show = !show;
ui->showModelButton->setText( show? "隱藏模型": "顯示模型" );
m_settings.setShowModel( show );
}
這裏我們使用了QWindow來替代我們曾經使用的QWidget,並且使用了QWidget:: createWindowContainer()函數來將QWindow的內容嵌入QWidget框架中;緊接着我們在構造函數中創建了QQmlAspectEngine類實例,並且註冊了QRenderAspect和QInputAspect;隨後我們使用一個QVariantMap數據結構,將surface以及eventSource以鍵值對的形式存儲起來供QAspectEngine使用;接着作爲可選的內容,我們爲了讓C++這一部分控制QML,我們定義了一個Settings類,並且將m_settings注入QML環境作爲上下文變量;最後我們使用initialize()函數初始化QAspectEngine,並且指定了我們需要展示的場景數據:main.qml。
此外,當按鈕按下的時候,我們可以通過改變m_settings的屬性從而控制我們是否想要顯示模型。
同時我們還必須在main.qml中作一些設置:
import Qt3D 2.0
import Qt3D.Renderer 2.0
Entity
{
id: root
Camera
{
id: camera
position: Qt.vector3d( 0.0, 20.0, 100.0 )
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16.0 / 9.0
nearPlane : 0.1
farPlane : 1000.0
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 20.0, 0.0 )
}
components: FrameGraph
{
ForwardRenderer
{
clearColor: Qt.rgba( 0.2, 0, 0, 1 )
camera: camera
}
}
Entity
{
Mesh
{
id: chestMesh
source: "qrc:/assets/Chest.obj"
enabled: _settings.showModel
}
components: [ chestMesh ]
}
Configuration
{
controlledCamera: camera
}
}
如上面所示,我們在名爲root的Entity中定義了一個攝像機、一個實體,還有一些必要的設置。同時我們通過綁定_settings.showModel來控制Mesh的顯示或者隱藏。
本次教程的代碼均在我的github中,感興趣的同行們可以通過git clone或者是直接下載我的git項目來獲取到本套教程的所有源代碼。