Skip to main content

Canvas2D: WatchUI デモ

コメント
このブログは「Canvas2D: WatchUI Demo」の抄訳です。  

前回のブログにおいて、私は Canvas2D を紹介しました。これは Qt 6.12 で追加された新しい QML アイテムで、Qt Canvas Painter を介して GPU を利用しながら JavaScript で描画を行うことができます。その記事では API に焦点を当て、Canvas2D とは何か、Qt Quick Canvas と比較してどう違うのか、QCanvasPainter C++ API と比較してどう違うのか、どの程度高速なのか、について説明しました。しかし、その記事を読んだ人の中には、「実際に Canvas2D を使って作った UI はどのような見た目になるのだろう?」と思った人もいるかもしれません。

そこで、Qt 6.12.0 リリースに向けて Canvas2D(および QQEM)のテストを行っていた際に、私はアイデアを示すためのデモアプリケーションを数日かけて作成しました。WatchUI は、3D の腕時計モデル上で動作する、6 つのスワイプ可能なビューを備えたスマートウォッチのデモです。これは、以前 Qt 6.5 リリース のために作成されたスマートウォッチデモをベースにしています。ただし、ウォッチ画面のコンテンツ部分は再実装されており、QQEM のエフェクトだけでなく、Canvas2D も使用しています。デモは次のようなものです:

ウォッチフェイスの内側に見えているものはすべて、Canvas2D によって描画されるか、Qt Quick Effect Maker のエフェクトによってシェーディングされるか、あるいは通常の Qt Quick アイテムによって構成されています。そして、そこには C++ のコードが一行もありません。

これは少し立ち止まって考える価値があります。Canvas2D や QQEM が登場する以前は、このような高性能 UI をカスタム C++ コードなしで実現することは、これほど簡単ではありませんでした。Qt におけるカスタム 2D ビジュアライゼーションは、従来であれば C++ で実装した低レベルの QSG* ノードや QQuickPaintedItem ベースのアイテムを必要としていました。あるいは、Quick Canvas を使う場合は毎フレームのテクスチャアップロードコストを受け入れなければなりませんでした。しかし、このデモではビジュアルレイヤー全体がデータとして構成されています。QML ファイル、JavaScript 関数、シェーダーだけです。例えば ViewWater.qml を編集し、再読み込みを実行するだけでよいのです。あるいは、Qt 6.12 で新たに導入された Hot Reload を使用することもできます。すると 1 秒後には、水面の揺れ方が変わっているのを確認できます。ウォッチフェイス、メータークラスター、ダッシュボードなどの試作において、このような反復開発の速度は非常に大きな意味を持ちます。

Canvas2D と Qt Quick Effect Maker: 理想的な組み合わせ

WatchUI を作るうえで興味深かったのは、Canvas2D 単体ではなく、シェーダーエフェクトとの役割分担が非常に自然であることでした。この 2 つは、それぞれ得意なことが異なります。

Canvas2D は、形状を記述できるジオメトリの描画が得意: 例えば、特定の長さと角度を持つ時計の針、3 つの制御点を通るベジェ曲線、ベースライン上に配置されたテキスト、心拍データのサンプルを結んだポリラインといったものです。つまり、インクをどこに描くかが分かっているものであれば、命令型のパス API を使って数行で記述できます。そして Canvas Painter が、それをキャッシュされた頂点バッファと数回の描画呼び出しへと変換します。

シェーダーエフェクトは、ピクセル単位の処理が得意: ブルームやグロー、プロシージャルノイズ,雲,雨、屈折や歪み、まっすぐな棒グラフをリング状へ曲げる処理、などは、パスを使って再現しようとすると厄介です。例えば、グロー効果を 30 本の半透明な同心円状ストロークで表現しようとすると、遅いうえに見た目も良くありません。しかし、フラグメントシェーダーであれば数行で実装でき、UI が動作する程度の GPU であればほぼ無視できるコストで実現できます。

このデモでは、Canvas2D とシェーダーを複数の方法で組み合わせています:

  • Canvas の背後にシェーダーを配置: TIME & DATE ビューでは、時計表示の背後にプロシージャルな星雲エフェクトを配置しています。WEATHER ビューでは、気温グラフの背後にアニメーションする雨と雲を配置しています。Canvas は `fillColor: "transparent"` そして `alphaBlending: true`を設定した状態で上に配置されるため、Canvas が描画しなかった部分からシェーダーが透けて見えます。

  • Canvas をシェーダー入力として利用: WATER ビューでは、グラスと波打つ水面を Canvas2D で描画しています。そのアイテムには `visible: false`を設定し、バブルシェーダーへ source として渡しています。シェーダーは、そのジオメトリに対して上昇する泡や屈折効果を追加します。このような形状をピクセル単位で計算するのは現実的ではありません。

  • Canvas2D のみを使用: MUSIC ビューと HEARTBEAT ビューでは、シェーダーエフェクトは使用していません。コンテンツはすべて Canvas2D のみで描画されています。

  • シェーダーのみを使用: ACTIVITY ビューでは Canvas2D を一切使用していません。発光するバーをリング状に曲げた表現で構成されており、これは純粋なシェーダーだけで効率的に実現できます。

この 2 つが非常にうまく組み合わさる理由は、どちらも Qt Quick シーングラフの第一級要素(first-class citizen) だからです。Canvas2D アイテムはシーングラフへ直接レンダリングされます。そのため、中間的な QImage は存在せず毎フレームのテクスチャアップロードも発生しません。一方、ShaderEffect はシーングラフのテクスチャを入力として利用します。したがって、この 2 つを重ね合わせるコストは、Qt Quick のアイテムを 2 つ重ねる場合と同程度です。

Qt Quick の統合 2D/3D レンダリング

このデモでは、2D のモックアップではなく、実際の 3D ビューと腕時計モデルを使用しています。時計本体、バンド、ガラス部分は、実際のマテリアルとライティングを備えた Qt Quick 3D シーンとして構成されています。そして、WatchUI アイテム、つまり 6 つのビューからなる 2D UI 全体が、時計の画面としてディスプレイ表面にマッピングされています。

ここで Qt Quick の統合 2D/3D レンダリングアーキテクチャの強みが発揮されます。Qt Quick と Qt Quick 3D は、同じレンダラーと同じグラフィックス抽象化レイヤー(QRhi)を共有しています。そのため、2D のサブツリーを 3D シーン内のテクスチャとして利用でき、3D コンテンツを 2D シーン内へ埋め込むこともできます。しかも、そのためのレンダーターゲットテクスチャ処理を手作業で実装する必要はありません。このデモでは、実際に次の 3 つの利点が得られています:

  1. 2D UI がインタラクティブなままであること: ビューのスワイプ、再生/一時停止ボタンのタップ、水面ビューのボタン操作などは、すべて 3D の表面を介して動作します。なぜなら、それは焼き付けられた画像ではなく、実行中の Qt Quick アイテムツリーそのものだからです。

  2. 1 フレーム、1 レンダラー: 3D の腕時計モデル、2D ビュー、Canvas2D の描画、シェーダーエフェクトは、すべて同じフレームグラフの一部として扱われ、同じ GPU パイプラインへ送られます。「2D レイヤー」と「3D レイヤー」の間の同期問題は発生しません。なぜなら、それらは同一のレンダリングアーキテクチャ上で動作しているからです。

  3. 2D の処理をそのまま再利用できること: 開発中は、まったく同じ WatchUI.qml を 2D ウィンドウ上でフルスクリーン表示できます。そしてデモでは、そのまま変更せずに 3D モデル上へ配置できます。各ビューは、自身がどちらの環境で動作しているのかを意識する必要がありません。

自動車のメータークラスター、家電製品の UI、製品ビジュアライゼーションを開発している人にとって、これは有効な設計パターンです。まず通常の 2D Qt Quick UI としてインタラクティブな画面を作成し、その後でそれを 3D 製品モデルへ配置します。さらに Canvas2D を組み合わせることで、そのインタラクティブな画面は、C++ を書くことなく、完全にアニメーションするカスタムビジュアライゼーションとして実装できるようになります。

次のセクションでは、6 つのウォッチビューそれぞれについて、その主要な部分がどのように実装されているかを順番に説明します。

時間と日付

canvas2d_watchui_view1_clock最初のビューは、先ほど説明した 「Canvas の背後にシェーダーを配置する」 という構成を最も分かりやすく示す例です。

時計の背後で漂っている青い点と線のネットワークは、Martijn Steinrucken による UniverseWithin シェーダーエフェクトを Qt Quick Effect Maker に取り込み、少しカスタマイズしたものです。加えられた変更は、開始時のフェード効果を削除、中心点からの距離を利用して、内容を円形領域内にマスク、ハイライトカラーをパラメータ化し、QML プロパティから簡単に調整できるようにする、です。

一方で、鮮明に表示されている部分はすべて、単一の Canvas2D 要素によって描画されています

  • リムの目盛り(rim ticks): 小目盛りと大目盛りは `lineWidth` が異なるため、別々のパスとして描画しています。72 個の目盛りは、それぞれ 2 組の `beginPath()`/`stroke()` で描画されます。命令型のパス API の優れた点の一つは、バッチ処理が後から加える最適化ではなく、自然な書き方そのものになっていることです。

  • 針(hands): `drawHand()`は 6 行程度で実装されています。`rotate()`、`moveTo(0,0)`、`lineTo(0,-length)`、`stroke()`、そして元の回転へ戻す処理です。時針と分針は単色で描画していますが、秒針は `createRadialGradient()` を使用しています。中心では完全に透明、先端では不透明な白となるグラデーションを設定することで、先端へ向かって細く消えていくような表現を実現しています。この表現を別の方法で実現しようとすると、カスタムポリゴンが必要になるでしょう。

  • 日付と時刻のテキスト: 日付文字列とローカライズされた時刻文字列を `fillText()` で描画しています。その下には、大きなぼかし量を持つ `createBoxShadow()` を配置しています。これによって、星雲の背景から文字を浮かび上がらせる柔らかな暗い影が作られています。新機能の記事でも説明したように、ボックスシャドウはブラー処理ではなく SDF 計算によって実装されているため、必要なのは 1 枚のクアッドだけです。これらのテキストは Qt Quick の Text 要素で描画することもできますが、今回は Canvas2D 側で実装することにしました。

アニメーションも興味深い部分です。秒針は `getMilliseconds()`を参照しているため、フレームごとに再描画されることで、カチカチと動くのではなく滑らかに回転します。さらに、ビューがスライドインおよびスライドアウトする際には、目盛りもアニメーションします。そのため、このビューへスワイプすると文字盤が組み立てられていくように見えます。描画が静的画像ではなく動的に行われることで可能になる、こうした細かな演出を味わいたいなら、ぜひ動画をスローモーションで見てみてください。

天気

canvas2d_watchui_view2_weather
天気ビュー(上図)は、レイヤーによってではなく、画面領域によって 2 つの技法を使い分けています。

上部 3 分の 2、つまり曇った空と斜めに流れる雨の筋は、`WeatherRainEffect` シェーダーによって描画されています。これは Qt Quick Effect Maker の組み込みの雨ノードと雲ノードを組み合わせて作成したものです。内部的には、異なるスケールの雨テクスチャを 4 層重ね、それぞれをスクロールさせることで視差効果を生み出しています。また、雲は遠近歪みを加えて描画されるため、地平線が遠くにあるように見えます。しかし、QQEM を使う場合、そのような内部実装を理解する必要はありません。エフェクトノードを配置し、パラメータを調整して、エフェクトとして出力するだけです。

このエフェクト要素は意図的に画面上部へ配置されています。そのため、雨はステータスバー部分にも降り続けます。これによって、天気表示が単なるウィジェットではなく、時計全体の一部であるかのように感じられます。

ここで私が特に気に入っている細かな演出は、ビューのスワイプアニメーション状態と雨エフェクトの風向きをプロパティバインディングで結び付けている点です。シェーダー内の風向きはビュー遷移によって制御されているため、ビューが表示されるときには雨が一方向へ傾き、ビューが消えるときには逆方向へ傾きます。このように、物理的なエフェクトをスクロール位置と連動させるのは、ユーザーにとって心地よい演出になります。

一方、下半分の天気予報グラフは Canvas2D が担当しています:

  • 気温グラフ(temperature curve) は、3 つの制御点を持つ `bezierCurveTo()` で描画されています。同じ座標データを使って 2 回描画されます。最初は、基準線まで閉じたパスとして描画し、半透明の白から完全な透明へ変化する縦方向の `createLinearGradient()` で塗りつぶします。次に、開いたパスとして白色でストローク描画し、`lineCap = "round"`を設定しています。

  • 時間軸(hour axis) は"8", "12", "16", "20"を `fillText()` で描画しています。さらに、4 本の縦グリッド線を 1 つのパスにまとめて描画しています。

  • 天気アイコン(weather icons) は`drawImage()`を使って描画されます。PNG 画像は`Component.onCompleted` 内で `loadImage()` によって事前に読み込まれています。これらのアイコンは Canvas2D の path2d と SVG パスを使って描画することも可能ですが、アイコンを拡大縮小する必要がないため、画像を使用する方法でも十分です。

今回は、左上にある場所名と気温のテキストは通常の Qt Quick の `Text` アイテムで実装されています。このような静的テキストを Canvas 上へ描画する理由は特にありません。また、同じビュー内で宣言型の Qt Quick アイテムと Canvas 描画を組み合わせても、追加のコストは発生しません。

音楽

canvas2d_watchui_view3_music
音楽ビュー(上図)は、90 年代音楽に対して素晴らしい趣味を持っていることを示しています。また、このビューは 100% Canvas2D で構成されており、シェーダーエフェクトは一切使用していません。このビューは、調整可能なアンチエイリアシング(adjustable antialiasing) 機能を紹介するために用意されています。

バー状のスペクトラムは、ダミーのオーディオデータから生成された合成波形です。形状が自然に先細りになるよう、最初と最後の数本のバーにはフェードが適用されています。すべてのバーは、`moveTo()`/`lineTo()`の組み合わせで 1 つのパスにまとめられ、さらに`lineCap = "round"`が設定されています。その後、この単一のパスに対して 2 回 ストローク描画が行われます:


ctx.strokeStyle = g1;            // 5-stop rainbow linear gradient
ctx.lineWidth = 1.6 * lineWidth;
ctx.antialias = 10;              // soft edges -> glow
ctx.stroke();
ctx.strokeStyle = "#ffffff";
ctx.lineWidth = lineWidth;
ctx.antialias = 1;               // crisp
ctx.stroke();

それがグロー効果のすべてです。最初の描画パスでは、より太いストロークと 10 ピクセルのアンチエイリアシング幅を使用し、グラデーションの境界を柔らかな光の輪のように広げています。次の描画パスでは、その上に鮮明な白色のコアを描画します。必要なのは 2 回の描画呼び出しだけです。ブラー処理も追加のレンダーターゲットも必要ありません。調整可能なアンチエイリアシングは、一見すると単なる技術的な機能に思えるかもしれません。しかし実際には、ラインアートのためのグローブラシとしても利用できるのです。

色は、5 つのカラーストップを持つ斜め方向の `createLinearGradient()` から生成されています。そのため、虹色のグラデーションはバーごとではなく、スペクトラム全体にかかっています。ビュー遷移中は、`globalSaturation` と `globalBrightness` の両方がアニメーションします。その結果、別のビューへスワイプするとスペクトラムは徐々に彩度を失ってグレースケールになり、同時に暗くなっていきます。これもまた、たった 2 行のコードで実現されており、レイヤーエフェクトは使用していません。

中央の再生/一時停止ボタンは、白色のストロークを持つ `ctx.circle()`と、その背後に配置された適切な半径とぼかし量を持つ boxshadow2d によって描画されています。これにより、円形のシャドウ効果を表現しています。内部のアイコンは 2 本の線分で構成されています。4 つの端点の座標は、`playingAnimated` によって再生状態と一時停止状態の位置の間を線形補間しています。さらに、このプロパティに対して`Behavior { SmoothedAnimation { velocity: 2 } }`を設定しています。これにより、一時停止アイコンの 2 本のバーが三角形の再生アイコンへと変形し、再び元に戻るアニメーションが実現されます。毎フレーム再描画する仕組みでは、このようなアイコン変形は非常に簡単です。パスの端点を補間し、中間形状を計算するだけでよいからです。

アクティビティ

canvas2d_watchui_view4_activity
アクティビティビュー(上図)には、Canvas2D がまったく使用されていません。Canvas2D を使って似たような円形バーを実現することもできますが、このビューは、こうした UI コンポーネントに対して通常のシェーダーエフェクトがいかに強力であるかを示すために意図的に作られました。

このビューには、小さなバーで構成された 3 本の同心円リングがあり、それぞれのバーが独自の色で発光しています。その特徴はすべてピクセル単位の処理です。そのため、`CircleBar.qml` は 3 段階のシェーダーパイプラインとして実装されており、各段階で Qt Quick Effect Maker によって作成されたエフェクトを使用しています:

  1. BarsEffect: バーをプロシージャルに生成し、水平な直線状の帯として描画します。バーの幅、本数、滑らかさ、分布は uniform で制御されます。`barsAmount` は単純に`value * barsAmount`で計算されるため、リングの"progress"は単なる浮動小数点値です。2 色のカラーグラデーションが帯に沿って適用され、現在値を超えたバーは暗い `barsColorOff` で描画されます。

  2. GlowEffect: この帯にブルーム効果を追加します。QQEM の `BlurHelper` ノードを使用しており、これによって広がりのある低コストなグローを実現しています。`glowBloom`、`glowBlurAmount`、`glowColor`はリングごとに設定できます。

  3. BendEffect: 発光する帯を円弧状へ変形します。極座標 UV マッピングを用い、`circleBendStartAngle`、`circleBendSpanAngle`、`circleBendRingWidth`によって、リング上のピクセルを元の直線状テクスチャ座標へ対応付けます。

これら 3 つの円形バー生成エフェクトはすべて QQEM の組み込みエフェクトノードとして提供されているため、自分で実装する必要はありません。

数値表示部分は、`monofonto` フォントを使用した QML の `Text`アイテムで構成されています。また、`MultiEffect` によるドロップシャドウが適用されています。その背後では、`BackgroundEffect`がオレンジ色の「電気雲(electric clouds)」を描画しています。これはフラクタルノイズを利用したエフェクトであり、リングのバー色から色付けされるため、背景とバーが常に同じ雰囲気を共有するようになっています。Electric Clouds も QQEM の組み込みノードとして提供されており、そのまま利用しながら自由にカスタマイズできます。

ウォーター

canvas2d_watchui_view5_water-1
ウォータービュー(上図)は、Canvas2D とシェーダーエフェクトを分離して使うのではなく、Canvas2D の描画結果をシェーダーへ入力する例として作られています。

グラスは Canvas2D によって描画されています。まず、容器部分として、暗い色で塗りつぶした `ctx.circle()` を描画し、その上にやや明るい色のストロークを重ねます。次に水を描画します。水は 2 つの部分から構成される 1 本の連続したパスです。グラス底部の丸みを表現する `ctx.arc()`と、波打つ水面を表現する、上部に配置された `lineTo()`の点列です。このパスは `closePath()` で閉じられます。その後、このパスは 1 つの縦方向グラデーションで塗りつぶされ、別のグラデーションでストローク描画されます。

そして、ここからがポイントです:


BubblesEffect {
    anchors.fill: canvas
    source: canvas
    timeRunning: true
}

Canvas2D {
    id: canvas
    visible: false
    // ...painting the glass and water
}

Canvas は表示されません。Canvas の描画結果そのものがシェーダーへの入力となり、そのシェーダーが水の中に見える泡の上昇や屈折効果を追加します。これは、Canvas2D とシェーダーの理想的な役割分担の例です。液体の形状(shape)は、水位、波の位相、グラスの半径によって決まるジオメトリなので、Canvas2D を使用します。一方、液体の質感(texture)はピクセル単位の処理なので、GLSL が担当します。どちらも、本来得意ではない処理を無理に担当する必要がありません。

補足: Canvas Painter にはカスタムシェーダーブラシ(custom shader brushes)のサポートがありますが、Canvas2D はまだこれをサポートしていません。カスタムブラシクラスは Qt 6.12 では依然として Technology Preview の段階であり、今後さらに強力になるよう改良していく予定です。理想的には、この例でもグラス内の水をカスタムのバブルブラシで直接塗りつぶせるようになり、別のレンダリングステップが不要になるでしょう。将来的にはそのような選択肢も考えられます。

アニメーションにも注目する価値があります。これらはすべて、視覚プロパティに対する`Behavior`ブロックではなく、描画コード内で実現されています。`waveSpeed`は `FrameAnimation.elapsedTime`から取得されます。また、波の振幅は`Math.sin(waterLevel * Math.PI)`によってスケーリングされています。そのため、水面はグラスが半分ほど満たされているときに最も活発に揺れ、水が空に近づいたり満杯に近づいたりするにつれて穏やかになります。物理的にも自然な挙動であり、たった 1 回の `Math.sin()`呼び出しで実現できます。水位そのものは、`animatedValue` に対する `SmoothedAnimation`によってアニメーションします。その結果、「+」ボタンを押すと水位は瞬時に変化するのではなく、実際に注がれているように増加します。また、波の振幅も新しい水位から自動的に再計算されます。ビュー遷移中には、`globalSaturation` と `globalContrast`がアニメーションします。そのため、別のビューへスワイプすると、水の色は徐々に彩度を失いながら消えていきます。「Daily Goal」、ミリリットル表示、パーセンテージ表示は、シェーダーの上に配置された `Text`アイテムです。そのため、泡と一緒に屈折することなく、常に鮮明な状態で表示されます。

心拍数

canvas2d_watchui_view6_heartbeat
最後のビュー(上図)は、再び Canvas2D のみで構成されています。そして、このビューは実際のデータ可視化アプリケーションに最も近いものです。見た目については、他のビューとの統一感が十分ではないかもしれません。しかし、それは重要ではありません。このデモの主な目的は、Canvas2D のさまざまな活用方法を示すことだからです。

ECG グラフの背景グリッドは、Canvas2D を使うと非常に簡単に実現できます:


const cols = 30;
const rows = 20;
const lw2 = gridLineWidth * 0.5;
const gb = ctx.createGridPattern(gx + lw2, gy + lw2,
                                 (gw - 2 * lw2) / cols,
                                 (gh - 2 * lw2) / rows);
gb.setLineWidth(gridLineWidth);
gb.setBackgroundColor("#40101010");
gb.setLineColor("#404040");
ctx.fillStyle = gb;
ctx.fillRect(gx, gy, gw, gh);

30×20 のグリッド、つまり 52 本のアンチエイリアス付きラインは、gridpattern2d ブラシを使用した 1 回の `fillRect()` で描画されています。グリッド密度に関係なく描画コストが一定なのは、このパターンがジオメトリへ分割されるのではなく、フラグメントシェーダー内で評価されるためです。グリッドやバー状のパターンは、チャート、ゲージ、計器類の UI に頻繁に登場します。そのため、グリッドパターンは Canvas Painter において第一級のブラシとして提供されています。

ECG 波形そのものはシンプルな折れ線グラフです。通常は単一のパスとして描画されますが、波形バッファの終端で表示位置が折り返される場合には、同じ `beginPath()` 内の 2 つのサブパスとして描画されます。この切れ目が、実際の心拍モニターのように画面上を走査するスキャンラインの途切れを生み出しています。

このストロークには、参考になるポイントが 2 つあります:

  • `strokeStyle` には、左右の端で `transparent`、中央で赤色になる横方向の `createLinearGradient()` が使用されています。そのため、波形はグラフの左右端で自然にフェードアウトします。クリッピング、マスク、追加アイテムは必要ありません。フェード効果そのものがブラシに組み込まれています。

  • `ctx.miterLimit = 100`が設定されています。これにより、グラフがほぼ垂直に方向転換する箇所でも、鋭いピーク形状を維持できます。デフォルト値のままでは、その角が切り落とされてベベル状になってしまい、先端が平らになった ECG 波形は不自然に見えます。

データ自体は人工的に生成されたものですが、適切な波形形状とランダム性を持っています。同じ心拍は二度と現れません。また、この合成データを実際のセンサーデータへ置き換えることも非常に容易です。

まとめ

WatchUI は、私が Canvas2D の開発作業を進める中で作成したデモです。その主な目的は、「実際の UI はどのような見た目になるのか?」という疑問に対して、単なるベンチマーク以上の説得力を持つ答えを示すことにあります。Canvas2D の API 自体を試してみたいのであれば、モジュールに同梱されている Canvas 2D Tester サンプルが、今でも最適な出発点です。

しかし、WatchUI から得られる重要なメッセージは、個々の技術そのものではなく、それらの組み合わせにあります。記述可能なジオメトリには Canvas2D、ジオメトリだけでは表現できないピクセル処理には Qt Quick Effect Maker のシェーダー、テキストやレイアウトには通常の Qt Quick アイテム、それら全体を製品へ統合するための Qt Quick の統合 2D/3D レンダラー、これらをすべて組み合わせることで、C++ に一切触れることなく、QML、JavaScript、GLSL だけで実現できます。

Canvas2D は Qt 6.12 において Technology Preview の段階にあります。つまり、今まさに皆さんのフィードバックが API の将来を形作るタイミングです。もし Canvas2D を使って何かを作ったり、あるいは利用中に課題や制限にぶつかったりした場合は、ぜひフィードバックをお寄せください。Qt bug tracker または forum threadを通じてご意見をお待ちしています。

コメント

ブログを購読

Qt 6.12 を
今すぐ試そう!

最新リリースはこちらからダウンロードできます。 www.qt.io/download

Qt 6.12 LTS がリリースされました!アプリケーション開発者やデバイス開発者向けに、多くの新機能と改善が追加されています。 

採用情報 

現在、さまざまなポジションで採用を行っています。募集職種はこちら をご覧ください。また、Instagram をフォローして #QtPeople の働き方もぜひチェックしてください。