Qt Graphs改善点の理解と利用: 第2回

本稿は「QtGraphs 개선점 이해 및 활용하기 - 2편」韓国版の抄訳です。
 

第2回のブログでは、前回の第1回からさらに Qt Graphs の具体的な改善点を説明し、3Dカスタムアイテムについても追加で説明します。最後に、波高分析アプリの実習を終了します。

概要

この記事では、Qt Graphs の構造的改善である Qt Graphs と Qt Quick 3D との関係について説明します。Quick 3Dを活用することで得られる性能的な安定性と、Qt Graphsで発生する新しい機能的な利点について説明します。 また、第1回で行った波のピーク分析アプリに 3D カスタムオブジェクトと 3D 視覚効果を適用してみます。

 

Qt Graphsの改善点

既存の Data Visualization モジュールのレンダリングおよび構造

過去、Qt 5 の Data Visualizationモジュールは独自のレンダリングクラスを保有しており、このクラスは OpenGL APIを活用してレンダリングを実行していました。 そのため、独自のレンダリングクラスの機能を別途管理する必要があり、OpenGL を活用できない環境では性能的な制限がありました。 また、3D 視覚効果を適用する際にも別途の手作業が必要でした。 もちろん、このような特性が短所だけではありません。 モジュールの要件に合わせて便利に独自の機能を開発できるというメリットもあります。

下図は、Qt 5 の Data Visualization モジュールがレンダリングを実行する方法を示します。

image-2025-1-10_17-48-3

要約すると、Data Visualization モジュールでは、独自のレンダリングコードが存在するため、コードの重複やメンテナンスの問題、そして OpenGL のレンダリング依存性によって引き起こされる問題を抱えていました。

Qt GraphsのQt Quick 3D を活用した構造改善

Qt 6 の Qt Graphs モジュールからは、独自のレンダリングクラスを使わず、レンダリングバックエンドとして Quick 3D モジュールを使うように再設計されました。 つまり、Qt Graphs の View は Quick 3D モジュールの ViewPort を継承し、ViewPort が持つ機能と特性を継承するようになりました。 これにより、以下のように機能の動作が変更されました:

  • RHI ベースの Scene Graph レンダリングの実行
  • SceneEnvironment、Light Control、Camera などの既存/新規機能が Quick 3D 方式で処理

内部的な変更点を知らなければ、Qt 6 の Qt Graphs モジュールはユーザーの立場で単純な機能統合/追加程度に感じられるかもしれません。しかし、内部の変更点を理解すれば、技術的に大きな構造改善が行われたことを実感できるでしょう。下記は Qt 6 での Qt Graphs と Quick 3D の関係を図で表したものです。

image-2025-1-13_10-3-0

簡単な例を挙げましょう。 Qt Graphs が Quick 3D を利用していることは、すでにわかっています。これにより、Qt Graphs で可能なことの一つは、3DGraph に Quick3D で適用可能な属性の一つであるSceneEnivronment を適用できることです。 つまり、以下のように、グラフに SceneEnvironment を適用してToneMapを適用することができます。

example.ui
Surface3D {    id: surfaceGraph     environment: ExtendedSceneEnvironment {        tonemapMode: ExtendedSceneEnvironment.TonemapModeFilmic    }    ...}

 

番外編
Qt Graph 3D でカスタムアイテムを追加する方法

Qt Graphs が提供する基本的な要素だけでは、データを視覚化するには不十分な場合があります。例えば、グラフに自分だけの特別なマーカーを追加してデータの視覚化を補完したり、カスタマイズしたい場合があります。このような状況では、Custom3DItem という要素を使用して、独自の 3D オブジェクトを Graph に追加することができます。カスタム 3D モデルを使用するには、Qt Framework が解釈可能な 3D オブジェクトのメッシュファイルが必要です。通常、3DアセットはMaya3ds Max、またはBlender のようなツールを使って作成しますが、これらのツールを使って作成した結果が Qt Frameworkで使用できない場合があります。このため、Balsam というツールが存在し、Qtが解釈可能なように 3D asset を変換してくれます。

上の過程で Custom3DItem に mesh file を適用してカスタム 3D オブジェクトを Graph に追加することができます。このように追加された 3D カスタムオブジェクトは下図のように SceneGraph で解釈された後、レンダリングされます。Custom3DItem 以外にも、Qt ではこれを継承して下記のようにもっと具体的なタイプを提供しています:

  • Custom3DLabel: カスタムラベルオブジェクト
  • Custom3DVolume:3Dテクスチャを適用可能なオブジェクト

image-2025-1-13_11-9-23

 
コーディング実習で概念を身につけましょう

前回の実習の残りのステップを進め、波のピークアプリを完成させましょう。 今回はステップ3とステップ4を進めます。🌊 🌊

  1. グラフモデルを作成 (第1回)
  2. グラフビューを作成 (第1回)
  3. カスタム 3D オブジェクトを追加
  4. 3D 視覚効果を適用
カスタム 3D オブジェクトを追加

それでは、波の最高点を表すために 3D ブイオブジェクトを追加し、また、波の高さを表記するラベルを一緒に追加してみましょう。これは Custom3DItem と Custom3DLabel を使って実現します。 Surface3D は customItemList というプロパティを持っています このプロパティにカスタムオブジェクトを追加してグラフに表示することができます。Custom3DItem に望む形のオブジェクトを作るため、メッシュ obj ファイルを作成する必要があります。 このため、Blender というツールを使って非常に簡単なドーナツ形のメッシュファイルを作成し、このメッシュファイルを Qt Balsam ツールを使って変換して obj ファイルを生成しました。最後に、ブイの色と似たテクスチャファイルを Custom3DItem に適用してブイのように見えるようにしました。

下記のコードを参考してください。

SeaSurfaceForm.ui
Surface3D {    id: seaSurfaceGraph     ...     customItemList: [        Custom3DItem {            id: markerId            meshFile: "SeaAnalysis/mesh/buoy.obj"            textureFile: "SeaAnalysis/mesh/coral.jpg"            scaling: Qt.vector3d(0.15, 0.15, 0.15)            visible: false // Start hidden        },        Custom3DLabel {            id: labelId            backgroundColor: "black"            textColor: "orange"            font.bold: true            visible: false            scaling: Qt.vector3d(1.5, 1.5, 1.5)        }    ]}
 

次は、ブイとラベルの位置を更新するコードを書きます。 このため、 WaveDataProxy にhighestPeakChanged というシグナルを新しく定義して、一番高い波の位置が更新された時、その位置にブイとラベルを移動させるコードを書きました。ブイとラベルがより自然に動くように、Vector3dAnimation を適用して位置を更新するようにしました。

SeaSurface.qml
SeaSurfaceForm {     ...     Connections {        target: waveDataProxyId        function onHighestPeakChanged () {            markerId.visible = true;            labelId.visible = true;             // Animate the marker's position            markerPositionAnimation.from = markerId.position            markerPositionAnimation.to = waveDataProxyId.highestPeakPos            markerPositionAnimation.running = true             // Animate the label's position            labelPositionAnimation.from = labelId.position            labelPositionAnimation.to = waveDataProxyId.highestPeakLabelPos            labelPositionAnimation.running = true             labelId.text = " Highest Peak: " + waveDataProxyId.highestPeakPos.y.toFixed(1) + " M ";        }    }     Vector3dAnimation {        id: markerPositionAnimation        target: markerId        property: "position"        duration: 150    }     Vector3dAnimation {        id: labelPositionAnimation        target: labelId        property: "position"        duration: 150    }}

 

このように Custom3DItem、Custom3DLabel、イベントスロット、そして Vector3dAnimation を適用して実行すると、下記のように一番高い波のマーカーとなるブイを確認することができます。 ring buoy

image-2025-1-24_16-25-52

3D視覚効果を適用

先ほど、Qt Graphs が Quick 3D を活用することで、より多くの視覚効果を適用できることを紹介しました。 また、これらの視覚効果がRHIによってパフォーマンス的により安定して実行できることも紹介しました。したがって、theme、texture、そして scene environment のような視覚効果を適用して、波をよりリアルにすることができます。まずテクスチャを Surface3D に適用すると、下記のような結果を確認することができます。

Surface3DSeries {    id: surfaceSeriesId     drawMode: Surface3DSeries.DrawSurface    textureFile: "SeaAnalysis/image/ocean_texture.jpg"}

 

以下は上のテクスチャを適用して実行した結果です。

image-2025-1-24_16-29-40

 

また、座標軸を消して、Quick 3D の活用で可能になった SceneEnvironment の glow 効果などを適用することで、夜の海のような効果も表現できるようになります。

以下はこれらの視覚効果を Surface3D に適用するコードです。

Surface3D {    id: seaSurfaceGraph     anchors.fill: parent     theme : GraphsTheme {        id: surfaceTheme        colorScheme: Qt.Dark        plotAreaBackgroundVisible: false        labelsVisible: false        gridVisible: false    }     environment: ExtendedSceneEnvironment {        backgroundMode: ExtendedSceneEnvironment.Color        clearColor: "black"        tonemapMode: ExtendedSceneEnvironment.TonemapModeNone        adjustmentContrast: 4        glowEnabled: true        glowStrength: 1.2        glowIntensity: 0.8        glowBloom: 0.9        glowUseBicubicUpscale: true        glowLevel: ExtendedSceneEnvironment.GlowLevel.One                   | ExtendedSceneEnvironment.GlowLevel.Two                   | ExtendedSceneEnvironment.GlowLevel.Three                   | ExtendedSceneEnvironment.GlowLevel.Four    }     ...}

Surface3D のグリッドとラベルが非表示になり、SceneEnvironment の glow プロパティを利用してライト効果が追加されました。これで Qt Graphs を使って夜の海の波を表現し、波のピークを視覚化して みました water wave

練習コードはこちらからご覧ください。

app_sample (1)

まとめ

今回のブログシリーズでは、Qt 6.8 で新しく導入された Qt Graphs モジュールの基本的な概念と、Qt Graphs に適用されたモデル/ビュープログラミングの概念を見て、過去の構造と改善された現在の構造を比較しました。 また、Qt Graphs が Quick 3D を活用して、Rendering Hardware Interface (RHI) などの利点をどのように活用できるかを調べました。 さらに、3D データ作業は2Dデータと比較して複雑であり、3D グラフのモデルを設計する際に、Data Proxy などの追加的な考慮事項を探求しました。最後に、この記事で説明した概念を応用して、Qt Graphs を使った簡単な波高分析アプリを作成しました。

Qt Graphs は、学ぶべきことや練習することがたくさんある膨大なトピックです。 この記事が、Qt Graphsを積極的に使用していない場合でも、Qt Graphsとその利点に慣れるのに役立つことを願っています。

もっと詳しく知りたいですか?

10日間の無料トライアルで Qt を直接体験してください!

Qt 6 トライアルする

Qt 専門家にお問い合わせする


Blog Topics:

Comments