web-dev-qa-db-ja.com

Android(2D)のCanvas描画パイプラインをどのように組み合わせるのですか?

Androidの(2D)Canvas描画パイプラインのコンポーネントがどのように組み合わされるかについて、もっと理解したいと思います。

たとえば、 XferModeShaderMaskFilter および ColorFilter はどのように相互作用しますか?これらのクラスのリファレンスドキュメントはかなりまばらで、 Canvas および Paint のドキュメントは、実際に役立つ説明を追加していません。

また、固有の色を持つ描画操作(例:drawBitmap、またはdrawRectのような「ベクター」プリミティブ)がどのようにこれに当てはまるかは、私には完全に明らかではありません。 Paintの色を使用して、代わりに固有の色を使用しますか?

また、次のようなことができることにも驚きました。

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);

これにより、楕円が消去されます。これに気付く前の私のメンタルモデルは、キャンバスに描画すると(概念的には)別の "レイヤー"に描画され、そのレイヤーは、ペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。 CLEARalwaysが色(およびアルファ)を​​設定するので、それがそのように単純であれば、上記のコードはビットマップ全体(クリッピング領域内)を消去します。ソースのアルファに関係なく0に。したがって、これは、消去を楕円形に制限するために行われている追加の種類のマスキングがあることを意味します。

私は APIデモ を見つけましたが、各デモは「真空」で動作し、それが焦点を当てているもの(例:XferModes)が他のもの(例:ColorFilters)とどのように相互作用するかを示していません。

十分な時間と労力で、これらの部分がどのように関連しているか、またはソースを解読できるかを経験的に理解できますが、誰か他の人がすでにこれを解決しているか、またはさらに良いことに、パイプライン/図面モデルの実際のドキュメントがあることを願っています私は逃した。

この質問は、コードを この回答は別のSO質問 で参照してください。

更新

いくつかのドキュメントを探していると、ここで私が興味を持っているものの多くは skia の上にかなり薄いベニアのように見えるので、役に立つであろういくつかのskiaドキュメントがあるかもしれません。私が見つけることができる最高のものは SkPaintのドキュメント です:

ペイントに割り当てることができる効果には6つのタイプがあります。

  • SkPathEffect-アルファマスク(ダッシュなど)を生成する前のジオメトリ(パス)の変更
  • SkRasterizer-カスタムマスクレイヤー(シャドウなど)の作成
  • SkMaskFilter-色を付けて描画する前のアルファマスクの変更(ぼかし、エンボスなど)
  • SkShader-例グラデーション(線形、放射状、スイープ)、ビットマップパターン(クランプ、繰り返し、ミラー)
  • SkColorFilter-xfermodeを適用する前にソースカラーを変更します(例:カラーマトリックス)
  • SkXfermode-例ポーターダフ転送モード、ブレンドモード

明示的には述べられていませんが、ここでの効果の順序は、パイプラインに現れる順序であると推測しています。

60

Romain Guyが言ったように、「この質問はStackOverflowで答えるのは困難です」。実際には完全なドキュメンテーションはありませんでした。完全なドキュメンテーションは、ここに含めるにはかなり大きなものになります。

結局、ソースを読んで、たくさんの実験をしました。私は途中でメモを取って、それらをここで見ることができるドキュメントに変えました:

この図と同様に:

enter image description here

これは明らかに「非公式」なので、通常の警告が適用されます。

上記に基づいて、ここに「サブ質問」のいくつかへの回答があります:

また、固有の色を持つ描画操作(例:drawBitmap、またはdrawRectのような「ベクター」プリミティブ)がどのようにこれに当てはまるかは、私には完全に明らかではありません。 Paintの色を使用して、代わりに固有の色を使用しますか?

「ソースカラー」はShaderに由来します。 drawBitmapでは、ALPHA_8Shader以外が使用されている場合、BitmapShaderは一時的にBitmapに置き換えられます。他の場合では、Shaderが指定されていない場合、単色を生成するShaderのみが使用され、Paintの色が使用されます。

また、次のようなことができることにも驚きました。

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);

これにより、楕円が消去されます。これに気付く前の私のメンタルモデルは、キャンバスに描画すると(概念的には)別の "レイヤー"に描画され、そのレイヤーは、ペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。 CLEARalwaysが色(およびアルファ)を​​設定するので、それがそのように単純であれば、上記のコードはビットマップ全体(クリッピング領域内)を消去します。ソースのアルファに関係なく0に。したがって、これは、消去を楕円形に制限するために行われている追加の種類のマスキングがあることを意味します。

XferModeは、「ソースカラー」(Shaderから)および「デスティネーションカラー」(CanvasBitmapから)に適用されます。次に、ラスタライズで計算されたマスクを使用して、結果を宛先とブレンドします。詳細については、上記のドキュメントの転送フェーズを参照してください。

48

StackOverflowでこの質問に答えることは困難です。ただし、始める前に、形状(たとえば、drawRect())には固有の色がないことに注意してください。色情報alwaysはPaintオブジェクトから取得されます。

これにより、楕円が消去されます。これに気付く前の私のメンタルモデルは、キャンバスに描画すると(概念的には)別の "レイヤー"に描画され、そのレイヤーは、ペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。 CLEARはソースのアルファに関係なく常に色(およびアルファ)を​​0に設定するため、それがそのように単純であれば、上記のコードはビットマップ全体(クリッピング領域内)を消去します。したがって、これは、消去を楕円形に制限するために行われている追加の種類のマスキングがあることを意味します。

モデルが少しずれています。楕円は別のレイヤーに描画されません(Canvas.saveLayer()を呼び出さない限り)。楕円はCanvasのバッキングビットマップに直接描画されます。ペイントの転送モードは、プリミティブによって描画されるすべてのピクセルに適用されます。この場合、楕円のラスタライズの結果のみがビットマップに影響します。特別なマスキングは行われていません。楕円自体isマスクです。

とにかく、ここにパイプラインの簡略図があります。

  1. プリミティブ(長方形、楕円形、パスなど)
  2. PathEffect
  3. ラスタライズ
  4. MaskFilter
  5. カラー/シェーダー/カラーフィルター
  6. Xfermode

(私はあなたの更新を見たばかりで、はい、あなたが見つけたものはパイプラインのステージを順番に説明しています。)

レイヤー(Canvas.saveLayer())を使用すると、パイプラインが2倍になるため、パイプラインが少し複雑になります。最初にパイプラインを経由してプリミティブをオフスクリーンビットマップ(レイヤー)内にレンダリングし、パイプラインを経由してオフスクリーンビットマップをキャンバスに適用します。

11
Romain Guy

SkPathEffect-アルファマスクを生成する前のジオメトリ(パス)の変更(例:ダッシュ)SkRasterizer-構成するカスタムマスクレイヤー(例:シャドウ)SkMaskFilter-色付けして描画する前のアルファマスクの変更(例:ぼかし)SkShader-例グラデーション(線形、放射状、掃引)、ビットマップパターン(クランプ、繰り返し、ミラー)SkColorFilter-xfermode(カラーマトリックスなど)を適用する前にソースカラーを変更しますSkXfermode-たとえばポーターダフ転送モード、ブレンドモード

http://imgur.com/0X5Yqod

0
Tường Vũ