qt - 反转父 qt3d 实体变换(不适用于 scale3D)
问题描述
由于比这个最小测试用例更复杂的原因,我需要childEntity
另一个实体(parentEntity
,青色框)的实体( ,洋红色框)子,但childEntity
应该独立于parentEntity
' 转换。
因此我添加了这个处理程序:
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))
}
}
这适用于消除父级的平移和旋转,但不适用于缩放。
当父级scale3D
不是 [1,1,1] 并且还设置了旋转时,尽管时间childEntity
的乘积给出了 4x4 标识,但它会出现扭曲。为什么?parentTransform.matrix
childTransform.matrix
最小测试用例:(加载到 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()
}
}
解决方案
问题是 QTransform 节点没有将转换存储为一般的 4x4 矩阵。而是将矩阵分解为以固定顺序应用的 3 个变换:
- S - 对角缩放矩阵
- R - 旋转矩阵
- T - 翻译
然后按 T * R * S * X 的顺序将其应用于点 X。
矩阵属性的文档描述了这个分解步骤https://doc.qt.io/qt-5/qt3dcore-qtransform.html#matrix-prop
因此,当父级的变换为 M = T * R * S 时,子级的逆变换将是 M^-1 = S^-1 * R^-1 * T^-1。在子 QTransform 上设置逆将尝试以相同的方式分解它:
M^-1 = T_i * R_i * S_i = S^-1 * R^-1 * T^-1
那是行不通的,因为特别是 S 和 R 不会像这样通勤。
您可以在设置childTransform.matrix后通过比较childTransform.matrix和i的值在代码中对此进行测试。
我认为唯一的解决方案是在嵌套在子对象上方的实体上使用 3 个 QTransform,以实现逆序的正确顺序为 S^-1 * R^-1 * T^-1。
从父 QTransform 中的相应参数计算逆 S^-1, R^-1 T^-1 非常简单。
推荐阅读
- python - sklearn 的 KFold 函数,带有 shuffle 和 random_state
- azure - 如何同时交换在 Azure 应用服务 Web 应用上运行的 2 层应用程序的部署槽?
- javascript - 调整 Safari 静音自动播放的视频音量
- tornadofx - GraalVM 与 TornadoFX CSS URL 协议的兼容性
- python - Migrating SQLite3 data with foreign keys and auto_increment field to mysql
- c - Why memcmp return int
- java - An error happened during template parsing (spring boot thymeleaf integration with html file)
- linux - Recording alpine container audio
- django - ERR_CONNECTION_TIMED_OUT when trying to access AWS EC2 hosted Django application
- c - C language also supports abstraction?