ジオメトリ実現の概要
このトピックでは、 Direct2D ジオメトリの実現を使用して、特定のシナリオでアプリのジオメトリ レンダリングパフォーマンスを向上させる方法について説明します。
次のセクションが含まれます。
ジオメトリの実現とは
Windows 8.1で導入されたジオメトリの実現は、Direct2D アプリが特定のケースでジオメトリレンダリングのパフォーマンスを簡単に向上させる新しいタイプの描画プリミティブです。 ジオメトリの実現は、 ID2D1GeometryRealization インターフェイスによって表されます。
ジオメトリの実現を使用する理由
Direct2D が ID2D1Geometry オブジェクトをレンダリングするときは、そのジオメトリをテセレーションと呼ばれるプロセスを通じてグラフィックス ハードウェアが認識する形式に変換する必要があります。 通常、Direct2D では、ジオメトリが変更されない場合でも、描画されるすべてのフレームにジオメトリをテセレーションする必要があります。 アプリがフレームごとに同じジオメトリをレンダリングする場合、繰り返される再テセレーションは無駄な計算作業を表します。 ジオメトリのテセレーション(完全なラスタライズ)をキャッシュし、繰り返し再テセレーションするのではなく、キャッシュされた表現を各フレームに描画する方が、計算効率が高くなります。
開発者がこの問題を解決する一般的な方法は、ジオメトリの完全なラスター化をキャッシュすることです。 特に、新しいビットマップを作成し、そのビットマップにジオメトリをラスター化してから、必要に応じてそのビットマップをシーンに描画するのが一般的です。 (この方法については、「Direct2D アプリのパフォーマンスを向上させる」の 「Geometry レンダリング 」セクションで説明されています)。このアプローチは非常に計算効率が高い一方で、いくつかの欠点があります。
- キャッシュされたビットマップは、シーンに適用される変換の変更に影響を受けます。 たとえば、ラスタライズをスケーリングすると、顕著なスケーリングアーティファクトが発生する可能性があります。 高品質のスケーリング アルゴリズムを使用してこれらの成果物を軽減すると、計算コストが高くなる可能性があります。
- キャッシュされたビットマップは、特に高解像度でラスター化されている場合に、大量のメモリを消費します。
ジオメトリの実現は、上記の欠点を回避するジオメトリをキャッシュする別の方法を提供します。 ジオメトリの実現は、ピクセル (完全なラスター化の場合と同様) ではなく、数学的平面上のポイントによって表されます。 このため、スケーリングやその他の操作に対する完全なラスター化よりも機密性が低く、メモリの消費が大幅に少なくなります。
ジオメトリの実現を使用するタイミング
図形の変更頻度が低いが、変換の変更の影響を受ける可能性がある複雑なジオメトリをアプリでレンダリングする場合は、ジオメトリの実現を使用することを検討してください。
たとえば、静的マップを表示するが、ユーザーが拡大/縮小できるマッピング アプリケーションがあるとします。このアプリは、ジオメトリの実現を使用して恩恵を受けることができます。 レンダリングされるジオメトリは静的なままであるため、テセレーション作業を保存するためにキャッシュすると便利です。 ただし、ユーザーがズームするとマップがスケーリングされるため、アーティファクトのスケーリングにより、完全なラスター化をキャッシュすることは理想的ではありません。 ジオメトリの実現をキャッシュすると、アプリはスケーリング中に高いビジュアル品質を維持しながら、再テセレーション作業を回避できます。
一方、アニメーションジオメトリを持つ万華鏡アプリを考えてみましょう。 このアプリは、おそらくジオメトリの実現を使用して恩恵を受けないでしょう。 図形自体はフレーム間で変化するため、テセレーションをキャッシュすることは役に立ちません。 このアプリの最善の方法は、 ID2D1Geometry オブジェクトを 直接描画することです。
ジオメトリの実現を作成する
ID2D1GeometryRealization オブジェクトは、既存の ID2D1Geometry オブジェクトから作成する必要があります。 ジオメトリの実現を作成するには、 CreateFilledGeometryRealization メソッドまたは CreateStrokedGeometryRealization メソッドを呼び出し、実現する ID2D1Geometry を渡します。
- CreateFilledGeometryRealization は、図形の内部 ( FillGeometry を呼び出して描画される領域) の実現を作成します。
- CreateStrokedGeometryRealization は、 DrawGeometry を呼び出すことによって描画される領域である図形のストロークの実現を作成します。
両方の種類のジオメトリの実現は、 ID2D1GeometryRealization インターフェイスによって表されます。
ジオメトリの実現を作成する場合、 Direct2D は、指定されたジオメトリ内の曲線をポリゴン近似にフラット化する必要があります。 作成方法にはフラット化許容値パラメーターを指定する必要があります。これは、ジオメトリの真の曲線とその多角形近似との間の最大距離をデバイスに依存しないピクセル (DIP) で指定します。 フラット化許容値が低いほど、結果として得られるジオメトリ実現オブジェクトの忠実度が高くなります。 同様に、フラット化許容値を高くすると、ジオメトリの忠実度が低くなります。 忠実度の高いジオメトリの実現は、忠実度の低いジオメトリよりも描画コストが高くなりますが、可視成果物を導入する前にさらにスケーリングできることに注意してください。 フラット化許容値の使用に関するガイダンスについては、以下の 「ジオメトリの実現のスケーリング 」を参照してください。
注意
ジオメトリ実現オブジェクトは、特定のグラフィックス デバイスに関連付けられます。これらはデバイスに依存するリソースです。
ジオメトリの実現を描画する
描画ジオメトリの実現は、ビットマップなどの他の Direct2D プリミティブの描画に似ています。 これを行うには、 DrawGeometryRealization メソッドを呼び出し、描画するジオメトリ実現オブジェクトと使用するブラシを渡します。 他の Direct2D 描画メソッドと同様に、BeginDraw と EndDraw の呼び出しの間に DrawGeometryRealization を呼び出す必要があります。
ジオメトリの実現をスケーリングする
他の Direct2D プリミティブと同様に、ジオメトリの実現は、デバイス コンテキストで設定された変換を考慮します。 変換変換と回転変換は、ジオメトリの実現の視覚的な品質には影響しませんが、スケール変換では視覚的なアーティファクトが生成される可能性があります。
特に、ジオメトリの実現に十分な大きさを適用すると、真の曲線の多角形近似が明らかになる可能性があります。 ここでの画像は、遠くにスケールアップされた楕円ジオメトリの実現 (塗りつぶしとストローク) のペアを示しています。 曲線フラット化アーティファクトが表示されます。
ビジュアル品質に敏感なアプリでは、このようなことが起こらないように対策を講じる必要があります。 スケーリングの処理方法は、アプリのニーズによって異なります。 いくつかの異なる種類のアプリに推奨される方法をいくつか次に示します。
スケーリングしないアプリでのジオメトリの実現の使用
アプリがジオメトリの実現に対してスケーリングを実行しない場合は、単一のフラット化許容値を使用して、実現を 1 回だけ作成しても安全です。 (非スケーリング変換は、レンダリングされたジオメトリの実現の視覚的な品質には影響しません)。 ComputeFlatteningTolerance 関数を 使用して、DPI の適切なフラット化許容値を計算します。
float dpiX, dpiY;
deviceContext->GetDpi(&dpiX, &dpiY);
float flatteningTolerance = D2D1::ComputeFlatteningTolerance(
D2D1::Matrix3x2F::Identity(), // apply no additional scaling transform
dpiX, // horizontal DPI
dpiY // vertical DPI
);
少量でスケーリングするアプリでジオメトリの実現を使用する
アプリでジオメトリの実現を少量 (たとえば、最大 2 倍または 3 倍) だけスケールアップできる場合は、ジオメトリの実現を 1 回だけ作成し、既定よりも比例的に低いフラット化許容度で作成するのが適切な場合があります。 これにより、スケーリング成果物が発生する前に大幅にスケールアップできる、忠実度の高い実現が作成されます。トレードオフは、忠実度の高い実現を描画するには、より多くの作業が必要であるという点です。
たとえば、アプリがジオメトリの実現を 2 倍を超えるスケールになることは決してないことを知っているとします。 アプリでは、既定値の半分のフラット化許容値を使用してジオメトリの実現を作成し、必要に応じて実現を最大 2 倍にスケーリングできます。 computeFlatteningTolerance 関数を使用して、maxZoomFactor パラメーターとして 2.0 を渡して適切なフラット化許容値を計算します。
float dpiX, dpiY;
deviceContext->GetDpi(&dpiX, &dpiY);
float flatteningTolerance = D2D1::ComputeFlatteningTolerance(
D2D1::Matrix3x2F::Identity(), // apply no additional scaling transform
dpiX, // horizontal DPI
dpiY, // vertical DPI
2.0f // realization can be scaled by an additional 2x
);
大量にスケーリングするアプリでジオメトリの実現を使用する
アプリでジオメトリの実現を大量にスケールアップまたはスケールダウンできる場合 (たとえば、10 倍以上)、適切にスケーリングを処理する方が複雑になります。
これらのアプリのほとんどで推奨される方法は、視覚的な忠実性を維持し、アーティファクトのスケーリングを回避するために、シーンのスケールアップ時に徐々に低いフラット化許容値でジオメトリの実現を再作成することです。 同様に、シーンがスケールダウンされると、表示されない詳細を無駄にレンダリングしないように、アプリは徐々に高いフラット化許容値でジオメトリの実現を再作成する必要があります。 アプリでは、スケールが変更されるたびにジオメトリの実現を再作成しないでください。そうすると、テセレーション作業をキャッシュする目的が無効になるためです。 代わりに、アプリはジオメトリの実現頻度を低くする必要があります。たとえば、スケールの増減が 2 倍ごとに行われる場合などです。
ユーザーの操作に応じてアプリでスケールが変更されるたびに、アプリは新しいスケールを、ジオメトリの実現が最後に作成されたスケール (たとえば、 m_lastScale メンバーに格納) と比較できます。 2 つの値が近い場合 (この場合は 2 の係数内)、それ以上のアクションは実行されません。 ただし、2 つの値が近くない場合は、ジオメトリの実現が再作成されます。 ComputeFlatteningTolerance 関数は、新しいスケールに適したフラット化許容値を計算するために使用され、m_lastScaleは新しいスケールに更新されます。
さらに、アプリは常に、 maxZoomFactor パラメーターとして値 2 を ComputeFlatteningTolerance に渡すことで、新しいスケールに通常使用されるよりも小さい許容値を使用して実現を作成します。 これにより、スケーリングアーティファクトを発生させることなく、新しいジオメトリの実現を追加の係数2でスケールアップできます。
注意
ここで説明する方法は、すべてのアプリに適していない場合があります。 たとえば、アプリで非常に大きな要因でシーンを非常に迅速にスケーリングできる場合 (たとえば、数フレームのスパンで 100% から 1,000,000% に移動できる "ズーム" スライダーが含まれている場合)、このアプローチでは、フレームごとにジオメトリの実現を再作成することで過剰な作業が発生する可能性があります。 もう 1 つの方法は、シーンのスケールの各操作が完了した後 (たとえば、ユーザーがピンチ ジェスチャを完了した後) にのみジオメトリの実現を再作成することです。