C
Qt Quick Ultralite の perspective_transforms の例
Qt Quick のUltraliteアプリケーションで、パースペクティブ(2.5D)変換を実装する方法を示します。
概要
このperspective_transforms のサンプルでは、Matrix4x4 のQML変換タイプを使用して、パースペクティブ変換と準3D効果を実装しています。音楽アルバムのカバーフローコンポーネントを用いて、その動作を実演しています。

この例のUIの上部にはラジオボタンのグループがあり、以下のカバーフロースタイルを切り替えることができます:
- カルーセル
- サークル
- Circle 2D(直交変換を使用)
- パースペクティブ
中央にはカバーフローコンポーネントが表示され、選択されたスタイルに応じてアルバムカバーの動きがアニメーション化されます。
画面の最下部には、スライダーコントロールのグループがあり、ユーザーはこれを使って仰角や傾斜角などのカメラパラメータを調整できます。
さらに、このサンプルには「デモ」モードがあり、5秒以上ユーザー操作がない場合に有効になります。このモードでは、利用可能なカバーや表示タイプ間の切り替えがアニメーションで表示されます。ユーザーがアプリケーションの操作を開始すると、アニメーションは停止します。
対象プラットフォーム
プロジェクト構造
アプリケーションプロジェクトの構造には、パースペクティブ変換に関連する特別な機能はありませんが、最小構成よりも若干複雑になっています。以下のサブディレクトリが含まれています:
- controls -CheckBox 、Slider など、この例で使用されるカスタム UI コントロールの実装が含まれています。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 "^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ファイルは、アプリケーションのユーザーインターフェースを定義します。
このファイルでは、RadioButton や Slider などの主要な UI コンポーネントのレイアウトが定義されています。これらは、controls サブディレクトリで定義されているカスタムコントロールです。
import "controls"IdleTimer は、ユーザーの非アクティブ状態が検出されたときに UI のアニメーション処理を行います。これは、タッチスクリーンを備えていないプラットフォームを対象としています。このモジュールは 2 つのシグナルを公開しており、これらはカバーフローのタイプと現在選択されているアルバムの切り替えに個別に使用されます。
IdleTimer {
id: idleTimer
property int coverDir: 1
onSwitchCover: {
...
}
onSwitchFlowType: {
...
}
}最も重要な部分は、Cover Flowコンポーネントのインスタンス化です。これは、CoverFlow コンポーネントの現在の状態を保持するオブジェクトの作成から始まります。
CoverFlowState {
id: currentState
screenWidth: root.width
screenHeight: root.height
}
...その後、CoverFlow コンポーネントが実際のレンダリングを担当します。
CoverFlow {
anchors.fill: parent
currentState: currentState
}CoverFlowState
CoverFlowState.qmlファイルには、CoverFlow のレンダリング方法に影響を与えるすべてのパラメータが定義されています。このファイルでは、以下のパラメータを設定します:
- 画面/キャンバスのサイズ
CoverFlowサイズと位置- レンダリングするカバーの数と、現在選択されているカバーのインデックス
- FOVやクリッピング距離、仰角、傾斜角などのカメラ設定
- 特定のカバーフロータイプの設定
- 現在のビュータイプに関する情報およびタイプ遷移に関連するパラメータ
モーフ比は、異なるカバーフロータイプ間のアニメーションによる遷移に使用されるプロパティです。
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 コントロールは、Image アイテム(適切な変換が適用されている)を子要素とするRectangle です。1 つの画像は実際のカバー画像を表し、もう 1 つは前者の反射をレンダリングするために使用されます。両方の Image アイテムは、Matrix4x4 変換を使用しており、matrix プロパティは、matrix4x4 QML 基本型(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
}
...新しいmatrix4x4 は、Qt::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) {matrix4x4 型には16個の値があり、それぞれ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ライセンスの下で利用可能です。
詳細はこちらをご覧ください。