QML Scene Graph におけるテキスト描画

この記事は Qt Blog の "Text Rendering in the QML Scene Graph" を翻訳したものです。
執筆: Yoann Lopes, 2011年7月15日

少し前に、Gunnar が QML Scene Graph の新機能について 説明しました 。その記事で述べられたように、新機能の一つが "Distance Field Alpha Testing" に基づいたテキスト描画の新技術です。この技術は OpenGL の全てのパワーを活用して、それまでの Qt では成し得なかったスケーラブルでサブピクセル座標、サブピクセルアンチエイリアシングなテキストをほぼノーコストで持つことが可能となります。

まずは、以下のビデオでこの技術がもたらす改善をご覧ください。

http://www.youtube.com/watch?v=M4waDSXWGGw

Distance Field(距離場)… って何?

おそらく、ほとんどの人が "Distance Filed"(距離場) とはなんだろうと疑問に思っていらっしゃるでしょう。Distance Transform や Distance Map とも呼ばれていますが、デジタル画像の各画素にグリフの一番近いエッジまでの距離を示す値をマッピングする手法です。その値は 0.0 から 1.0 の範囲を取り、グリフのエッジ上の画素は 0.5 になります。グリフ外の画素はその直近のエッジからの距離が増すにつれて 0.0 へと近づきます。グリフ内の画素は逆に直近のエッジからの距離が増すにつれて 1.0 へと近づきます。

[gallery include="5928, 5927, 5929" link="file"]

Distance Field は高解像度な画像やグリフのベクトルによる表現から生成することができます。最初のソリューションは典型的な総当たりによる手法であるため、非常に遅くなる可能性があります。そのため、このソリューションを我々が使う数十ものグリフ(中国語の場合は数百にもなります)を一度に生成するために適用するつもりにはなれませんでした。いくつかのツール(例えば、このツール)で与えられたフォントのグリフ群についてあらかじめ計算しておき、実行時にはその計算結果が保存されたファイルを使う方法もあります。しかし、この方法は開発者にとって不便であるため採用しませんでした。

その代わりに、距離データの生成にグリフのベクトルによる表現を用いることにしました。単純に、グリフのアウトラインを内側と外側に決められた距離だけ拡大し、その内外の枠とアウトラインとを距離のグラデーションで塗りつぶします。これらの結果を巨大なテクスチャの 64×64 画素のセルに 8-bit のチャンネルとして格納します。この方法によって(Kim に感謝します)、Distance Field を(平均的な)モバイルデバイスでグリフあたり 1msec 以下で生成できるようになり、実行時にどんなベクトルフォントも動的に利用できるようになります。

動作原理

この技術ではテクスチャに対して GPU ネイティブの線形補間が利用できるという利点があります。エッジからの距離を正確に補間することができ、任意のサイズでグリフを再構成することができます。必要なのは Alpha Testing、すなわち、しきい値に応じて画素の表示の有無を決定することだけです。通常はグリフのエッジ上の値である 0.5 をそのしきい値として用います。この結果、グリフはどんなにズームしてもまるでベクトルグラフィックスであるかのように、くっきりとしたアウトラインを持ちます。唯一の欠点はとがった角が断ち切られることですが、この技術を使わずに拡大したグリフのひどい見た目を考えると取るに足りないものといえます。

[gallery link="file" include="5930, 5925"]

この技術は、全てをグラフィックハードウェアで実行時に「ただで」行えるため、パフォーマンスに影響を与えることなく素晴らしい見た目を得ることができます。

改善点

高品質なアンチエイリアシング

グリフの同じ Distance Field 表現を用いて、たった一行のシェーダーコードで高品質なアンチエイリアシングを実現できます。

varying highp vec2 sampleCoord;
uniform sampler2D texture;
uniform lowp vec4 color;
uniform highp float distMin;
uniform highp float distMax;
void main() {
    gl_FragColor = color * smoothstep(distMin, distMax, texture2D(texture, sampleCoord).a);
}

Alpha Testing で一つのしきい値を使うのではなく、シェーダーでエッジをぼかすために二つの異なったしきい値を用います。入力された Distance Field の値は二つのしきい値の間で smoothstep で補間されてジャギーが取り除かれます。ぼかす領域の幅は二つのしきい値間の距離を変化させることで調整できます。グリフが小さくなれば、ぼかす領域はより広くなります。グリフが拡大されれば、ぼかす領域は狭くなります。

グレーアンチエイリアシング

GPU が充分にパワフルであれば(すなわち、デスクトップマシンの GPU であれば)、シェーダーコードに数行追加することでサブピクセルアンチエイリアシングを行うこともできます。出力する画素のα値の計算に距離データを用いるのではなく、出力する画素で各色要素を別々に計算するために隣接画素のデータを用います。そのためには一つの画素ではなく、五画素をテクスチャから取り出す必要があります。赤要素は最も左から三つの Distance Field の値の平均に、緑要素は中間の三つの Distance Field の値の平均に、青要素は最も右から三つの Distance Field の値の平均になります。サブピクセルアンチエイリアシングは処理能力がより必要となるため、モバイルプラットフォームでは現状では無効になっています。もっとも、最近ではモバイルデバイスが高解像度のディスプレイを持つようになっており、サブピクセルアンチエイリアシングの利用が無意味になってきています。

サブピクセルアンチエイリアシング

特殊効果

Distance Field の利用によって、アンチエイリアシングに加えて、数行のシェーダーコードでアウトライン化や発光(glow)、影付けなどの特殊効果を行うこともできます。この技術を用いて QML の Text 要素に三つのスタイル(outline, raised, sunken)を実装することができました。例えばアウトライン化を行うには、二つの距離値の間にあるテクセルに異なった色を使用するだけです。これによって、これらの効果をより速く、よりきれいにスケーラブルに実行することができます(Scene Graph ベースではない QtQuick 1.0 では装飾されたテキストのスケーリングの品質はひどいものでした)。

実装の詳細

与えられたフォントに対して、64×64 画素のサイズで一度のみラスタライズを行い、各グリフ(もしくはその Distance Field 表現)をキャッシュします。どんなサイズのグリフの描画においても、同じテクスチャが適切にスケーリングされて利用されます。QPainter で利用されていたネイティブのフォントレンダリングでは、アプリケーションで使われるサイズごとにグリフをキャッシュしています。(Distance Field では)あるフォントを様々なサイズで用いる際に、グラフィックメモリの使用量をより少なくすることができます。

グリフを任意のサイズにスケーリングできるようになったため、ズームしたときにグリフを正確な座標に配置するためにフォントのヒントを無効にする必要があります。その結果、グリフの座標がサブピクセル単位となります(すなわち、ピクセルグリッドに沿った配置ではありません)。

ハックをはじめよう

Qt 5 のリポジトリ からファイルを取得して、QtDeclarative モジュールにある qsgdistancefield から始まる名前のファイルを探してください。

  • QML_DISABLE_DISTANCEFIELD 環境変数を使ってデバッグ用に Distance Field によるテキスト描画をオフにすることができます。
  • デスクトッププラットフォームではサブピクセルアンチエイリアシングがデフォルトで有効になっています。qmlscene にオプション –text-gray-antialiasing を渡すことで標準的なグレーアンチエイリアシングを用いることができます。

この技術に関する詳細は Valve 社の論文 を参照してください。


Blog Topics:

Comments

Michal Lazo
2 points
56 months ago

Any chance for Clang/LLVM on windows ?

C
Cristian Adam
0 points
56 months ago

Which variant do you have in mind?

Michal Lazo
0 points
56 months ago

Same as what google use for Chrome now. So we will be able to build whole qt+qtwebengine with free compiler on windows

S
Santtu Ahonen
0 points
56 months ago

Windows + Clang is planned under Qt 6.1 here https://bugreports.qt.io/browse/QTBUG-86432

Gabureanu Adrian
1 point
56 months ago

It's a bit too early to completely drop off UWP in Qt6. AFAIK Microsoft doesn't yet support delivering traditional desktop apps to the Microsoft Store. Maybe after Project Reunion it will. Maybe it won't. Until further announcements from Microsoft it might make sense to skip UWP for Qt 6.0 and Qt 6.1. But if they still don't support delivering traditional desktop apps to the Microsoft Store by spring 2021 or don't announce anything new, it might be a good idea to bring UWP back in Qt 6.2.

Nevertheless it's always better to under-promise and over-deliver than to over-promise and under-deliver.

P
Peter Staab
0 points
56 months ago

Microsoft supports traditional desktop apps since a few years (they even provide a converter app which automates packaging).

Cameron Gutman
1 point
56 months ago

For the Store on PC, yes. However, if you want to run on Xbox, HoloLens, or Surface Hub, UWP is the only game in town.https://docs.microsoft.com/en-us/windows/apps/desktop/choose-your-platform says (emphasis mine):

Not only can you use UWP to create desktop applications for Windows PCs, but UWP is also the only supported platform for Xbox, HoloLens, and Surface Hub applications.

O
Oliver Wolff
0 points
56 months ago

Even though it might be possible to develop Qt applications for Xbox, HoloLens or Surface Hub, we haven't seen much interest from Qt users. While HoloLens and Surface Hub applications with Qt might make sense for some people, the Qt framework probably is not the first address for people who want to develop Xbox applications/games

Gabureanu Adrian
0 points
56 months ago

@Peter Staab, Have you published a Qt app on the Microsoft Store using Desktop Bridge (converter)? Or do you know any such app?

--

The reason for low adoption of UWP is monetization. For e.g. as of this year, Microsoft shut down their own ad platform for Windows UWP apps. However you can still sell in-app purchases. So the monetization opportunities are still there, but they're quite limited. But with traditional apps it's even worse, because you cannot include Qt Purchasing into them.

So far I got 60+ apps published on the Microsoft Store with a focus on Windows 10 Desktop and I plan for more. If 1) Microsoft opens up their store to traditional apps, 2) allows in-app purchases into traditional apps and 3) Qt supports Qt Purchasing in traditional apps ... I think I won't miss UWP that much.

Cameron Gutman
1 point
56 months ago

Windows 8.1 is still supported by Microsoft (for free) until January 10, 2023. It is most certainly not out of support. It still receives security patches every Patch Tuesday until that EOL date. See https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet

Are you perhaps confusing it with Windows 8.0, which is in fact out of support?

This means that we will not have 32bit Windows support available.

I'm not sure I follow this.The current Supported Platforms page has both 32-bit and 64-bit support listed for Windows 10. I don't understand how dropping Windows 7 and Windows 8.x support would impact whether 32-bit support remains on Windows 10. Can you clarify this?

O
Oliver Wolff
0 points
56 months ago

Hi Cameron,

We are not confusing Windows 8.1 with Windows 8.0. As you pointed out yourself, Windows 8.1 is in Microsoft's "Extended Support" phase until 2023. That means that the operating system gets security updates, but not much more is promised by Microsoft. That basically reflects what Qt's LTS versions are about. Having 5.15 available as an LTS version of Qt means, that the Qt applications you are running with that version on Windows 8.1 will get security updates until 5.15's end of support (which will also be in the year 2023 if I am not mistaken).

The end of 32 bit packages for Windows was perhaps phrased a bit unfortunately by Santtu. The decision no longer to support 32 bit on Windows was done deliberately from the Windows version support. This decision does not mean that we will actively remove support for 32 bit on Windows though. Having a platform as "supported" means more than "it works by chance". In the end it all boils down to resources. Windows platforms traditionally do not have the strongest focus on open source projects, so the majority of Windows work is done inside the Qt Company (that's my gut feeling). Interest in 32 bit packages on Windows has been decreasing over the time and we reached a point, where it no longer makes sense to invest into this architecture on Windows any more. These investments are not only measured in man power, but also computing power. We cannot just add more and more systems into our CI system. In order to bring new configurations there, other configurations have to be removed. Summing that up: It is possible, that 32 bit Windows builds of Qt6 will be possible, but as there will not be any CI coverage, we cannot be sure of that.

Cameron Gutman
0 points
56 months ago

We are not confusing Windows 8.1 with Windows 8.0. As you pointed out yourself, Windows 8.1 is in Microsoft's "Extended Support" phase until 2023. That means that the operating system gets security updates, but not much more is promised by Microsoft.

Extended support is still support, though. You can still request non-security fixes provided you have a support contract with Microsoft (and even during mainstream support, good luck getting non-security fixes without a support contract). Source

Besides, by that logic, Windows 7 support would have been dropped back in 2015 after it entered extended support, yet Qt maintained support for Windows 7 up through the end of extended support this year. There must be more to it than that.

Having 5.15 available as an LTS version of Qt means, that the Qt applications you are running with that version on Windows 8.1 will get security updates until 5.15's end of support (which will also be in the year 2023 if I am not mistaken).

Well it means that for commercial customers. As an open source user, I only get support for 5.15 until Qt 6.0 is released as far as I understand.

Interest in 32 bit packages on Windows has been decreasing over the time and we reached a point, where it no longer makes sense to invest into this architecture on Windows any more. These investments are not only measured in man power, but also computing power. We cannot just add more and more systems into our CI system. In order to bring new configurations there, other configurations have to be removed. Summing that up: It is possible, that 32 bit Windows builds of Qt6 will be possible, but as there will not be any CI coverage, we cannot be sure of that.

Understood. Thanks for these details. Maybe I can use this as an excuse to drop my 32-bit Windows support ;)

O
Oliver Wolff
0 points
56 months ago

If you have a support contract with the Qt Company, you will get the security fixes you are asking for and you can request other changes via your support/sales channels. You can request changes for Windows 10, but they do not guarantee that every fix you are asking for will land in their product. This is basically the same The Qt Company offers.

Windows 7 had a much bigger market share for a much longer time so we decided to keep it for a longer time. The situation is different for Windows 8.1. There does not seem to be too much interest, so we are doing that cut for Qt6. At least as far as I know, there is not "more to it than that"

Cameron Gutman
0 points
56 months ago

Windows 7 had a much bigger market share for a much longer time so we decided to keep it for a longer time. The situation is different for Windows 8.1. There does not seem to be too much interest, so we are doing that cut for Qt6.

This is what I meant by there being "more to it" than just being in extended support ;)

Thank you for the info.

Cameron Gutman
1 point
56 months ago

As a the developer of a GPLv3 app using open-source Qt, the loss of platform support in Qt 6 puts us in a bit of a bind considering that Qt 5.15 will only be supported for open-source users until Qt 6.0 (plus your roadmap doesn't estimate platform parity with Qt 5 until Qt 6.2). For example, WebAssembly developers using the open-source Qt have literally no way of running a supported Qt version during 6.0's life because Qt 5.15 support is gone for them and Qt 6 doesn't support WebAssembly yet.

I prefer to always ship the latest Qt version (and have even shipped a Qt 5.15.1-based release already) and regularly report bugs against the latest releases. Seemingly, I'm the exact active open-source Qt user that you are trying to encourage with your policy to end LTS support for open-source users. However, the platform support loss actually prevents me from continuing this, because I have users on Windows 7 and 8.1. I am stuck without being able to use a supported Qt build after Qt 6.0 releases, until I decide to drop Windows 7 and Windows 8.1. All other open-source Qt applications will be in the same situation (Wireshark comes to mind).

I understand the complexities of developing against an 11 year old OS, and I'm not asking you not to drop support for Windows 7 in Qt 6 or anything like that (though not dropping Windows 8.1 would be nice given that it's actually still supported by Microsoft until 2023). However, due to the lack of platform parity with Qt 6 (especially for WebAssembly developers), would you consider offering Qt 5.15 LTS builds to open-source users at least until Qt 6.2 is released? Dropping Windows 7 in 2H 2021 is more palatable, since Windows 7 Embedded POSReady remains supported until October 12, 2021.

Vadim Peretokin
0 points
56 months ago

Seconded, would like an answer to this please. We're in exactly the same situation as open-source users of Qt.

NekkiT
0 points
46 months ago

Thx for the info!

Sergio
0 points
42 months ago

Is there any technical reason for dropping Windows 7 support? Will Qt 6 run on it when compiled from source?

Mark Wilson
0 points
31 months ago

Online Installer freeze on 64-bit Ubuntu 20.04 and 22.04 (VirtualBox VM's on windows 11) during install of gcc 64-bit. Not sure what I'm missing here.

Sergey Rozhenko
0 points
15 months ago

I'm late to the party, but I'd mirror my tweet here: Qt 6 is cancer. When it's not an app that stops supporting Windows 7/8, not even a browser, but a mere UI framework, there's nothing screaming incompetence of its makers more than that. Don't use that crap.