Qt Quick 3D 6.0アップデート

本投稿は「What is new in Qt Quick 3D 6.0」の抄訳です。
しばらくの間Qt Quick 3D関連の最新情報を更新しておりませんでしたが、何もやっていなかったというわけではなく、Qt Quick 3DのQt 6.0対応に注力していたため、なかなか情報更新ができなかったのが事実です。そのため、今日は我々が今まで行ったことついてご紹介しようと思います。

Qt Quick 3Dでどこでもレンダリング

Qt 6リリースに向けて一番大変だったのは既存の描画エンジンをQt Rendering Hardware Interface(RHI)にポーティングする作業でした。その分価値がある作業であり、プラットフォームが提供するグラフィックスAPIに合わせてQt QuickQt Quick3Dを最適化できるようになりました。
  • OpenGL (version 3以降)
  • OpenGL ES (version 2以降)
  • Vulkan (1.0以降)
  • Direct3D 11 (11.1以降)
  • Metal

これによって、どんなプラットフォームとグラフィックスAPIを選択しても、Qt Quick 3Dは該当APIの中身を理解する必要なく使えるようになりました。たとえグラフィックスAPIの知識が必要な場合でも、例えば座標系の原理など、QtはOpenGLの概念から他のNative APIに直接変換する形にしています。最近いろんなAPIが次々に登場してしまい、グラフィックスの開発はだんだん大変になってましたが、Qt QuickとQt Quick 3Dを使えば、もう心配する必要はありません。

2Dと3D統合の完成度の向上

以前のバージョンでは3Dの中で2Dが描画される際は、まずはTextureのようなOffscreenに描画される必要がありました。これはQt QuickのLayerの概念と似ているものです。Qt 6からは2Dが3Dシーンに直接描画されるようになりました。今までQt Quickで遠近感を表現することができなくて不便を感じていた方には朗報です。
さらに使い方もさらに簡単になりました。下のコードでどうやって3Dシーンで2Dコンテンツを表現したのかご覧ください。


import QtQuick
import QtQuick3D

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("2D in 3D")
    color: "black"

    View3D {
        anchors.fill: parent

        PerspectiveCamera {
            z: 200
        }

        DirectionalLight {

        }

        Model {
            source: "#Cube"
            materials: DefaultMaterial {}
            eulerRotation.y: 20
            Node {
                // Empty spatial Node to give 2D item
                // a position in 3D space
                y: 100
                Text {
                    // 2D content in 3D
                    anchors.centerIn: parent
                    text: "Cube Label"
                    color: "white"
                }
            }
        }
    }
}

2Dであるテキスト部品が3Dキューブの子供として配置され、キューブを動かすとテキスト部品も合わせて動いていることが確認できます。
 

ただのテキストではなくもっと複雑なQt Quickコンテンツも表現できます。次のようなコードになると思います。

import QtQuick
import QtQuick3D

Window {
    visible: true
    width: 640
    height: 480

    View3D {
        anchors.fill: parent

        PerspectiveCamera {
            z: 200
        }

        DirectionalLight {

        }

        Texture {
            id: dynamicQMLTexture
            sourceItem: Rectangle {
                width: 256
                height: 256
                color: "pink"

                Text {
                    anchors.centerIn: parent
                    text: "Dynamic Texture!"
                    color: "white"
                    font.pointSize: 24
                }
            }
        }

        Model {
            source: "#Cube"
            eulerRotation.y: 20
            materials: DefaultMaterial {
                diffuseMap: dynamicQMLTexture
            }
        }
    }
}
Texture部品のsourceItemプロパティでQt Quickの部品を指定することができます。これによって、ご覧のように内部でQt Quick部品をQSGTextureに描画しテクスチャーとして取り扱うことができます。

glTF2サポートの改善

Qt Quick 3DはglTF2コンテンツととても相性がよくなりました。glTF2のほとんどの仕様をサポートできるようになりました。一番大きな変化点はgfTF2のリギングアニメーションをインポートできることです。

brainstem-dance

もう一つ大きな変化はバイナリのキーフレームをQtQuickTimelineにインポートできるようになったことです。

6.0で入っていなかった機能はglTF2のモーフィングアニメーションのサポートです。この作業は進んではいたのですが、残念ながら今回の6.0のスケジュールには間に合いませんでした。近いうちにサポートする予定です。
また、gfTF2のアセットがデザイナさんの3Dツールと同様に描画されるように再現性を高める作業も取り組んでおりました。我々の目標はglTFを100%サポートすることであり、これからもさらに力をいれて改善を行いたいと思います。

カスタムマテリアルとポストプロセスエフェクトの再設計

Qt5で少し現実的に妥協しなければいけなかった部分がカスタムマテリアルとポストプロセスエフェクトでした。これはQt 3D Studioとほぼ同等なものでしたが、使い方も簡単ではなく、描画も最適化されていなかったのです。Qt 6でRendering Hardware Interfaceを採用後、さらに厳密に調査した結果、もっと改善できることが分かりました。

カスタムマテリアル

カスタムマテリアル機能の目的はユーザが自分のシェーダモデルを使ったマテリアルを作成できるようすることです。通常これは直接シェーダコードを作成することを意味します。Qt QuickではShaderEffectと呼ばれるAPIを提供することで2Dのシェーダを適用できます。またQMLでプロパティをシェーダUniformにバインドする強力な機能も提供しております。3Dマテリアルでも同じようにを提供するつもりでしたが、2Dとは違い、シェーダを書く際に、考慮してはいけない外部要因がたくさんありました。2Dの場合は該当するオブジェクトのテクスチャーそのものだけ処理すればよいですが、3Dはライティング、シャドウ、ブレンディングなど外部要素もシェーダコードの中で全部考慮しなくてはいけません。そのため多くのユーザにとって自分なりのマテリアルを作ることは難しかったのです。

このような理由でマテリアルを作成するための機能をより強化しました。新しいカスタムマテリアルAPIの詳細はここで確認してください。

ポストプロセスエフェクト

ポストプロセスエフェクトは以前バージョンと大きな変化はなく、ただし、カスタムマテリアルAPIと同様な仕組みを入れました。ポストプロセスエフェクトの基本はShaderEffectと同様ですが、3Dの空間向けですのでデプスバッファもアクセスできます。またShaderEffectではできなかったマルチパス処理がポストプロセスエフェクトではできます。ポストプロセスエフェクトのAPIの詳細はここで確認してください。

カスタムマテリアルとポストプロセスエフェクトはかなり強力でもありながらいろんな利用シーンがありますが、この記事だけではうはまく説明できませんので別途ブログの記事を執筆する予定です。待ちきれない方は、ここで全体的な説明と詳細を確認してください。

パワフルなQQuickRenderControlとQt Quick 3D

Qt QuickではQQuickRenderControlというとても強力な機能があります。これを使うとQt Quickの描画先を自由に決めることができます。QQuickWindowに縛られることはありません。Qt 6のRHI上でQQuickRenderControlが動くようになったため、さまざまな場所でどんなグラフィックスAPIを使っても3Dを描画することできるようになりました。ご覧の例はVR・AR機械でもQtQuick3Dを描画したデモです。


ただし、これは一番シンプルな例であり、今後もっと新しい情報を展開する予定です。

高品質レンダリングのための大きな改善

今回のリリースに向けてレンダリングコードを綿密にレビューしましたが、正しいやり方で動作していることを確認できました。PrincpledMaterialに関しては、Physically Based Rendering (PBR)をより使いやすい形で提供したいと考えていました。しかし、それには慎重な変更が必要です。リアルタイムレンダリングエンジンはオフラインエンジンとは違い、妥協しながら、品質の高いレンダリングに近づけなくてはいけません。性能の最適化が増えるほど、デザイナーが求めている表現とその結果の間の差は大きくなります。その差を減らすのが我々の目標でした。

今までの成果をこの記事で詳細に説明することは難しいのですが、いくつかの例の写真でアセットがどう表現されたのかを確認できると思います。

トーンマッピング

以前のQt Quick 3Dでうまくできなかった部分は色とトーンマッピングを処理する部分です。通常は描画機能は線形な色空間で行われ、スクリーンに描画する直前にsRGB色空間に変換されます。しかしQt Quick 3Dはこのような流れに対応していませんでした。Qt 6になってからこそこのような対応ができ、さらに新しいAPIを導入することで色のトーンマッピングも設定できるようになりました。もちろん、ポストプロセスエフェクトに適用した後自分の設定を行われるケースがある場合は必要に応じてデフォルトで行われるトーンマッピングを解除できます。

テクスチャーフィルタリング

5.15ではすべてのテクスチャーはBilinear filteringしか適用できなかった致命的なバグがありました。6.0からはNearest neighbor filteringも適用できます。またMipmapを生成し、Mipmap filteringも可能になりました。
 

オフラインシェーダベーキング

Qt 6.0はQt Rendering Hardware Interfaceを使って描画を行うため、シェーダコードは事前に作成されることが好ましいですが、3Dシーンの場合通常マテリアルの設定とシーンの内容を組み合わせてシェーダがランタイムで生成されるため簡単にはできません。たとえば、シーンの中にライトが何個あるか、シャドウがオンになってるかなどの状況によって最適なシェーダも異なります。

シェーダ生成ツールを使うと、コマンドラインでシーンを設定することで、どのようなシェーダがランタイムで生成されそうなのかを把握できます。このシェーダのリストを使うとランタイムで該当シーンのマテリアルが必要とするさまざまなシェーダのキャッシュを事前に生成することができます。もちろん、ランタイムでシーンを動的に変更したら、予測できなかった新しい組み合わせが発生され、ランタイムで新しくシェーダを生成する必要性が生じます。
これからも機能の改善は続いて行いますが、ビルドタイムでシーンから必要なシェーダの大半を事前に生成する場合は現状も十分有用だと思います。

iOS サポート

理論的にはQt Quick 3Dは5.15からもiOS上で動くはずでしたが、iOSサポートは当初予定になかったためテストをしていませんでした。Qt 6.0からはQt Quick 3DがiOSで、さらにMetalに最適化された上で動作します。

改善されたリソース管理機能

以前のバージョンのQt Quick 3DはView3Dが解除される際に一緒にGPUのリソースも解除されます。つまり、シーンからモデルかテクスチャーが削除されても、あとで再利用されることを考慮し、GPUのリソースはメモリで残りました。6.0ではリソース管理方法を改善し、GPUリソースがどこからも参照されない時点で解除するようになりました。

ダイナミックジオメトリ

5.15ではC++でランタイムで生成されたジオメトリデータのためのAPIはありましたが、6.0ではもっと使いやすくするために改善が行われました。通常はモデルは静的メッシュファイルが前提されてますがあるケースは事前に知ることができないケースがあります。ダイナミックジオメトリAPI使い、C++でQQuick3DGeometryを継承して生成されたインスタンスをModelのgeometry プロパティに指定します。

これを使いこなすと、いろんなことができると思います。このAPIは三角形ポリゴンのみではなく、ポイントとラインも使えます。

ダイナミックテクスチャー

既にダイナミックにQt Quickからクキスチャーをダイナミックに生成することは可能ですが、場合によってはランタイムでファイルか他のソースから直接読み込んでテクスチャーを生成する必要があります。C++で使えるダイナミックテクスチャーAPIはダイナミックジオメトリAPIと同様にランタイムでテクスチャーデータをロードしてくれます。QQuick3DTextureDataを継承して生成されたインスタンスをTextureのtextureDataプロパティに指定します。

ドキュメントとイグザンプル

Qtが素晴らしい製品になった大きな理由一つはドキュメントとイグザンプルでした。同じようにQt Quick 3Dもこの部分に力を入れてます。ドキュメントとイグザンプルの作成は一通り終わりました。Qt 6のドキュメントはここを確認してください。

まとめ

ご覧のとおり、このような素晴らしいQt Quick 3D機能をQt 6.0リリースに合わせるためにかなり忙しい時期を過ごしました。3D Graphicsの機能と開発範囲はかなり膨大です。現在の機能以外も必要な機能がたくさんあるのは我々も知っております。もし追加してほしい機能がありましたら、ご連絡ください。我々は今後の計画についてたくさんのアイディアがありますが、何が一番重要なのかを考えながら次の作業を取り組みたいと思いますので、たくさんのフィードバックをお待ちしています。

ビデオとライブコーディングをご希望の方はバーチャルのQt World Summitをご覧ください。Qt 6のQt Quick 3Dのほとんどの機能と概念を紹介しております。

 

Blog Topics:

Comments