C
Qt Quick Ultralite 视图变换示例
展示如何在 Qt Quick Ultralite 应用程序中实现透视(2.5D)变换。
概览
perspective_transforms
示例使用 Matrix4x4
QML 变换类型实现透视变换和准 3D 效果。它通过音乐专辑封面流动组件来演示这一点。
示例的 UI 在顶部包含一组单选按钮,可以切换以下封面流动样式
- 旋转木马
- 圆形
- 圆形 2D(使用正交变换)
- 透视
封面流动组件在中间渲染。它根据所选的样式动态地显示专辑封面运动。
在最底部,一组滑动控件允许用户调整摄像头参数,如升降角度或倾斜角度。
此外,示例还具有“演示”模式,当用户交互超过5秒时启用。在此模式下,动画在可用的封面和视图类型之间切换。当用户开始与应用程序交互时,动画停止。
目标平台
项目结构
应用程序项目结构没有与透视变换相关的特殊功能,但它比最小更复杂。它包含以下子目录
- controls - 包含示例中使用的自定义 UI 控件的实现,例如 CheckBox、Slider 或 RadioButton
- imports - 在项目中使用 QML 模块的内容 - 主要用于全局常量(使用单例)
- resources - 图形资产 - 大多数是专辑封面
CMake 项目文件
本示例的 CMakeLists.txt 将 perspective_transforms
定义为主要可执行目标。
... qul_add_target(perspective_transforms QML_PROJECT mcu_perspective_transforms.qmlproject SELECTORS no_controls GENERATE_ENTRYPOINT ) elseif(NOT QUL_PLATFORM MATCHES "^stm32f769i" AND NOT QUL_PLATFORM MATCHES "^stm32f469i" AND NOT QUL_PLATFORM MATCHES "^mimxrt1170-evkb") qul_add_target(perspective_transforms QML_PROJECT mcu_perspective_transforms.qmlproject SELECTORS small_controls GENERATE_ENTRYPOINT ) ...
QmlProject 文件
所有相关的 QML 文件都在 QmlProject 文件中指定。
... QmlFiles { files: [ "CoverFlow.qml", "CoverFlowState.qml", "Cover.qml", "IdleTimer.qml", "perspective_transforms.qml" ] } QmlFiles { files: [ "controls/CheckBox.qml", "controls/RadioButton.qml", "controls/Slider.qml" ] } ...
所有图像资源都已添加带有 ImageFiles.MCU.resourceOptimizeForRotation 属性启用。这将提高支持平台上转换性能。
ImageFiles { files: [ "resources/cover0.jpg", "resources/cover1.jpg", "resources/cover2.jpg", "resources/cover3.jpg", "resources/cover4.jpg", "resources/cover5.jpg", "resources/cover6.jpg", "resources/cover7.jpg", "resources/cover8.jpg", "resources/cover9.jpg", ] MCU.base: "resources" // Optimize all assets for transformations MCU.resourceOptimizeForRotation: true
此外,使用 constants.qmlproject 定义了一个包含全局常量的模块并添加到主项目文件中。
ModuleFiles { files: [ "imports/constants/constants.qmlproject", "configuration/configuration.qmlproject" ] MCU.qulModules: ["Controls"] }
应用程序 UI
perspective_transforms.qml 文件定义了应用程序的用户界面。
它布局了主要的 UI 组件,如单选按钮和滑块。这些都是定义在 controls
子目录中的自定义控件。
import "controls"
IdleTimer
在检测到用户不活动时负责动画 UI。这是为没有触摸屏的平台设计的。它公开了两个信号,用于独立切换封面流类型和当前专辑选择。
IdleTimer { id: idleTimer property int coverDir: 1 onSwitchCover: { ... } onSwitchFlowType: { ... } }
最相关的是封面流组件的实例化。这从创建一个持有 CoverFlow
组件当前状态的对象开始。
CoverFlowState { id: currentState screenWidth: root.width screenHeight: root.height } ...
然后,CoverFlow
组件负责实际的渲染。
CoverFlow { anchors.fill: parent currentState: currentState }
CoverFlowState
CoverFlowState.qml 文件包含所有影响 CoverFlow
渲染方式的参数。它配置了以下参数
- 屏幕/画布大小
CoverFlow
大小和位置- 要渲染的封面数量和当前选中封面索引
- 相机设置,如视场角或剪切距离、俯仰、倾斜等
- 特定封面流类型的设置
- 当前视图类型和与类型过渡相关的参数
形态比是一个用于在不同封面流类型之间进行动画过渡的属性。
property real morphRatio: 1 property int currentViewType: CoverFlowType.Carousel property int previousViewType: CoverFlowType.Carousel NumberAnimation on morphRatio { id: morphAnimation from: 0.0 to: 1.0 duration: 200 }
使用 switchViewType
在封面流类型之间切换。
function switchViewType(newType : int){ previousViewType = currentViewType currentViewType = newType morphAnimation.start() }
CoverFlow
CoverFlow.qml 文件实现了封面流组件。它负责创建多个 Cover
组件的实例,其中其实际的渲染逻辑得到实现。
该组件有一个属性,用来持有其当前状态。
Item { id: root property CoverFlowState currentState ...
一个 Repeater 负责根据封面流状态中定义的值动态创建一定数量的 Covers
。
Repeater { model: root.currentState.numberOfCovers delegate: Cover { required property int index texture: "cover" + index + ".jpg" coverIndex: index state: root.currentState postMatrix: root.globalPostMatrix preMatrix: root.globalPreMatrix reflectionTransform: root.reflectionTransform } }
Cover
Cover.qml 实现了渲染封面(及其反射)所需的所有矩阵计算,使用正确的变换。Cover
控件是一个 Rectangle,其中带有 Image
项目(应用了适当的变换)作为其子项。一个图像代表实际的封面图像,而第二个用于渲染第一个图像的反射。两个图像项都使用 Matrix4x4 变换,其中 matrix
属性绑定到返回 matrix4x4 QML 基本类型的适当函数(请区分 Matrix4x4 变换对象和 matrix4x4 基本类型)。
Rectangle { id: cover property string texture property int coverIndex property CoverFlowState state property matrix4x4 coverTransform: calcCoverTransform() property matrix4x4 postMatrix property matrix4x4 preMatrix property matrix4x4 reflectionTransform z: calcFinalZ() Image { id: coverImageBase source: cover.texture transform: Matrix4x4 { matrix: coverTransform } opacity: 1.0 } Image { id: mirrorImageBase visible: cover.state.showReflection source: cover.texture transform: [ Matrix4x4 { matrix: reflectionTransform }, Matrix4x4 { matrix: coverTransform } ] opacity: 0.1 } ...
可以使用 Qt::matrix4x4() 工厂方法创建一个新的 matrix4x4,提供所有矩阵组件。以下是一个举翻译矩阵的例子
function mtxTranslate(x : real, y : real, z : real) : matrix4x4 { return Qt.matrix4x4(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1) }
matrix4x4 类型有以下算术运算可供使用
- 矩阵相乘 matrix4x4::times
- 矩阵与标量相乘 matrix4x4::times
- 矩阵相加 matrix4x4::plus
所有这些都在 calcCoverTransform()
函数中使用
function calcCoverTransform() : matrix4x4 { var previousViewType = state.previousViewType var currentViewType = state.currentViewType if (state.morphRatio == 0) { currentViewType = previousViewType } else if (state.morphRatio == 1) {
矩阵4x4类型有十六个值,每个值可以通过属性m11
到m44
(行/列顺序)访问。这在计算封面整体z
位置时使用。
function calcFinalZ() : real { var coverTransform = cover.coverTransform var x = state.coverSize/2 var y = state.coverSize/2 var inv_d = 1.0 / (coverTransform.m41 * x + coverTransform.m42 * y + coverTransform.m44) var fX = (coverTransform.m11 * x + coverTransform.m12 * y + coverTransform.m14) * inv_d var fZ = (coverTransform.m31 * x + coverTransform.m32 * y + coverTransform.m34) * inv_d var littleX = Math.abs(fX - state.coverFlowX - state.coverFlowW * 0.5) return -fZ * 100000 - littleX }
Cover.qml实现了在矩阵上操作的多项功能,可以用作参考。这些功能可以分为以下几类:
- 基本矩阵生成函数(平移、缩放、旋转、透视)
- 计算前转换和后转换矩阵(相机矩阵和初始封面转换)
- 计算针对单个封面流类型的最终转换
所有这些基本构建块足以实现复杂的2.5D效果。
文件
- perspective_transforms/CMakeLists.txt
- perspective_transforms/Cover.qml
- perspective_transforms/CoverFlow.qml
- perspective_transforms/CoverFlowState.qml
- perspective_transforms/IdleTimer.qml
- perspective_transforms/configuration/+no_controls/Configuration.qml
- perspective_transforms/configuration/Configuration.qml
- perspective_transforms/configuration/configuration.qmlproject
- perspective_transforms/controls/CheckBox.qml
- perspective_transforms/controls/RadioButton.qml
- perspective_transforms/controls/Slider.qml
- perspective_transforms/imports/constants/+small_controls/Constants.qml
- perspective_transforms/imports/constants/Constants.qml
- perspective_transforms/imports/constants/CoverFlowType.qml
- perspective_transforms/imports/constants/constants.qmlproject
- perspective_transforms/imports/constants/qmldir
- perspective_transforms/mcu_perspective_transforms.qmlproject
- perspective_transforms/perspective_transforms.qml
图像
- perspective_transforms/resources/cover0.jpg
- perspective_transforms/resources/cover1.jpg
- perspective_transforms/resources/cover2.jpg
- perspective_transforms/resources/cover3.jpg
- perspective_transforms/resources/cover4.jpg
- perspective_transforms/resources/cover5.jpg
- perspective_transforms/resources/cover6.jpg
- perspective_transforms/resources/cover7.jpg
- perspective_transforms/resources/cover8.jpg
- perspective_transforms/resources/cover9.jpg
另请参阅Matrix4x4、matrix4x4和Qt::matrix4x4。
在某些Qt许可证下提供。
了解更多信息。