For reasons that are more complex than this minimal testcase, I need to have a entity (childEntity
, the magenta box) child of another entity (parentEntity
, the cyan box), but childEntity
should be independent of parentEntity
's transform.
Therefore I add this handler:
QtQuick.Connections {
target: parentTransform
onMatrixChanged: {
// cancel parent's transform
var m = parentTransform.matrix
var i = m.inverted()
childTransform.matrix = i
// debug:
console.log(parentTransform.matrix.times(i))
}
}
which works well for cancelling out parent's translation and rotation, but not for scale.
When parent's scale3D
is not [1,1,1] and rotation is also set, then childEntity
appears distorted, despite the product of parentTransform.matrix
times childTransform.matrix
gives the 4x4 identity. Why?
Minimal testcase: (load into a QQuickView
)
import QtQml 2.12 as QtQml
import QtQuick 2.12 as QtQuick
import QtQuick.Controls 2.12 as QtQuickControls
import QtQuick.Scene3D 2.0
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
Scene3D {
function change_translation_and_rotation() {
parentTransform.translation.x = 0.1
parentTransform.translation.y = 0.5
parentTransform.translation.z = 2
parentTransform.rotationX = 30
parentTransform.rotationY = 60
parentTransform.rotationZ = 10
}
function change_rotation_and_scale() {
parentTransform.rotationX = 30
parentTransform.rotationY = 60
parentTransform.rotationZ = 10
parentTransform.scale3D.x = 0.1
parentTransform.scale3D.y = 0.5
parentTransform.scale3D.z = 2
}
function reset_transform() {
parentTransform.translation.x = -0.5
parentTransform.translation.y = 0
parentTransform.translation.z = 0.5
parentTransform.rotationX = 0
parentTransform.rotationY = 0
parentTransform.rotationZ = 0
parentTransform.scale3D.x = 1
parentTransform.scale3D.y = 1
parentTransform.scale3D.z = 1
}
data: [
QtQml.Connections {
target: parentTransform
onMatrixChanged: {
// cancel parent's transform
var m = parentTransform.matrix
var i = m.inverted()
childTransform.matrix = i
// debug:
console.log(parentTransform.matrix.times(i))
}
},
QtQuick.Column {
spacing: 5
QtQuick.Repeater {
id: buttons
model: ["change_translation_and_rotation", "change_rotation_and_scale", "reset_transform"]
delegate: QtQuickControls.Button {
text: modelData.replace(/_/g, ' ')
font.bold: focus
onClicked: {focus = true; scene3d[modelData]()}
}
}
}
]
id: scene3d
anchors.fill: parent
aspects: ["render", "logic", "input"]
Entity {
id: root
components: [RenderSettings {activeFrameGraph: ForwardRenderer {camera: mainCamera}}, InputSettings {}]
Camera {
id: mainCamera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d(-3.46902, 4.49373, -3.78577)
upVector: Qt.vector3d(0.41477, 0.789346, 0.452641)
viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
}
OrbitCameraController {
camera: mainCamera
}
Entity {
id: parentEntity
components: [
CuboidMesh {
xExtent: 1
yExtent: 1
zExtent: 1
},
PhongMaterial {
ambient: "#6cc"
},
Transform {
id: parentTransform
translation: Qt.vector3d(-0.5, 0, 0.5)
}
]
Entity {
id: childEntity
components: [
CuboidMesh {
xExtent: 0.5
yExtent: 0.5
zExtent: 0.5
},
PhongMaterial {
ambient: "#c6c"
},
Transform {
id: childTransform
translation: Qt.vector3d(-0.5, 0, 0.5)
}
]
}
}
QtQuick.Component.onCompleted: reset_transform()
}
}