このページでは

C

Qt Quick Ultralite perspective_transforms の例

Qt Quick Ultralite アプリケーションに透視(2.5D)変換を実装する方法を示します。

概要

perspective_transforms の例では、Matrix4x4 QML transform タイプを使って、透視変換と擬似3D効果を実装しています。この例では、音楽アルバムのジャケットフローコンポーネントを使用しています。

この例のUIには、上部にラジオボタンがあり、以下のカバーフローのスタイルを切り替えることができます:

  • カルーセル
  • サークル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
    )
...
Qmlプロジェクトファイル

関連する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をアニメーションさせる処理を行います。これはタッチスクリーンのないプラットフォーム向けです。これは2つのシグナルを公開しており、カバー・フロー・タイプと現在のアルバム・セレクションを独立に切り替えるために使用される。

    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 サイズと位置
  • レンダリングするカバーの数と現在選択されているカバーのインデックス
  • 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.qmlファイルは、カバーフローコンポーネントを実装します。実際のレンダリングロジックが実装されるCover コンポーネントのインスタンスを複数作成します。

このコンポーネントには、現在の状態を保持するプロパティが1つあります。

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.qmlは、右変換を使用してカバー(およびその反射)をレンダリングするために必要なすべての行列計算を実装します。Cover contorlはRectangle 、その子としてImage アイテム(適切なトランスフォームが適用されている)を持つ。1つの画像は実際のカバー画像を表し、2つ目の画像は1つ目の画像の反射をレンダリングするために使用されます。どちらの画像アイテムも、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 型では以下の算術演算が可能です:

これらはすべて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エフェクトを実装するのに十分です。

ファイル

画像

Matrix4x4,matrix4x4,Qt::matrix4x4()も参照

特定の Qt ライセンスの下で利用可能です。
詳細を見る。