メインコンテンツにスキップ
バージョン: v8.x

グラフィック

Graphics は、PixiJSツールボックスの中でも複雑で、誤解されやすいツールです。一見すると、図形を描くためのツールのようですが、実際はマスクを生成するためにも使用できます。これはどのように機能するのでしょうか?

このガイドでは、Graphics オブジェクトの動作の考え方から始めて、その謎を解き明かしていきます。

グラフィックのサンプルコードをご覧ください。

Graphics は描画ではなく構築のためのもの

Graphics クラスを初めて使用するユーザーは、その動作に戸惑うことがよくあります。Graphics オブジェクトを作成して四角形を描くサンプルコードを見てみましょう。

// Create a Graphics object, draw a rectangle and fill it
let obj = new Graphics()
.rect(0, 0, 200, 100)
.fill(0xff0000);

// Add it to the stage to render
app.stage.addChild(obj);

このコードは機能し、画面に赤い四角形が表示されます。しかし、よく考えてみると、かなり混乱します。なぜオブジェクトを*構築*するときに四角形を描くのでしょうか?描画は1回限りのアクションではないでしょうか?2フレーム目にはどのように四角形が描画されるのでしょうか?さらに、たくさんの drawThis や drawThat 呼び出しで Graphics オブジェクトを作成し、それを*マスク*として使用すると、さらに奇妙になります。一体どういうことでしょうか?

問題は、関数名が画面にピクセルを配置する*描画*というアクションを中心にしていることです。しかし、それにもかかわらず、Graphics オブジェクトは実際には*構築*に関するものです。

rect() 呼び出しをもう少し詳しく見てみましょう。rect() を呼び出すと、PixiJS は実際には何も描画しません。代わりに、「描画」した四角形を後で使用するジオメトリのリストに格納します。その後、Graphics オブジェクトをシーンに追加すると、レンダラーが来て、Graphics オブジェクトに自身をレンダリングするように要求します。その時点で、ジオメトリリストに追加した他の形状、線などと合わせて、四角形が実際に描画されます。

何が起こっているのかを理解すれば、すべてがより理にかなってきます。たとえば、Graphics オブジェクトをマスクとして使用する場合、マスキングシステムはジオメトリリスト内のグラフィックプリミティブのリストを使用して、画面に表示されるピクセルを制限します。描画は関係ありません。

だからこそ、Graphics クラスを描画ツールではなく、ジオメトリ構築ツールと考えることが役立つのです。

プリミティブの種類

Graphics クラスには多くの関数がありますが、簡単に言うと、追加できる基本的なプリミティブのリストは次のとおりです。

  • 四角形
  • 角丸四角形
  • 楕円
  • 円弧
  • ベジェ曲線と2次曲線

さらに、以下の複雑なプリミティブにアクセスできます。

  • トーラス
  • 面取り四角形
  • フィレット四角形
  • 正多角形
  • 星形
  • 角丸多角形

SVGもサポートされています。ただし、PixiJSが穴をレンダリングする方法の性質上(パフォーマンスを優先)、複雑な穴の形状は正しくレンダリングされない場合があります。しかし、ほとんどの形状では、これでうまくいきます!

 let mySvg = new Graphics().svg(`
<svg>
<path d="M 100 350 q 150 -300 300 0" stroke="blue" />
</svg>
`);

GraphicsContext

スプライトとその共有テクスチャの関係を理解することは、`GraphicsContext`の概念を理解するのに役立ちます。複数のスプライトがピクセルデータを複製せずにメモリを節約するために単一のテクスチャを利用できるのと同様に、GraphicsContextは複数のGraphicsオブジェクト間で共有できます。

この`GraphicsContext`の共有は、グラフィック命令をGPU対応のジオメトリに変換するという負荷の高いタスクが一度だけ行われ、その結果がテクスチャと同様に再利用されることを意味します。 これらのアプローチの効率の違いを考えてみましょう。

コンテキストを共有せずに個々の円を作成する

// Create 5 circles
for (let i = 0; i < 5; i++) {
let circle = new Graphics()
.circle(100, 100, 50)
.fill('red');
}

GraphicsContextを共有する場合

// Create a master Graphicscontext
let circleContext = new GraphicsContext()
.circle(100, 100, 50)
.fill('red')

// Create 5 duplicate objects
for (let i = 0; i < 5; i++) {
// Initialize the duplicate using our circleContext
let duplicate = new Graphics(circleContext);
}

さて、これは円や正方形では大したことではないかもしれませんが、SVGを使用している場合は、毎回再構築するのではなく、`GraphicsContext`を共有することが非常に重要になります。 テクスチャと同様に、最高のパフォーマンスを得るためには、コンテキストを事前に作成して再利用することをお勧めします!

let circleContext = new GraphicsContext()
.circle(100, 100, 50)
.fill('red')

let rectangleContext = new GraphicsContext()
.rect(0, 0, 50, 50)
.fill('red')

let frames = [circleContext, rectangleContext];
let frameIndex = 0;

const graphics = new Graphics(frames[frameIndex]);

// animate from square to circle:

function update()
{
// swap the context - this is a very cheap operation!
// much cheaper than clearing it each frame.
graphics.context = frames[frameIndex++%frames.length];
}

`Graphics`オブジェクトを作成するときに`GraphicsContext`を明示的に渡さない場合、内部的には独自のコンテキストを持ち、`myGraphics.context`を介してアクセスできます。 GraphicsContextクラスは、Graphics親オブジェクトによって作成されたジオメトリプリミティブのリストを管理します。 グラフィック関数は文字通り内部コンテキストに渡されます

let circleGraphics = new Graphics()
.circle(100, 100, 50)
.fill('red')

上記と同じ

let circleGraphics = new Graphics()

circleGraphics.context
.circle(100, 100, 50)
.fill('red')

`Graphics.destroy()`を呼び出すと、グラフィックが破棄されます。 コンストラクターを介してコンテキストが渡された場合、そのコンテキストの破棄はユーザーに任されます。 ただし、コンテキストが内部的に作成された場合(デフォルト)、破棄されるとGraphicsオブジェクトは内部の`GraphicsContext`を破棄します。

表示用のグラフィック

さて、`Graphics`クラスの仕組みについて説明したので、次はその使用方法を見てみましょう。 `Graphics`オブジェクトの最も明白な用途は、動的に生成された形状を画面に描画することです。

これを行うのは簡単です。 オブジェクトを作成し、さまざまなビルダー関数を呼び出してカスタムプリミティブを追加し、オブジェクトをシーングラフに追加します。 レンダラーはフレームごとに`Graphics`オブジェクトに自身をレンダリングするように要求し、関連付けられた線と塗りつぶしのスタイルを持つ各プリミティブが画面に描画されます。

マスクとしてのグラフィック

Graphicsオブジェクトを複雑なマスクとして使用することもできます。 そのためには、通常どおりオブジェクトとプリミティブを構築します。 次に、マスクされたコンテンツを含む`Container`オブジェクトを作成し、その`mask`プロパティをGraphicsオブジェクトに設定します。 コンテナの子は、作成したジオメトリの内部でのみ表示されるようにクリップされます。 この手法は、WebGLとCanvasベースのレンダリングの両方で機能します。

マスキングのサンプルコードをご覧ください。

注意点と落とし穴

`Graphics`クラスは複雑なため、使用時に注意すべき点がいくつかあります。

**メモリリーク**:不要になった`Graphics`オブジェクトで`destroy()`を呼び出して、メモリリークを回避します。

**穴**: 作成する穴は、形状内に完全に含まれている必要があります。そうでない場合、正しく三角形分割できない可能性があります.

**ジオメトリの変更**:`Graphics`オブジェクトの形状を変更する場合、削除して再作成する必要はありません。 代わりに、`clear()`関数を使用してジオメトリリストの内容をリセットし、必要に応じて新しいプリミティブを追加できます。 これを毎フレーム行う場合は、パフォーマンスに注意してください.

**パフォーマンス**:`Graphics`オブジェクトは一般的に非常に高性能です。 ただし、非常に複雑なジオメトリを作成すると、レンダリング中にバッチ処理を許可するしきい値を超える可能性があり、パフォーマンスに悪影響を与える可能性があります。 バッチ処理には、多くの形状を持つ単一の`Graphics`ではなく、多くの`Graphics`オブジェクトを使用する方が適しています.

**透明度**:`Graphics`オブジェクトはプリミティブを順番にレンダリングするため、ブレンドモードまたは部分的な透明度をオーバーラップするジオメトリで使用する場合は注意が必要です。 `ADD`や`MULTIPLY`などのブレンドモードは、最終的な合成画像ではなく、*各プリミティブで*機能します。 同様に、部分的に透明な`Graphics`オブジェクトは、プリミティブが重なり合っていることを示します。 単一のフラット化されたサーフェスに透明度またはブレンドモードを適用するには、AlphaFilterまたはRenderTextureの使用を検討してください.