新たなキャンバス描画モジュール「Qt Canvas Painter」により、我々は実現可能な最高の現代的C++ペインティングAPIの構築を目指しています。本ブログ記事では、Qtユーザーに提供される革新的なキャンバス描画機能の一部を紹介し、その内容と使用方法を解説します。
本記事を読む前に、Qt Canvas Painterの紹介に関する前回の記事をご確認ください。Qt Canvas Painterの基本を理解した上で、ここで提供される新しいキャンバス描画機能の詳細に進んでください。
Qt Canvas Painterは基本的に、HTML Canvas 2D Context APIをQt C++へ移植したもので、一部機能を削減・追加しています。前回のブログ記事では2D Contextと比較した主要な欠落機能について説明しましたので、本記事では追加機能に焦点を当てます。これらの追加機能は、本APIの主要目標である「ハードウェアアクセラレーション対応の命令型ペインター上で、パフォーマンスと生産性を可能な限り効果的に両立させる」ことを実現するためのものです。
では新機能を一つずつ見ていきましょう。ただし最初に必須の警告を。
Qt Canvas Painter は Qt 6.11 における技術プレビューです。つまり API や ABI の安定性は現時点では保証されません。
詳細に説明するキャンバスレンダリング機能は以下の通りです。
ブログの末尾では、その他の追加機能についても簡潔に言及されています。
アンチエイリアシング機能は、2Dキャンバスレンダリングにおいても現代的なユーザーインターフェースの重要な要素です。デフォルトのラスターバックエンドを持つQPainterはアンチエイリアシングをサポートしていますが、その実現方法によりCPU使用率が上昇します。一方、QPainter OpenGLバックエンドはマルチサンプリング(MSAA)技術を用いたアンチエイリアシングをサポートしています。これにはGL_EXT_framebuffer_multisampleおよびGL_EXT_framebuffer_blit拡張機能が必要であり、デスクトップ環境では一般的にサポートされていますが、組み込みデバイスでは必ずしも利用可能とは限りません。
長年にわたり多くのユーザーから寄せられたフィードバックに基づくと、アンチエイリアシングの選択肢がMSAAのみであることは、複数の理由から理想的ではありません。レンダリングターゲット全体でMSAAを有効化することは、パフォーマンスやリソース使用量の懸念から不適切な場合があり、また描画全体でMSAAを有効化することは視覚的に好ましくない場合もあります。Qt Canvas PainterはMSAAと頂点アンチエイリアシングの両方をサポートし、ギザギザを解消した滑らかなレンダリングをMSAA有効化なしで実現します。
頂点アンチエイリアシングの強みは、アンチエイリアシング量を自由に調整できる点です。一般的な1ピクセル分ではなく、例えば1.5ピクセルや3ピクセルを選択して描画を滑らかにできます。さらに、異なるパスごとに異なるアンチエイリアシング量を適用することも可能です。
この自由調整可能なアンチエイリアシングは、影やグロー効果の表現など、創造的な用途にも活用できます。
テキストの処理では、アプローチが若干異なります。Canvas PainterはテキストレンダリングにSigned Distance Field(SDF)手法を採用しています。基本的に、フォントグリフはぼやけた小さなテクスチャとしてレンダリングされ、フラグメントシェーダーの smoothstep() を使用してシャープでスケーラブルなテキストを作成します。しかしSDFでは、そのぼやけの一部を任意に利用してテキストをさらに滑らかにすることも可能です。SDFフォントテクスチャの解像度のため、この平滑化には限界がありますが、この技術でより滑らかなテキストを実現するのに依然として有用です。
これらの機能の詳細については、QCPainter の setAntialias() および setTextAntialias() メソッドを参照してください。
Qt Canvas Painter は、線形、放射状、円錐といった一般的なグラデーションタイプをすべてサポートしています。これらの機能は 2D Contextのものと一致しており、多数のパラメータを必要とする create*Gradient() メソッドよりも、QPainter および C++ ユーザーにとってより自然な API を提供します。
しかしQt Canvas PainterはさらにQCBoxGradientというグラデーションをサポートしています。現代のUIでは、角の丸い矩形がよく使用されています。これらはroundRect()メソッドで簡単に作成できますが、より滑らかなエッジや複数色での塗り分けが必要な場合はどうでしょうか?このような場合、QCBoxGradientブラシを使用すれば、通常の矩形を描画するだけで実現できます。
半径とぼかしを個別に調整できるため、角をシャープにしたり柔らかくしたりする様々なユースケースに適しています。
ベンチマークとパフォーマンスについては次回のブログ記事で詳しく説明しますが、ボックスグラデーションについて簡単に触れておきましょう。一見すると、下の画像は同じように描画された2つの角丸長方形に見えるかもしれませんね?
しかし、そうではありません。左側はroundRect()で塗りつぶしとストロークを適用したもので、右側は塗りつぶしのみのボックスグラデーションです。見た目は非常に似ていますが、内部の動作は異なります。左側は、この解像度で塗りつぶしに202個の三角形、ストロークに280個の三角形を使用しており、合計で484個です。右側はアンチエイリアス処理された塗りつぶしにわずか10個の三角形しか使用しないため、三角形分割がはるかに高速です。
したがって、特定のターゲットハードウェアで三角形分割や頂点処理がボトルネックとなり、フラグメントシェーディングに余剰能力が残っている場合、丸角四角形にはボックスグラデーションの利用を検討してください。
Canvas Painter QCBoxShadow は上記のボックスグラデーションと密接に関連し、CSS box-shadow と互換性のある API を持っています。ただし、遅いガウスぼかし手法の代わりに、フラグメントシェーダー上で高性能な SDF アプローチを採用しています。これはQt QuickのRectangularShadow要素の実行型バージョンとも見なせます。
これらのボックスシャドウは比較的単純な数学演算で計算されるため、角丸長方形形状のシャドウのみをサポートし、ガウスぼかしシャドウのレンダリング出力と完全に一致しません。しかし、パフォーマンスの問題でシャドウを全く使わないか、高速なボックスシャドウを使用するかの選択であれば、後者はレンダリングとアニメーションが非常に高速であるため採用する価値があります。
QPainterをご存知の方は、QBrushがバーやグリッド用の数種類のパターンスタイルをQt::BrushStyleに内包していることもご存知でしょう。これらは特定のパターンにハードコードされており、デザイナーがより詳細なパターンを望むため、現在ではサンプル以外ではほとんど使用されません。このニーズに対応し、グリッドやバーパターンに対するより現代的なアプローチを提供するため、Qt Canvas PainterはQCGridPatternブラシを提供します。
このクラスは QBrush のスタイルと比較して、線幅、位置、回転、ぼかし量などを容易に定義できるため、より自由度が高いです。レンダリングは比較的シンプルなフラグメントシェーダーコードで行われるため、パターンの値がアニメーションする場合でもパフォーマンスは非常に良好です。
もちろん、グリッドは線描画でも描画可能です。しかしグリッドパターンとの違いは、グリッドに10本の線があろうと1000本の線があろうと、パフォーマンスが全く変わらない点です。
ここまでで、Qt Canvas Painterがストロークや塗りつぶし用に非常に豊富なブラシ素材を提供していることは明らかでしょう。しかしもう一つ重要な要素があります:カスタムシェーダーブラシです。
Qt Canvas PainterはQRhiを基盤として構築されているため、事実上GPUを必要とします。この特性を利用し、API自体にシェーダーを必須とする設計が可能です。これにより、塗りつぶしやストロークは組み込みブラシに制限されず、幅広くカスタマイズできます。以下にカスタムブラシを複数使用した例を示します。
もちろん、カスタムブラシはテキストにも使用可能です。カスタム頂点シェーダーを活用すれば、例えば文字のグリフ位置をアニメーションさせるといったことも実現できます。
QCCustomBrushは、様々なユースケースに対応できるよう機能を強化するため、技術プレビュー期間中に変更が加えられる可能性が高いクラスの1つです。
HTML 2D Contextには、塗りつぶし/ストロークの現在の不透明度を設定するglobalAlphaプロパティがあります。QPainterでは、同じ機能がsetOpacity()と呼ばれています。同様に、Canvas Painterではグローバルアルファの設定が可能ですが、さらに輝度、コントラスト、彩度といった追加のカラーエフェクトもサポートしています。以下は、上記のエフェクトをすべて組み合わせて背景を単色で暗くし、ユーザーが気づきやすいように上部のポップアップをより目立たせる例です。
これらを利用すれば、個々のパスやキャンバス全体にカラーエフェクトを適用し、アニメーション化することが容易です。エフェクトはキャンバスレンダラーのフラグメントシェーダーの最終段階で適用され、オフスクリーンバッファへのレンダリングを必要としないため、これらのエフェクト使用によるオーバーヘッドは実質的に発生しません。
HTML 2D Contextと比較して、以下のような追加のキャンバスレンダリング機能も存在します(ややマイナーですが、ここで簡単に触れておきます):
上記の例は、Qt Canvas PainterがHTML 2D Context APIの上に提供する追加のキャンバス描画機能の一部に過ぎません。Canvas Painterは進化を続けており、これらの機能を微調整し、さらに機能を追加していく予定です。
このエキサイティングな開発に参加するには、Qt 6.11プレリリースをインストールするか、ソースからQtをビルドしてCanvas Painterをお試しください。バグ報告や提案はチケットとして作成してください。実際のユーザーフィードバックこそが、Qtソリューションの正式サポート機能として技術プレビュー段階を脱却し、改善を進める最良の方法です。本ブログ記事やCanvas Painter全般に関する質問は、関連するQtフォーラムスレッドでも受け付けています。
次回のブログ記事では、新Canvas Painterの比類なきパフォーマンスについてさらに詳しくご紹介します。またお会いできるのを楽しみにしております!