当前位置:网站首页>Qt Quick 3D学习:鼠标拾取物体
Qt Quick 3D学习:鼠标拾取物体
2022-06-12 22:02:00 【龚建波】
(注意,开源版的 Qt Quick 3D 是狗都不用的 GPL 协议)
Qt Creator 中有一个 picking 的示例,用于演示 View3D 中物体的拾取:

在示例基础上,我又加了一个简单的拖动效果,如图所示:

在使用 OpenGL 实现拾取的时候,我们可以用射线法。Qt Quick 3D 中封装了拾取操作,通过 View3D 的 pick 函数,可以取到 View3D 视口某个点下离屏幕最近的那个物体 Model。
PickResult pick(float x, float y)该函数返回一个 PickResult 对象,通过其 objectHit 属性可以判断是否拾取到了物体。
View3D {
MouseArea {
id: mouse_area
anchors.fill: parent
onPressed: {
//获取点在View上的屏幕坐标
pick_screen.text = "(" + mouse.x + ", " + mouse.y + ")"
//pick取与该点射线路径相交的离最近的Model的信息,返回PickResult对象
var result = control.pick(mouse.x, mouse.y)
//判断objectHit是否有效,就可以只知道是否拾取到了物体
if (result.objectHit) {
} else {
}
}
}
}
在 Qt5.15 中,返回的 PickResult 类型只有简单的几个属性:
//拾取原点与物体之间的距离,用视口坐标拾取则拾取原点就是观察点Camera的位置
distance : float
//拾取选中的Model对象
objectHit : Model
//pick点在场景中的位置,(可能相当于射线与物体表面的焦点坐标)
//This property holds the scene position of the hit.
scenePosition : vector3d
//pick点的UV位置
//This property holds the UV position of the hit.
uvPosition : vector2d在 Qt6.3 中,View3D 增加了 pickAll 函数拾取该点下所有的物体,同时 PickResult 类型也增加了一些属性:
//局部空间中被选中的面的法线
//This property holds the normal of the face that was hit in local coordinate space.
normal : vector3d
//This property holds the scene position of the hit in local coordinate space.
position : vector3d
//This property holds the normal of the face that was hit in scene coordinate space.
sceneNormal : vector3d拾取到物体之后,就可以对这个 Model 节点进行操作了。本文 Demo 中我实现了一个简单的拖动操作,主要流程是:
1.pick 选中时保存 Model 位置和 pick 位置的视口屏幕坐标差值(可以通过 View3D 的 mapFrom3DScene 函数将场景坐标转换为视口坐标,使用该函数需要先给 View3D 设置 camera )
2.在鼠标移动的过程中,通过差值还原物体 Model 的相对位置,使用 View3D 的 mapTo3DScene 函数转换得到 Model 新的场景坐标。
(但是这个逻辑没有考虑透视投影时,移动场景坐标 xy,视口坐标 xy 并不是等比变化的)
主要代码
Github(PickModel.qml): https://github.com/gongjianbo/HelloQtQuick3D
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick3D 1.15
import QtQuick3D.Helpers 1.15
View3D {
id: control
//背景
environment: SceneEnvironment {
clearColor: "darkGreen"
backgroundMode: SceneEnvironment.Color
}
//观察相机
//View3D的mapTo/mapFrom坐标转换函数需要先设置camera属性
camera: perspective_camera
PerspectiveCamera {
id: perspective_camera
z: 300
}
//光照
DirectionalLight {
eulerRotation.y: 45
}
//立方体
Model {
id: cube_node
objectName: "Cube"
source: "#Cube"
//使能pick
pickable: true
materials: DefaultMaterial {
diffuseColor: mouse_area.pickNode == cube_node ? "cyan" : "yellow"
}
//立方体转动
SequentialAnimation on eulerRotation {
running: true
loops: Animation.Infinite
PropertyAnimation {
duration: 10000
from: Qt.vector3d(0, 0, 0)
to: Qt.vector3d(360, 360, 360)
}
}
}
//锥体
Model {
id: cone_node
objectName: "Cone"
source: "#Cone"
pickable: true
x: 100
z: 50
materials: DefaultMaterial {
diffuseColor: mouse_area.pickNode == cone_node ? "cyan" : "orange"
}
}
//球体
Model {
id: sphere_node
objectName: "Sphere"
source: "#Sphere"
pickable: true
x: -100
z: -50
materials: DefaultMaterial {
diffuseColor: mouse_area.pickNode == sphere_node ? "cyan" : "purple"
}
}
//展示拾取对象的信息
Row {
x: 20
y: 20
spacing: 10
Column {
Label {
color: "white"
text: "Pick Node:"
}
Label {
color: "white"
text: "Screen Position:"
}
Label {
color: "white"
text: "Distance:"
}
Label {
color: "white"
text: "World Position:"
}
}
Column {
Label {
id: pick_name
color: "white"
}
Label {
id: pick_screen
color: "white"
}
Label {
id: pick_distance
color: "white"
}
Label {
id: pick_word
color: "white"
}
}
}
MouseArea {
id: mouse_area
anchors.fill: parent
hoverEnabled: false
property var pickNode: null
//鼠标和物体xy的偏移
property real xOffset: 0
property real yOffset: 0
property real zOffset: 0
onPressed: {
//获取点在View上的屏幕坐标
pick_screen.text = "(" + mouse.x + ", " + mouse.y + ")"
//pick取与该点射线路径相交的离最近的Model的信息,返回PickResult对象
//因为该模块一直在迭代,新的版本可以从PickResult对象获取更多的信息
//Qt6中还提供了pickAll获取与该射线相交的所有Model信息
var result = control.pick(mouse.x, mouse.y)
//目前只在点击时更新了pick物体的信息
if (result.objectHit) {
pickNode = result.objectHit
pick_name.text = pickNode.objectName
pick_distance.text = result.distance.toFixed(2)
pick_word.text = "("
+ result.scenePosition.x.toFixed(2) + ", "
+ result.scenePosition.y.toFixed(2) + ", "
+ result.scenePosition.z.toFixed(2) + ")"
//console.log('in',pick_screen.text)
//console.log(result.scenePosition)
var map_from = control.mapFrom3DScene(pickNode.scenePosition)
//var map_to = control.mapTo3DScene(Qt.vector3d(mouse.x,mouse.y,map_from.z))
//console.log(map_from)
//console.log(map_to)
xOffset = map_from.x - mouse.x
yOffset = map_from.y - mouse.y
zOffset = map_from.z
} else {
pickNode = null
pick_name.text = "None"
pick_distance.text = " "
pick_word.text = " "
}
}
onPositionChanged: {
if(!mouse_area.containsMouse || !pickNode){
return
}
var pos_temp = Qt.vector3d(mouse.x + xOffset, mouse.y + yOffset, zOffset);
var map_to = control.mapTo3DScene(pos_temp)
pickNode.x = map_to.x
pickNode.y = map_to.y
}
}
}
参考
边栏推荐
- MySQL介绍和安装(一)
- VagrantBox重新安装vboxsf驱动
- SQL tuning guide notes 13:gathering optimizer statistics
- Npoi create word
- [QNX hypervisor 2.2 user manual] 4.3 obtain the host component
- 3.5 测试类的setup和teardown
- 六月集训(第11天) —— 矩阵
- SQL tuning guide notes 15:controlling the use of optimizer statistics
- 接口测试工具apipost3.0版本对于流程测试和引用参数变量
- 【QNX Hypervisor 2.2 用户手册】4.4 构建Host
猜你喜欢

回文链表及链表相交问题(和心怡的人相交)你真的会了吗?

Redis optimization

数据库每日一题---第10天:组合两个表

Okio source code analysis

PCB封装下载网站推荐及其详细使用方法

Oracle SQL Developer的代码输入框中推荐使用的中文字体

Pat grade A - 1167 Cartesian tree (30 points) (buildtree + level traversal)

Build a highly available database

SQL调优指南笔记10:Optimizer Statistics Concepts

Producer consumer model under multithreading model
随机推荐
How to ensure thread safety?
Okio source code analysis
Design and practice of Hudi bucket index in byte skipping
Prefix sum and difference
Yyds dry inventory insider news: Series high-frequency interview questions, worth a visit!
User guide for JUC concurrency Toolkit
What is embedded
What is the race condition? How do you find and solve the competition?
June training (day 10) - bit operation
[proteus simulation] simple digital tube timer clock
生成小程序菊花码(生成菊花码、更换中间logo、更改图片尺寸,加文字)
Oracle livelabs experiment: introduction to Oracle Spatial
Linux backup MySQL
Modstartcms modular station building system v3.3.0 component function upgrade, event triggering enhancement
PE installation win10 system
【图像去噪】基于三边滤波器实现图像去噪附matlab代码
Ansible-大总结(六)
MySQL architecture and basic management (II)
Xingda easy control ModbusRTU to modbustcp gateway
[Jianzhi offer] Jianzhi offer 05 Replace spaces