canvas 3d學習一 應用結(jié)構(gòu)
Qt Canvas 3D是Qt 基于WebGL的3D內(nèi)容運行環(huán)境。由于QtQuick本身就是通過類js引擎執(zhí)行,而且渲染層面基于opengl技術(shù)。故結(jié)合webgL和Qtquick的優(yōu)勢,利用js高效的特點,給Qtquick增加了3d功能。而且Qt Canvas 3D還可以利用成熟的web 3d框架,如three.js、gl-matrix.js等,大大方便了利用QtQuick編寫3d內(nèi)容。Qt Canvas 3D是由官方支持,比Qt3D模塊較成熟。至于兩者性能上的差異尚待對比。
最新版QtCreater支持在創(chuàng)建項目時指定Qt Canvas 3D應用,下面我們通過該方式創(chuàng)建一個默認應用,學習其結(jié)構(gòu)組成。通過QtCreater創(chuàng)建一個使用three.js的應用。
main.cpp
#include?#include?int?main(int?argc,?char?*argv[]) { ????QGuiApplication?app(argc,?argv); ????QQmlApplicationEngine?engine; ????engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); ????return?app.exec(); }
從上面可以看出,Canvas 3D應用和普通qml應用對于c++后端要求一致,沒有額外內(nèi)容,由下面qml代碼可知,Canvas3D即一個普通的QtQuick Item。
main.qml
import?QtQuick?2.4 import?QtCanvas3D?1.0 import?QtQuick.Window?2.2 import?"glcode.js"?as?GLCode Window?{ ????title:?qsTr("untitled1") ????width:?1280 ????height:?768 ????visible:?true ????Canvas3D?{ ????????id:?canvas3d ????????anchors.fill:?parent ????????focus:?true ????????onInitializeGL:?{ ????????????GLCode.initializeGL(canvas3d); ????????} ????????onPaintGL:?{ ????????????GLCode.paintGL(canvas3d); ????????} ????????onResizeGL:?{ ????????????GLCode.resizeGL(canvas3d); ????????} ????} }
上述代碼通過Canvas3D元素定義了3d場景,當場景初始化后會發(fā)送?initializeGL 信號,從而執(zhí)on?initializeGL 槽。實際的控制邏輯寫在了glcode.js中,通過槽函數(shù)將要操作的場景對象canvas3d傳給js代碼。
glcode.js首先導入three.js,然后實現(xiàn)了main.qml中對應的3個槽對應的函數(shù)功能。其語法和普通的three.js應用區(qū)別不大,故一個基于html的three.js應用可以很方便的移植到QtQuick中。
The?Canvas3D?is a QML element that, when placed in your Qt Quick 2 scene, allows you to get a 3D rendering context and call 3D rendering API calls through that context object. Use of the rendering API requires knowledge of OpenGL-like rendering APIs.
There are two functions that are called by the?Canvas3D?implementation:
initializeGL?is emitted before the first frame is rendered, and usually during that you get the 3D context and initialize resources to be used later on during the rendering cycle.
paintGL?is emitted for each frame to be rendered, and usually during that you submit 3D rendering calls to draw whatever 3D content you want to be displayed.
邏輯代碼
Qt.include("three.js") var?camera,?scene,?renderer; var?cube; function?initializeGL(canvas)?{ ????scene?=?new?THREE.Scene(); ????//custom?begain ????camera?=?new?THREE.PerspectiveCamera(75,?canvas.width?/?canvas.height,?0.1,?1000); ????camera.position.z?=?5; ????var?material?=?new?THREE.MeshBasicMaterial({?color:?0x80c342, ???????????????????????????????????????????????????ambient:?0x000000, ???????????????????????????????????????????????????shading:?THREE.SmoothShading?}); ????var?cubeGeometry?=?new?THREE.BoxGeometry(1,?1,?1); ????cube?=?new?THREE.Mesh(cubeGeometry,?material); ????cube.rotation.set(0.785,?0.785,?0.0); ????scene.add(cube); ????//custom?end ????renderer?=?new?THREE.Canvas3DRenderer( ????????????????{?canvas:?canvas,?antialias:?true,?devicePixelRatio:?canvas.devicePixelRatio?}); ????renderer.setSize(canvas.width,?canvas.height); } function?resizeGL(canvas)?{ ????camera.aspect?=?canvas.width?/?canvas.height; ????camera.updateProjectionMatrix(); ????renderer.setPixelRatio(canvas.devicePixelRatio); ????renderer.setSize(canvas.width,?canvas.height); } function?paintGL(canvas)?{ ????renderer.render(scene,?camera); }
從上述js代碼可以看出,resizeGL和paintGL一般默認即可,不需要改動,需要我們編寫的是initializeGL中//custom begain 和//custom end 之間的內(nèi)容。