本章我们来学习View3D类。
View3D是用来渲染3D场景并显示在2D平面的类,并且该类可以放在QML2D下继承于Item子类的任何场景中,比如将View3D放在Rectangle中:
Rectangle {width: 200 height: 200color: "red"View3D { anchors.fill: parent anchors.margins: 40// ... ...}
}
效果如下所示:
View3D是用来渲染3D场景的,所以我们可以通过environment属性来设置环境参数,比如设置3D背景色、抗锯齿、天空盒等等,比如设置:
environment: SceneEnvironment {clearColor: "red" // 设置背景色为红色backgroundMode: SceneEnvironment.Color // 设置背景模式为color,也可以设置为天空盒、透明等等antialiasingMode: SceneEnvironment.MSAA // 抗锯齿模式antialiasingQuality: SceneEnvironment.High // 抗锯齿质量}
如果我们要在场景中显示2D类(必须是Item子类),可以通过Node类实现、比如我们要在View3D中显示一个Text:
import QtQuick
import QtQuick.Window
import QtQuick3D
import QtQuick3D.Helpers
Window {width: 640height: 480visible: truetitle: qsTr("Hello World")View3D {anchors.fill: parentenvironment: SceneEnvironment {clearColor: "#F1F1F1"backgroundMode: SceneEnvironment.ColorantialiasingMode: SceneEnvironment.MSAAantialiasingQuality: SceneEnvironment.High}PerspectiveCamera {id: cameraposition: Qt.vector3d(0, 0, 440)}Node {Rectangle {width: 400height: 400x: -width/2y: -height/2color: "#77202020"radius: 10border.width: 2border.color: "#77f0f0f0"Text {anchors.centerIn: parentfont.pixelSize: 20color: "#FFF"font.family: "Microsoft Yahei"style: Text.RaisedstyleColor: "#111"text: "QML3D学习 by诺谦"}}} }
}
效果如下所示:
这里我们使用了PerspectiveCamera 相机,要让View3D显示出来则必须需要一个继承于Camera类的相机,否则View3D无法知道我们要从哪个角度去展示3D场景。
我们设置了摄像机的position为Qt.vector3d(0, 0, 440)、只设置了z为440,而欧拉角度默认是0,所以可以看出摄像机的方向默认是从Z方向照射XY方向的。
假如我们设置为:
PerspectiveCamera {id: cameraposition: Qt.vector3d(0, -200, 440) // 摄像机Y方向后退200eulerRotation.x: 30 // 绕x正方向旋转30°}
效果如下所示:
而我们设置的Rectangle的x和y为宽高的负一半,这是为了让Rectangle在原点居中显示,除此之外,Node还可以组合式显示,比如:
Node {Rectangle {width: 400height: 400x: -width/2y: -height/2color: "#77202020"}Rectangle {width: 400height: 400x: 0y: 0color: "#77202020"}
}
效果如下所示:
其中Node类介绍如下所示:
如上图可以看到,Node类的子类非常多,比如Model类(显示3D模型)、ParticleSystem3D粒子系统类、Light光照类等等。
所以Node类非常重要,下章我们便来来学习Node类,再来学习其它类就会非常的方便快捷。
View3D的其它相关属性和方法介绍
- importScene : 设置公共的Node,比如有多个View3D,其内容都是相同的Node,只是相机位置不一致而已,具体参考示例(View3D Example),注意:该属性只能设置一次,后续更改将无效。
- camera : QtQuick3D::Camera,指定用哪个相机来显示
- environment : QtQuick3D::SceneEnvironment,设置渲染场景,比如背景色
- importScene : QtQuick3D::Node,设置公共的Node,比如有多个View3D,其内容都是相同的Node,只是相机位置不一致而已,具体参考示例(View3D Example),注意:该属性只能设置一次,后续更改将无效。
- renderFormat : enumeration, 设置渲染纹理的格式,默认为ShaderEffectSource.RGBA8
- renderMode : enumeration,渲染模式,默认为View3D.Offscreen,只有当某些GOU硬件不支持时,才会去更改渲染模式。
- renderStats : QtQuick3D::RenderStats,只读属性,统计信息,比如fps实时刷新率,frameTime,renderTime,syncTime, 和maxFrameTime等等
- scene : QtQuick3D::Node, 只读属性, 保存View3D场景的根节点。
方法如下所示:
- vector3d mapFrom3DScene(vector3d scenePos) : 将scenePos场景空间位置(3D)转换到视图平面位置(2D)
- vector3d mapTo3DScene(vector3d viewPos) : 将viewPos视图平面位置(2D)转换到场景空间位置(3D)
- PickResult pick(float x, float y) : 此方法将从视图坐标xy位置“射”一条光线到3D场景中,并返回与射线最近交叉的物体信息。例如,可以使用鼠标坐标来调用它来查找鼠标光标下的对象.
- List<PickResult> pickAll(float x, float y) : 和pick函数类似,不过是从视图坐标xy位置“射”一条光线到3D场景中,并返回与射线所有交叉的物体信息列表并从近到远进行排序
- PickResult rayPick(vector3d origin, vector3d direction) : 获取从场景空间位置origin,发出一个direction方向的射线,并返回与射线最近交叉的物体信息,例如,在判断射击子弹时是否有碰撞
- List<PickResult> rayPickAll(vector3d origin, vector3d direction): 和rayPick函数类似,不过获取的是一个所有交叉的列表
而PickResult 类常用参数如下所示:
- distance : float, 拾取距离,也就是射出光线的原点与交叉点的距离
- instanceIndex : int,当拾取命中实例模型的实例时,此属性保存实例表中的索引,如果该模型不是由多个子模块组成,那么始终返回0
- normal : vector3d,保存局部坐标空间中被击中的面的法线。
- objectHit : Model,保存被选中的模型对象,我们可以通过!=null来判断是否有选中对象
- position : vector3d,保存拾取命中时,在3D空间中的场景位置
接下来我们便来实现一个点击3D物体变色的示例。
由于点击只有对3D模型才有效果(比如对光无法进行点击),所以我们需要使用Model类,Model类需要在学了Node类后再详解,所以本章只简单使用,示例如下所示:
import QtQuick
import QtQuick.Window
import QtQuick3D
Window {width: 640height: 480visible: truetitle: qsTr("Hello World")View3D {id: _viewanchors.fill: parentenvironment: SceneEnvironment {clearColor: "#F1F1F1"backgroundMode: SceneEnvironment.ColorantialiasingMode: SceneEnvironment.MSAAantialiasingQuality: SceneEnvironment.High}camera: cameraPerspectiveCamera {id: cameraposition: Qt.vector3d(0, -900, 800)eulerRotation.x: 45}MouseArea {anchors.fill: parentonClicked: (mouse)=> {let ret = _view.pick(mouse.x, mouse.y)if(ret.objectHit != null)ret.objectHit.materials[0].diffuseColor =Qt.rgba(Math.random(),Math.random(), Math.random(), 1.0)}}DirectionalLight {eulerRotation: Qt.vector3d(0, 0, 0)castsShadow: truebrightness: 3}Model {id: _spheresource: "#Sphere"z: 300pickable: truescale: Qt.vector3d(2, 2, 2)materials: DefaultMaterial {diffuseColor: Qt.rgba(0.6, 0.5, 0.2, 1.0)}}Model {source: "#Rectangle"pickable: truescale: Qt.vector3d(10, 10, 1)materials: DefaultMaterial {diffuseColor: Qt.rgba(0.7, 0.2, 0.2, 1.0)}}}}
运行效果如下所示:
未完待续