Language:
Page Info
Skill Level:
Engine Version:
The translation of this page is out of date. Please see the English version for the latest version of the page.

スレートのクリップ処理システム

アンリアル エンジン 4.17 のリリースにより、新しいスレートのクリップ処理システムは 4.16 以前のバージョンに対して後方互換性を破ります。プロジェクトのアップデートについては、 本ページの 変換ガイド をご覧ください。

アンリアル エンジン (UE4) には、グラフィックスやテキストを画面の範囲内に制限するスレートのクリップ処理システムが導入されています。作成されたオブジェクトとパネルの周囲に 長方形 (またはクリップする領域) を作成します。このシステムはエディタおよび UMG UI Designer ツール全体で使用されます。ユーザーは、スレートを使って必要な時にエディタでパネルを移動し、そのサイズを変更することができます。 クリップ処理システムを使うと、テキストとグラフィックスをクリップする領域に収めることができます。UMG のレンダリング トランスフォームはさらに優秀で、UI に合うようにクリップします。

新機能

アンリアル エンジン 4.17 では、クリップ処理システムをさらに柔軟にするために大幅な見直しを行いました。これにより、プロジェクトの UI に使用する UMG などのツール システムにレンダリング エフェクトを追加する可能性が広がりました。 これまでのバージョンで使われていたクリップ処理システムはレイアウト空間が座標軸に平行のみという制限があったため、 下図のように、エッジ周りのレンダリング トランスフォーム全般が非常に難しい作業でした。

OldClippingIssue1.png

OldClippingIssue2.png

この例では、ウィジェットが回転しているのにクリップする領域 (白い点) は回転していないため、キャンバス パネル境界内にあるにもかかわらずグラフィックによるレンダリングが行われていないことが分かります。

クリッピング システムのバージョン 1.0 と 2.0 の違いを比較すると、このようになります。

Clipping 1.0 (4.16 以前)

Clipping 2.0 (4.17 以降)

  • 座標面に平行なクリップ処理は、レイアウト空間のみで機能します。

  • ウィジェットはすべてクリップされます。

  • クリッピングはすべてピクセル シェーダーで行われます (頂点ごとに浮動小数点が 6 個必要)。

  • 領域がバッチデータの一部なので、クリップする領域全体をバッチ処理できます。

  • 親から与えられたクリップする領域外でもレンダリング可能であり、レイアウト領域がクリップされる時に問題があるという点でレンダリング トランスフォームは「特殊」です。

  • 任意のクワッドであるクリップ処理

    • Scissor Rects を使って座標軸に平行にクリップした領域は、不要なピクセル シェーダー操作を防ぎます。

    • クリッピング ゾーンが複雑な場合は、ステンシル バッファが使われます。クリップするゾーンを自由に積み重ねたものをステンシル バッファの中に構成するためです。ドローコールをクリップする際はこれが使用されます。

  • 大部分はスクロール パネルと編集可能なテキスト フィールとで構成されているため、現時点で (デフォルトで) クリップするウィジェットは極めて少ないです。

    • レンダリング トランスフォームはもはや「特殊」ではなくなりました。トランスフォームを使えば、クリップしないという条件で別のウィジェット外でレンダリングすることが可能になります。

  • スレートはクリップする領域全体でのバッチができなくなりました。そのため、スレート頂点フォーマットの 6 つの浮動小数点が解放されるため、ピクセル シェーダーでクリップする必要がなくなりました。

これまでは空間は座標軸に平行であることが必須でしたが、新しいシステムはウィジェットのレンダリング空間でのクリップ処理に対応しているため、 (左図のような) クリップ処理の問題に対する心配がなくなり、ウィジェットの最外部にクリップするようになりました。ウィジェットの内側でトランスフォームを適用すると、端 (右) にぴったりクリップされます。

ClippingOld.png

ClippingNew.png

4.16 以前のクリッピングとトランスフォーム

4.17 以降で子のトランスフォームに合わせて

端でクリップ処理を適用した場合

ほとんどの場合、ウィジェットのクリップ ステートの変更を心配する必要はありません。例えばゲーム UI であれば、UMG ではウィジェット調節の必要はなく、スクロール パネル、またはエディタのようにテキストの長さを調節できないので、ウィンドウのサイズ変更のためップする必要のある場合にウィジェットを変更します。

ClippingExamples.png

以下は、各種クリップ処理設定の一例です。

  • 左 - ボタン上またはテキスト上でのクリップ処理が有効にされていない。

  • 中央 - テキスト上でクリップ処理が有効にされている。

  • 右 - ボタン上でクリップ処理が有効にされている。

異なるオブジェクトにクリップ処理を割り当てた時に生じる差に注目してください。境界線までクリップするため、パディングのようなものはここでは考慮されません。従って、ボタンにクリップ処理を設定すると、文字が端までずっと続いてからカットされます (右)。 その一方で、ボタンではなくテキストがクリップされる場合は、 テキストを収めるスペースをどれくらいにするかに基づいてクリップします (中央)。

シンプルな座標軸に平行なクリップ処理の例の他にも、積み重なっている任意のクワッドにも対応しています。

TransformClipping.png

これは極端なサンプルですが、3D トランスフォームとプロジェクションの導入には、プロジェクションでクリップされるウィジェットは投影空間でクリッピングを実行しなければならないので、 複数の任意のクリップする領域にまとめられることが必須です。

4.16 以前と 4.17 以降の変換ガイド

4.17 でのスレート クリップ処理システムへの変更は、以前のバージョンで使っていた後方互換性を破りました。以下のセクションでは、従来の問題を避けるためのプロジェクトのアップデート方法、 およびプロジェクトでウィジェットのデバッグに使用できるメソッドについて説明します。

ウィジェットのクリップ処理を有効にする

すべての UMG ウィジェットに対して、選択したウィジェットの [Details] パネルの Clipping プロパティを調整することができます。

UMGClippingProperty.png

詳細は UMG UI Designer を使ってクリップ処理をする を参照してください。

コードでクリップ処理を有効にするには、EWidgetClipping のクリップ処理用のプロパティを以下のいずれかのステートにする必要があります。

  • Inherit

  • ClipToBounds

  • ClipToBoundsWithoutIntersecting

  • ClipToBoundsAlways

  • OnDemand

以下がコードの例です。

SNew( SBorder )
.Clipping(EWidgetClipping::ClipToBounds)
[
    ...
]

非推奨とする API

以下の API は 4.16 現在、非推奨となっています。プロジェクトでこれらを使用している場合は、今それを使う必要があるのか検討してください。すべてのウィジェットがクリップするわけではないので、 クリップ処理システムでクリップする領域をうまく移動することができるコードは必要なくなりました。

  • FSlateDrawElement::Make___(...) - ドローコールごとにクリップする領域をパスする必要はなくなったので、関数コールを削除すれば自動的に新しいバージョンを使えるようになります。

  • SScissorRectBox - 座標軸に平行にクリップする領域は、どれもシザー領域となったため必要なくなりました。必ず削除し、直下の子ウィジェットでクリップ処理を有効にして、これまで行われていたこのジョブを置き換えてください。

カスタム クリッピング

ウィジェット内でクリップが必要となる場合があります。例えば、SProgressBar は、その進捗に応じて任意の位置を描画するプログレス バーをクリップする必要があります。クリップ処理を追加するためには、OnPaint で以下を行います。

OutDrawElements.PushClip(FSlateClippingZone(AllottedGeometry));

//TODO Do your drawing here, or child widget paint calls.

OutDrawElements.PopClip();

FSlateClippingZone は、既存コードに簡単な規則を可能にするいくつかのメソッドで初期化することができる、ウィンドウ領域の任意のクリップ対象領域です。

Hit Testing を変更するカスタム クリップ処理も必要であれば、以下を設定してクリップする領域を Hit Test Grid 上にプッシュする必要があります。

OutDrawElements.PushClip(FSlateClippingZone(AllottedGeometry));
Args.GetGrid().PushClip(FSlateClippingZone(GetCachedGeometry()));

//TODO Do your drawing here, or child widget paint calls.

OutDrawElements.PopClip();
Args.GetGrid().PopClip();

Hit Test Grid 用のクリッピング領域は、AllotedGeometry ではなくキャッシュ ジオメトリを使います。OnPaint では、Hit Grid はデスクトップ領域、AllotedGeometry は画面領域です。 従って、Tick に入ったらジオメトリを使用しなければなりません。

クリップ処理ステートのラップ処理

時々、クリップ処理ステートのあるウィジェットがクリップ処理をしない場合もあります。例えば、SScrollBox は他のウィジェットと同じくクリップ処理ステートの公式な変更が可能ですが、 SScrollBoxを構築すると、bClippingProxytrue` に設定されます。スレートがそのウィジェットをレンダリングする時、クリップ処理ステートを無視するため、スレートがそのウィジェットをレンダリングするとクリップ処理ステートを無視します。

内部では、SScrollBox 別のネスト化したウィジェットに情報を送る、あるいは命令されたクリップ処理ステートはすべて実行します。さらに、クリップ処理ステートをユーザーが変更する時、 SScrollBoxOnClippingChanged という名前の SWidget 関数をオーバーライドするので、新しいクリップ処理ステートをネスト化されたプライベート ウィジェットにミラーするタイミングが分かります。

カリングの変更

クリップ処理はレンダリング領域で実行されますが、エンジンはまだシンプルなバウンディング ボックスを使ってカリングを実行します。ただし、ボックスはレンダリング トランスフォームされたクリップ対象領域のバウンディング ボックスに基づきます。さらに、クリップ処理とカリングは時間経過と共にさらにニュアンスを帯びるので、カスタム パネルがあって MyClippingRect.IntersectionWith を使って描画が不可能なウィジェットの特定とカリングを行っている場合、SWidget 関数 IsChildWidgetCulled を使えるようになりました。以下が例です。

for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex)
{
    FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex];

    if (!IsChildWidgetCulled(MyCullingRect, CurWidget))
    {
        // Paint this widget.
    }
}

OnPaint コールで MyClippingRect を受け取る場所の名前はすべて MyCullingRect に変更します。

クリップ処理システムを変更しても、スレートのカリング方法は変更されません。以下の例では、親ウィジェット (青) がクリップする領域外 (緑) でカリングされると、 レンダリングを可能にするトランスフォームが親の範囲の完全に外側にある場合でも、子ウィジェット (黄) はカリングされます。フラグは直接の親ウィジェットによってのみチェックされるので、 クリップ処理プロパティ [Clip to Bounds - Without Intersecting] が有効にされた場合も同じです。

Widgets viewed outside | the clipping zone.

Widgets culled outside | the clipping zone.

クリップ処理のデバッグ

Widget Reflector はエディタ内で選択したウィジェットのクリップ処理ステートを表示します。

WidgetReflector.png

クリップ処理ステートが [On Demand] に設定されていることを表示する [Widget Reflector] を使ってテキスト ブロックが選択されています。

[Widget Reflector] を開くには、ファイル メニューから [Window] > [Developer Tools] > [Widget Reflector] を選択します。

以下は、エディタ内のすべてのウィジェットのクリップ処理およびカリング ステートのデバッグに使用可能なコンソール変数です。

コンソール変数

説明

Slate.ShowClipping

有効にすると、座標軸に平行にクリップする領域 (シザー領域) は黄色の枠線、ステンシル クリッピング クワッドは赤の枠線が表示されます。

画像をクリックしてフルサイズで表示

Slate.DebugCulling

有効にすると、パネルでのカリングの仕組み、および正しく動作しない原因が分かりやすくなります。GPU のクリップ処理を無効にしますが、そのまま正常に動作し続けるため、クリップする領域外でレンダリングされるものをすべて表示して、期待通りにカリングが行われているかを確認することができます。

Slate.EnableDrawEvents

有効にするとドロー イベントが有効になり、RenderDoc などのデバッグ時にバッチまたはクリップ処理ステートの推移が理解しやすくなります。Debug ビルドの使用時はデフォルトで有効になります。