[ui] Viewer3D: TransformGizmo - ready to be set with absolute values

- Now, we can set the transformation with a position vector, Euler angles and a scale vector.
This commit is contained in:
Julien-Haudegond 2020-07-15 14:55:39 +02:00
parent da765a5f98
commit d0a78d96ab
4 changed files with 70 additions and 17 deletions

View file

@ -188,6 +188,29 @@ class Transformations3DHelper(QObject):
return { "position": posMat, "rotation": rotMat, "scale": scaleMat, "quaternion": decomposition.get("quaternion") } return { "position": posMat, "rotation": rotMat, "scale": scaleMat, "quaternion": decomposition.get("quaternion") }
@Slot(QVector3D, QVector3D, QVector3D, result=QMatrix4x4)
def computeModelMatrixWithEuler(self, translation, rotation, scale):
""" Compute a model matrix from three Vector3D.
Args:
translation (QVector3D): position in space (x, y, z)
rotation (QVector3D): Euler angles in degrees (x, y, z)
scale (QVector3D): scale of the object (x, y, z)
Returns:
QMatrix4x4: corresponding model matrix
"""
posMat = QMatrix4x4()
posMat.translate(translation)
quaternion = QQuaternion.fromEulerAngles(rotation)
rotMat = self.quaternionToRotationMatrix(quaternion)
scaleMat = QMatrix4x4()
scaleMat.scale(scale)
modelMat = posMat * rotMat * scaleMat
return modelMat
#---------- "Private" Methods ----------# #---------- "Private" Methods ----------#

View file

@ -14,8 +14,10 @@ Entity {
readonly property Camera camera : cameraController.camera readonly property Camera camera : cameraController.camera
readonly property var windowSize: cameraController.windowSize readonly property var windowSize: cameraController.windowSize
readonly property alias objectTransform : transformGizmo.objectTransform // The Transform the object should use readonly property alias objectTransform : transformGizmo.objectTransform // The Transform the object should use
readonly property alias updateTransformations: transformGizmo.updateTransformations // Function to update the transformations
signal pickedChanged(bool pressed) signal pickedChanged(bool pressed)
signal gizmoChanged(var translation, var rotation, var scale)
onPickedChanged: { onPickedChanged: {
cameraController.loseMouseFocus = pressed // Notify the camera if the transform takes/releases the focus cameraController.loseMouseFocus = pressed // Notify the camera if the transform takes/releases the focus
@ -30,5 +32,8 @@ Entity {
onPickedChanged: { onPickedChanged: {
root.pickedChanged(pressed) root.pickedChanged(pressed)
} }
onGizmoChanged: {
root.gizmoChanged(translation, rotation, scale)
}
} }
} }

View file

@ -14,9 +14,29 @@ Entity {
property var windowSize property var windowSize
property var frontLayerComponent property var frontLayerComponent
property var window property var window
readonly property Transform objectTransform : Transform {}
readonly property Transform objectTransform : Transform {
translation: gizmoDisplayTransform.translation
rotation: gizmoDisplayTransform.rotation
scale3D: Qt.vector3d(1,1,1)
}
readonly property var updateTransformations: function updateTransformations(translation, rotation, scale) {
const gizmoModelMat = Transformations3DHelper.computeModelMatrixWithEuler(translation, rotation, Qt.vector3d(1,1,1))
gizmoDisplayTransform.setMatrix(gizmoModelMat) // Update gizmo matrix and translation/rotation of the object (with binding)
objectTransform.scale3D = scale // Update the scale of the object
}
signal pickedChanged(bool pressed) signal pickedChanged(bool pressed)
signal gizmoChanged(var translation, var rotation, var scale)
function emitGizmoChanged() {
const translation = gizmoDisplayTransform.translation // Position in space
const rotation = Qt.vector3d(gizmoDisplayTransform.rotationX, gizmoDisplayTransform.rotationY, gizmoDisplayTransform.rotationZ) // Euler angles
const scale = objectTransform.scale3D // Scale of the object
updateTransformations(translation, rotation, scale) // Optional: just to make sure the absolute values work well
gizmoChanged(translation, rotation, scale)
}
components: [gizmoDisplayTransform, mouseHandler, frontLayerComponent] components: [gizmoDisplayTransform, mouseHandler, frontLayerComponent]
@ -38,31 +58,27 @@ Entity {
/***** TRANSFORMATIONS (using local vars) *****/ /***** TRANSFORMATIONS (using local vars) *****/
function doRelativeTranslation(initialModelMatrix, translateVec) { function doRelativeTranslation(initialModelMatrix, translateVec) {
Transformations3DHelper.relativeLocalTranslate(gizmoDisplayTransform, initialModelMatrix.position, initialModelMatrix.rotation, initialModelMatrix.scale, translateVec) // Update gizmo matrix Transformations3DHelper.relativeLocalTranslate(gizmoDisplayTransform, initialModelMatrix.position, initialModelMatrix.rotation, initialModelMatrix.scale, translateVec) // Update gizmo matrix and object matrix with binding
Transformations3DHelper.relativeLocalTranslate(objectTransform, initialModelMatrix.position, initialModelMatrix.rotation, initialModelMatrix.scale, translateVec) // Update object matrix
} }
function doRelativeRotation(initialModelMatrix, axis, degree) { function doRelativeRotation(initialModelMatrix, axis, degree) {
Transformations3DHelper.relativeLocalRotate(gizmoDisplayTransform, initialModelMatrix.position, initialModelMatrix.quaternion, initialModelMatrix.scale, axis, degree) // Update gizmo matrix Transformations3DHelper.relativeLocalRotate(gizmoDisplayTransform, initialModelMatrix.position, initialModelMatrix.quaternion, initialModelMatrix.scale, axis, degree) // Update gizmo matrix and object matrix with binding
Transformations3DHelper.relativeLocalRotate(objectTransform, initialModelMatrix.position, initialModelMatrix.quaternion, initialModelMatrix.scale, axis, degree) // Update object matrix
} }
function doRelativeScale(initialModelMatrix, scaleVec) { function doRelativeScale(initialModelMatrix, scaleVec) {
Transformations3DHelper.relativeLocalScale(objectTransform, initialModelMatrix.position, initialModelMatrix.rotation, initialModelMatrix.scale, scaleVec) // Update object matrix Transformations3DHelper.relativeLocalScale(objectTransform, initialModelMatrix.position, initialModelMatrix.rotation, initialModelMatrix.scale, scaleVec) // Update only object matrix
} }
function resetTranslation() { function resetTranslation() {
gizmoDisplayTransform.translation = Qt.vector3d(0,0,0) gizmoDisplayTransform.translation = Qt.vector3d(0,0,0) // Reset gizmo matrix and object matrix with binding
objectTransform.translation = Qt.vector3d(0,0,0)
} }
function resetRotation() { function resetRotation() {
gizmoDisplayTransform.rotation = Qt.quaternion(1,0,0,0) gizmoDisplayTransform.rotation = Qt.quaternion(1,0,0,0) // Reset gizmo matrix and object matrix with binding
objectTransform.rotation = Qt.quaternion(1,0,0,0)
} }
function resetScale() { function resetScale() {
objectTransform.scale3D = Qt.vector3d(1,1,1) objectTransform.scale3D = Qt.vector3d(1,1,1) // Reset only object matrix
} }
function resetATransformType(transformType) { function resetATransformType(transformType) {
@ -71,6 +87,7 @@ Entity {
case TransformGizmo.Type.ROTATION: resetRotation(); break case TransformGizmo.Type.ROTATION: resetRotation(); break
case TransformGizmo.Type.SCALE: resetScale(); break case TransformGizmo.Type.SCALE: resetScale(); break
} }
emitGizmoChanged()
} }
/***** DEVICES *****/ /***** DEVICES *****/
@ -84,7 +101,7 @@ Entity {
property bool enabled: false property bool enabled: false
onPositionChanged: { onPositionChanged: {
if (objectPicker) { if (objectPicker && objectPicker.button === Qt.LeftButton) {
// Get the selected axis // Get the selected axis
let pickedAxis let pickedAxis
switch(objectPicker.gizmoAxis) { switch(objectPicker.gizmoAxis) {
@ -137,7 +154,8 @@ Entity {
const gizmoToCameraVector = camera.position.toVector4d().minus(gizmoCenterPoint) const gizmoToCameraVector = camera.position.toVector4d().minus(gizmoCenterPoint)
const orientation = gizmoLocalAxisVector.dotProduct(gizmoToCameraVector) > 0 ? 1 : -1 const orientation = gizmoLocalAxisVector.dotProduct(gizmoToCameraVector) > 0 ? 1 : -1
if (angle !== 0) doRelativeRotation(objectPicker.modelMatrix, pickedAxis, angle*orientation) if (angle !== 0) doRelativeRotation(objectPicker.modelMatrix, pickedAxis, angle*orientation) // Do a rotation from the initial Object Model Matrix when we picked the gizmo
return return
} }
@ -156,18 +174,23 @@ Entity {
let offset = (mouseVector.length() - scaleUnit) * sensibility let offset = (mouseVector.length() - scaleUnit) * sensibility
offset = (offset < 0) ? offset * 3 : offset // Used to make it more sensible when we want to reduce the scale (because the action field is shorter) offset = (offset < 0) ? offset * 3 : offset // Used to make it more sensible when we want to reduce the scale (because the action field is shorter)
if (offset) doRelativeScale(objectPicker.modelMatrix, pickedAxis.times(offset)) if (offset) doRelativeScale(objectPicker.modelMatrix, pickedAxis.times(offset)) // Do a scale from the initial Object Model Matrix when we picked the gizmo
return return
} }
} }
} }
}
onReleased: { if(objectPicker && objectPicker.button === Qt.RightButton) {
if(objectPicker && mouse.button === Qt.RightButton) {
resetMenu.updateTypeBeforePopup(objectPicker.gizmoType) resetMenu.updateTypeBeforePopup(objectPicker.gizmoType)
resetMenu.popup(window) resetMenu.popup(window)
} }
} }
onReleased: {
if(objectPicker && mouse.button === Qt.LeftButton) {
emitGizmoChanged()
}
}
} }
Menu { Menu {

View file

@ -15,6 +15,7 @@ ObjectPicker {
property int gizmoType property int gizmoType
property point screenPoint property point screenPoint
property var modelMatrix property var modelMatrix
property int button
signal pickedChanged(var picker) signal pickedChanged(var picker)
@ -25,6 +26,7 @@ ObjectPicker {
mouseController.objectPicker = this mouseController.objectPicker = this
root.isPressed = true root.isPressed = true
screenPoint = pick.position screenPoint = pick.position
button = pick.button
pickedChanged(this) pickedChanged(this)
} }
onEntered: { onEntered: {