UE4で3Dモデルの断面を表示する

UE4で、3Dモデルの断面を表示させるために、UE4マテリアルのBoxMask-3Dを利用しました。
他にももっと良い方法がありましたら、ぜひコメントにお願いします！

# 動作環境
* UE4.24.3
* Windows 10
* GeForce RTX2070

# 参考サイト
* SphereMaskですが、とても参考になりました。
 * [Create dynamic mask within overlapping volume \- Unreal Engine Forums](https://forums.unrealengine.com/development-discussion/rendering/1528092-create-dynamic-mask-within-overlapping-volume)
 * [Location Based Opacity in UE4 \- Part1 \- YouTube](https://www.youtube.com/watch?v=XYPPd5oLoPM)
 * [Location Based Opacity in UE4 \- Part2 \- YouTube](https://www.youtube.com/watch?v=CkEueafOvFg)
 * [UE4 Object Mask l Unreal Engine 4.26 (Tutorial)](https://www.youtube.com/watch?v=wJgT9s_SQaU)
* BoxMaskの回転追従
 * https://forums.unrealengine.com/development-discussion/rendering/97595-boxmask-3d-rotation-question#post1640080


# 断面表示させたい3Dモデルを用意
* **UE4でアクタマージしたメッシュ(1メッシュ、1マテリアル)を使うことを前提** に書いています。
* 使用する3Dモデルを任意のマップに配置し、アクタマージ、マテリアルマージをしておきましょう。

# 断面表示するオブジェクト
## マテリアルパラメータを作成
先に、マテリアルのBoxMaskで使用するマテリアルパラメータを作成しておきます。

* コンテンツブラウザ上で右クリック > マテリアル・テクスチャ > マテリアルパラメータコレクション を選択し、MPC_CrossSectionを作成します。
設定するパラメータは、下図の通りです。
![MPC_CrossSection.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/07f45b4a-976d-02e6-a143-39302bd01e4d.png)

## マテリアルを作成
* コンテンツブラウザ上で右クリック > マテリアル を選択し、M_CrossSectionを作成します。
* 詳細タブで、MaterialのBlendModeをMaskedに変更します。
* マテリアルノードは下図の通りです。
![M_CrossSection.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/803e5362-f158-7aec-19b0-03f1a716cb72.png)

BoxMask-3Dの引数の内訳は以下の通り。

* A : World Position Offset(板に追従しているBoxの回転値を渡しています)
* B : マスクの中心点
* Bounds : BoxのサイズをVectorで指定
* Edge Falloff : エッジを柔らかく(Boxの角に丸みを持たせる)

引数Aで、Boxの回転値をVectorで直接渡そうとしたら上手くいかず、回転軸の計算の順番が関係していて、こちらの [フォーラム](https://forums.unrealengine.com/development-discussion/rendering/97595-boxmask-3d-rotation-question#post1640080) を参考にノードを組みました。

BaseTextureでは、デフォルトのテクスチャ(今回は、/Engine/EngineMaterials/Grid)を設定しています。

## 断面表示するオブジェクトのブループリントクラス
* コンテンツブラウザ上で右クリック > ブループリントクラス > すべてのクラス > StaticMeshActorを選択し、BP_CrossSectionを作成します。
* コンポーネントタブで、コンポーネントを追加 をクリックし、StaticMeshを追加します。
　![BP_CrossSection_component.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/e77bf8b4-f6ae-4a16-2e83-5b422add800e.png)
    * 詳細タブ > コリジョン で、
       * コリジョンプリセット : Custom
       * ObjectType : WorldDynamic

* 変数を追加します。
    * MaskedMesh (Static Mesh型、 **インスタンス編集可能にチェックを入れる** )
    * Material (Material Instance Dynamic型)
    * DiffuseTexture (Texture型)
* Construction Scriptで、下記の通りにノードを組みます。
    * [BP\_CrossSection　ConstructionScript > BlueprintUE\.com \| PasteBin For Unreal Engine 4](https://blueprintue.com/blueprint/n02as90s/)

# 断面表示させるための板
## 透明マテリアルを作成
* コンテンツブラウザ上で右クリック > マテリアル を選択し、M_PlaneTranslucentを作成します。
* 詳細タブで、BlendModeをTranslucentに変更します。
* オパシティに定数0.2を渡してあげます。(ガラスっぽいマテリアルとか凝りたい方はご自由にどうぞ)
![M_PlaneTranslucent.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/8bae09af-c8b1-e131-d805-6bafd95868c0.png)


## 板の枠線をUMGで作成
透明な板だと、板を見つけられないので、枠線を表示させるためのUMGを作成します。UMGでなくても他の方法でも良いですが、今回はこれで。

* コンテンツブラウザ上で右クリック > ユーザーインターフェース > ウィジェットブループリント を選択し、CrossSectionPlaneUMGを作成します。
* パレットタブで Border を検索し、階層タブの CanvasPanelの下にドラドラで追加します。
* 階層タブのBorderをクリックし、詳細タブで値を変更します。
    * スロット
        * サイズX : 1250
        * サイズY : 850
    * コンテンツ
        * Content Color and OpacityのRGBA: 1.0, 1.0, 1.0, 0.0
    * アピアランス
        * Brush : 枠線以外を透過した画像(↓こういうの)を用意して、UE4にインポートし、その画像を設定してください。 

![PlaneFrame.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/dacee3cf-aca7-ae6f-0f14-1c69c94ff6da.png)

## 板のブループリントクラス
* コンテンツブラウザ上で右クリック > ブループリントクラス > よく使うクラス > Actor を選択し、BP_CrossSectionPlaneを作成します。
* コンポーネントタブで、コンポーネントを追加 をクリックし、下記の3つのコンポーネントを追加します。
![BP_CrossSectionPlane_component.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/63c690b5-11cc-10f0-cb16-3734eec45adf.png)
    * **Plane** (Static Mesh)
        * トランスフォーム
            * 位置 ： 0.0, 0.0, -250.0
            * 拡大・縮小 : 0.34, 0.5, 0.001
            * 可動性 : ムーバブル
        * Static Mesh: Cube(/Engine/EnngineMeshs/Cube)
        * Materials: M_PlaneTranslucent(先ほど作成したもの)
        * Collision
            * コリジョンプリセットをCustom
            * ObjectTypeをPhysicsBody に変更
    * **Frame** (Widget Component)→Planeの子に配置
        * トランスフォーム
            * 回転 ： 0.0, 90.0, 0.0
            * 拡大・縮小 : 1.0, 0.215, 109.0
            * 可動性 : ムーバブル
        * ユーザーインターフェース
            * Widget Class : CrossSectionPlaneUMG(先ほど作成したもの)
            * Draw Size : X 1250, Y850
    *  **Box** (Static Mesh)
        * トランスフォーム
            * 拡大・縮小 : 1000.0, 1000.0, 500.0
            * 可動性 : ムーバブル
        * Static Mesh: Cube(/Engine/EnngineMeshs/Cube)
        * Materials: M_PlaneTranslucent(先ほど作成したもの)
        * Collision
            * Generate Overlap Events : チェックを外す
            * Can Character Step Up On : No
            * コリジョンプリセット : NoCollision
        * Rendering
            * Visible : チェックを外す

Boxは、BoxMasked-3Dで使用するLocation、Rotation、Boundsに値を渡すために配置。
Planeの上に大きいBoxが乗っていて、Planeを動かすとPlaneの面に沿ってBoxが追従して動いて、マスクされるイメージです。

* SetBoxMask関数を作成
    * BoxMaskの位置や回転をマテリアルに反映させるためのSetBoxMask関数を作成します。ノードは以下の通りです。
        * [SetBoxMask > BlueprintUE\.com \| PasteBin For Unreal Engine 4](https://blueprintue.com/blueprint/1ohavc3z/)
* Construction Scriptで、SetBoxMask関数を実行します。
* イベントグラフで、TickイベントにSetBoxMask関数をつなげます。

# レベルにBPを配置して確認
* レベルにBP_CrossSectionを配置します。
    * BP_CrossSectionの詳細タブで、デフォルト > MaskedMeshに断面表示させたいメッシュを設定します。(その上のStatic Meshの項目ではないので要注意！)
![BP_CrossSection_MapPlacement.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/07856d4f-79b2-e910-d5e1-2abc8aba553b.png)
* レベルにBP_CrossSectionPlaneを配置します。
    * BPの原点が板の中心ではないので、板が椅子にオーバーラップできる位置、回転値を設定してください。
* BP_CrossSectionPlaneを動かすと、こんな感じで断面を表示できます。
![CrossSectionTest-Unreal-Editor-2020-06-17-16-27-58_Trim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/b58af848-5463-3793-f076-fc9b07d9897e.gif)

# おまけ
VRで動かしてみました。
![cross_section_vr_comp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200334/d79c4a51-a5d8-fa07-0a21-4348e0aad37b.gif)