mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-08-06 10:18:42 +02:00
[ui] Viewer3D: TransformGizmo - new mouse handling translation
- Translations are computed using the dot product between the mouse vector (picked position to current position) and the projected picked axis vector. Like this, the behaviour is a lot more natural and user-friendly.
This commit is contained in:
parent
29c4be6210
commit
fb3b541a7f
2 changed files with 39 additions and 16 deletions
|
@ -80,26 +80,28 @@ Entity {
|
||||||
|
|
||||||
/***** GENERIC MATRIX TRANSFORMATIONS *****/
|
/***** GENERIC MATRIX TRANSFORMATIONS *****/
|
||||||
|
|
||||||
function decomposeModelMatrixFromTransform(transform) {
|
function decomposeModelMatrixFromTransformations(translation, rotation, scale3D) {
|
||||||
const posMat = Qt.matrix4x4()
|
const posMat = Qt.matrix4x4()
|
||||||
posMat.translate(transform.translation)
|
posMat.translate(translation)
|
||||||
const rotMat = quaternionToRotationMatrix(transform.rotation)
|
const rotMat = quaternionToRotationMatrix(rotation)
|
||||||
const scaleMat = Qt.matrix4x4()
|
const scaleMat = Qt.matrix4x4()
|
||||||
scaleMat.scale(transform.scale3D)
|
scaleMat.scale(scale3D)
|
||||||
|
|
||||||
return { position: posMat, rotation: rotMat, scale: scaleMat }
|
return { position: posMat, rotation: rotMat, scale: scaleMat }
|
||||||
}
|
}
|
||||||
|
|
||||||
function localTranslate(transform, translateVec) {
|
function decomposeModelMatrixFromTransform(transform) {
|
||||||
const modelMat = decomposeModelMatrixFromTransform(transform)
|
return decomposeModelMatrixFromTransformations(transform.translation, transform.rotation, transform.scale3D)
|
||||||
|
}
|
||||||
|
|
||||||
|
function localTranslateFrom(transform, initialDecomposedModelMat, translateVec) {
|
||||||
// Compute the translation transformation matrix
|
// Compute the translation transformation matrix
|
||||||
const translationMat = Qt.matrix4x4()
|
const translationMat = Qt.matrix4x4()
|
||||||
translationMat.translate(translateVec)
|
translationMat.translate(translateVec)
|
||||||
|
|
||||||
// Compute the new model matrix (POSITION * ROTATION * TRANSLATE * SCALE) and set it to the Transform
|
// Compute the new model matrix (POSITION * ROTATION * TRANSLATE * SCALE) and set it to the Transform
|
||||||
const mat = modelMat.position.times(modelMat.rotation.times(translationMat.times(modelMat.scale)))
|
const mat = initialDecomposedModelMat.position.times(initialDecomposedModelMat.rotation.times(translationMat.times(initialDecomposedModelMat.scale)))
|
||||||
transform.setMatrix(mat)
|
transform.setMatrix(mat)
|
||||||
}
|
}
|
||||||
|
|
||||||
function localRotate(transform, axis, degree) {
|
function localRotate(transform, axis, degree) {
|
||||||
|
@ -140,9 +142,9 @@ Entity {
|
||||||
|
|
||||||
/***** SPECIFIC MATRIX TRANSFORMATIONS (using local vars) *****/
|
/***** SPECIFIC MATRIX TRANSFORMATIONS (using local vars) *****/
|
||||||
|
|
||||||
function doTranslation(translateVec) {
|
function doTranslation(initialDecomposedModelMat, translateVec) {
|
||||||
localTranslate(gizmoDisplayTransform, translateVec) // Update gizmo matrix
|
localTranslateFrom(gizmoDisplayTransform, initialDecomposedModelMat, translateVec) // Update gizmo matrix
|
||||||
localTranslate(objectTransform, translateVec) // Update object matrix
|
localTranslateFrom(objectTransform, initialDecomposedModelMat, translateVec) // Update object matrix
|
||||||
}
|
}
|
||||||
|
|
||||||
function doRotation(axis, degree) {
|
function doRotation(axis, degree) {
|
||||||
|
@ -369,6 +371,7 @@ Entity {
|
||||||
gizmoType: TransformGizmo.Type.POSITION
|
gizmoType: TransformGizmo.Type.POSITION
|
||||||
|
|
||||||
onPickedChanged: {
|
onPickedChanged: {
|
||||||
|
this.decomposedObjectModelMat = decomposeModelMatrixFromTransformations(objectTransform.translation, objectTransform.rotation, objectTransform.scale3D) // Save the current transformations
|
||||||
root.pickedChanged(picker.isPressed) // Used to prevent camera transformations
|
root.pickedChanged(picker.isPressed) // Used to prevent camera transformations
|
||||||
transformHandler.objectPicker = picker.isPressed ? picker : null // Pass the picker to the global FrameAction
|
transformHandler.objectPicker = picker.isPressed ? picker : null // Pass the picker to the global FrameAction
|
||||||
}
|
}
|
||||||
|
@ -430,9 +433,7 @@ Entity {
|
||||||
if (objectPicker) {
|
if (objectPicker) {
|
||||||
switch(objectPicker.gizmoType) {
|
switch(objectPicker.gizmoType) {
|
||||||
case TransformGizmo.Type.POSITION: {
|
case TransformGizmo.Type.POSITION: {
|
||||||
const offsetX = mouseHandler.currentPosition.x - mouseHandler.lastPosition.x
|
// Get the corresponding axis translation
|
||||||
const offsetY = mouseHandler.currentPosition.y - mouseHandler.lastPosition.y
|
|
||||||
|
|
||||||
let pickedAxis
|
let pickedAxis
|
||||||
switch(objectPicker.gizmoAxis) {
|
switch(objectPicker.gizmoAxis) {
|
||||||
case TransformGizmo.Axis.X: pickedAxis = Qt.vector3d(1,0,0); break
|
case TransformGizmo.Axis.X: pickedAxis = Qt.vector3d(1,0,0); break
|
||||||
|
@ -440,8 +441,27 @@ Entity {
|
||||||
case TransformGizmo.Axis.Z: pickedAxis = Qt.vector3d(0,0,1); break
|
case TransformGizmo.Axis.Z: pickedAxis = Qt.vector3d(0,0,1); break
|
||||||
}
|
}
|
||||||
|
|
||||||
doTranslation(pickedAxis.times(0.01*offsetX - 0.01*offsetY))
|
const sensibility = 0.02
|
||||||
mouseHandler.lastPosition = mouseHandler.currentPosition
|
|
||||||
|
// Compute the current vector PickedPoint -> CurrentMousePoint
|
||||||
|
const pickedPosition = objectPicker.screenPoint
|
||||||
|
const mouseVector = Qt.vector2d(mouseHandler.currentPosition.x - pickedPosition.x, -(mouseHandler.currentPosition.y - pickedPosition.y))
|
||||||
|
|
||||||
|
// Transform the positive picked axis vector from world coord to viewport coord
|
||||||
|
const viewMatrix = camera.transform.matrix.inverted()
|
||||||
|
const gizmoLocalPointOnAxis = gizmoDisplayTransform.matrix.times(Qt.vector4d(pickedAxis.x, pickedAxis.y, pickedAxis.z, 1))
|
||||||
|
const gizmoCenterPoint = gizmoDisplayTransform.matrix.times(Qt.vector4d(0, 0, 0, 1))
|
||||||
|
const projectedPointOnAxis = camera.projectionMatrix.times(viewMatrix.times(gizmoLocalPointOnAxis))
|
||||||
|
const projectedCenter = camera.projectionMatrix.times(viewMatrix.times(gizmoCenterPoint))
|
||||||
|
const projectedAxisVector = Qt.vector2d(projectedPointOnAxis.x/projectedPointOnAxis.w - projectedCenter.x/projectedCenter.w, projectedPointOnAxis.y/projectedPointOnAxis.w - projectedCenter.y/projectedCenter.w)
|
||||||
|
|
||||||
|
// Get the cosinus of the angle from the projectedAxisVector to the mouseVector
|
||||||
|
const cosAngle = projectedAxisVector.dotProduct(mouseVector) / (projectedAxisVector.length() * mouseVector.length())
|
||||||
|
const offset = cosAngle * mouseVector.length() * sensibility
|
||||||
|
|
||||||
|
// If the mouse is not at the same spot as the pickedPoint, we do translation
|
||||||
|
if (offset) doTranslation(objectPicker.decomposedObjectModelMat, pickedAxis.times(offset)) // Do a translation from the initial Object Model Matrix when we picked the gizmo
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ ObjectPicker {
|
||||||
property color gizmoBaseColor
|
property color gizmoBaseColor
|
||||||
property int gizmoAxis
|
property int gizmoAxis
|
||||||
property int gizmoType
|
property int gizmoType
|
||||||
|
property point screenPoint
|
||||||
|
property var decomposedObjectModelMat
|
||||||
|
|
||||||
signal pickedChanged(var picker)
|
signal pickedChanged(var picker)
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ ObjectPicker {
|
||||||
onPressed: {
|
onPressed: {
|
||||||
root.isPressed = true
|
root.isPressed = true
|
||||||
pickedChanged(this)
|
pickedChanged(this)
|
||||||
|
screenPoint = pick.position
|
||||||
mouseController.currentPosition = mouseController.lastPosition = pick.position
|
mouseController.currentPosition = mouseController.lastPosition = pick.position
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue