UE4 レイマーチング法で遊ぶ

# 概要
レイマーチング法で色々レンダリングして遊ぶための記事です。
![raymarching_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/45b851df-4d74-10c7-c265-fdec71df5d49.png)

![raymarching_08_02.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/00052056-d70b-90c3-e731-93d1e5c2bd45.png)


# 必要な知識
* UE4の基本操作
* マテリアル（等）の作成・適用
* HLSLを少々
* ベクトルの計算（推奨）

# 注意点
MaterialEditorのCustomノードを使用しますが、
コード編集時の挙動がやや不安定な環境があるようです(ver 4.7.3)。
特に文字列選択時にトラブりやすいので、こまめなセーブを心がけて下さい。

# レイマーチング法とは

ここを読むとだいたい分かります！(i-saint氏による、作例の超かっこいい記事です）
http://i-saint.hatenablog.com/entry/2013/08/20/003046

ざっくりと説明すると、
表示したい物体と座標との距離を返す関数("distance function"と呼ばれる）を用いて視線と物体の交差する位置を計算、レンダリングする手法です。

ポリゴンを使った通常の手法とは異なり数式により形状を表現します。
生物等の恣意的な形にすることは困難ですが、
幾何学的な図形や、無限（概念的には）に繰り返すような表示が得意です。


# 球を表示する

とりあえず、ベタ塗りの球を表示するのが最も簡単なのでそれをやります。

レイマーチングは概念的にはポリゴンに依存しないレンダリング手法ですが、
UE4ではマテリアルを割り当てるための枠をマップ上に作るのが表示するには楽です。
・枠の内側にカメラがある時：全視界がRayMarchingで描画される
・枠の外側にカメラがある時：枠の中がRayMarchingで描画される
という見え方になります。


## １．レイを飛ばすためのMaterialFunctionを作る
必須ではありませんが、少しだけ見やすくなります。
まずMaterialFunctionを作ります。
名前は何でもいいですが、後での説明のためにViewRayとしておきます。
![raymarch_00.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/cc642588-cdaa-3e4e-7300-403821b52e61.png)
こんな感じで繋ぎます。
・position からカメラの座標、
・direction からカメラ→現在のピクセル座標方向ベクトル
をWorld座標系で返します。

## ２．マテリアルの設定
ライティングの影響を受けないようにします。
![raymarch_01.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/f884d61f-d039-8245-fd14-3e7f26829c54.png)

Customノードを配置します。

入力として
pos // レイの始点
dir // レイの方向（長さ１）
spherePos  // 球の座標
sphereRadius  // 球の半径
endDistance  // 描画する距離の限界
を設定します。

コードを書きます。

```
float3 currentPos = pos;

float retval = 0;

for( int i=0; i<20; ++i )
{
 float distance = length( spherePos - currentPos ) - sphereRadius;
 if( distance < 0.1 )
 {
  retval = 1;
  break;
 }
 else if( distance > endDistance )
 {
  break;
 }
 currentPos += distance * dir;
 retval += 0.01;
}

return retval;
```
こんなかんじでつなぎます。
![raymarch_02.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/57d6c916-b004-a9db-d1d6-f355dbd11530.png)



## ３．部屋を作る
先ほど作成したマテリアルが選択されている状態にして、
BSP-> Sphere　（べつにSphereでなくてもよい）をマップに配置し適当なボリュームを確保します。
半径2000くらいでやります。
分かりやすいよう、座標は原点(0,0,0)に設定するのがよいでしょう。
次に、同じ位置にほんの少し小さい(1950とか)Sphereを配置し、BrushTypeをSubtractに設定します。
こうすることにより空洞が作れます。
![raymarch_04.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/f96b4d15-f112-9db5-3ac4-46f00d9a6e3b.png)


これで周囲の少しぼやけた球っぽいものがBSPの内部に表示されると思います。
ループ末尾の
retval += 0.01;
によって、球の周辺部が明るくなります（別にしなくてもいいですが演出として）。
![raymarch_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/61553/27dd4665-9888-3e4a-d490-64ccd3260685.png)


# その他の図形を作る
Customコードのうち
float distance = length( spherePos - currentPos ) - sphereRadius;
の部分を様々な式に書き換えることで色々出ます。
下記のページが参考になります。
http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm

# Unrealっぽいマテリアルを適用する（やや高度？）

法線情報をも計算することでライティングを適用できます。
そのための設定についてダラダラと並べておきます。

マテリアルの設定を幾つか変更します。
* ShadingModel : DefaultLit（ライティングON）
* BlendMode : Masked ~~Translucent（透過有効）~~
*  ~~TranslucencyLightingMode : TLMSurface（半透明オブジェクトに通常のライティングを適用）~~ 
* TangentSpaceNormal : Off（接空間で法線を計算することは通常ないと思います）
(3/25 Transparent -> Masked に変更しました。半透明な表示をするのでなければこのほうがよさそうです)

あとはBaseColorやらMetalicやらを適当に設定します。

Custom内で法線を計算、出力する必要があります。

Customノードは1変数しか出力できないようですので出力形式としてはVector4を選択し、
xyz に法線、w にOpacity等の追加情報を入れるのがとりあえず分かりやすいと思います。


# まとめ
UE4でレイマーチングるための手順について紹介しました。


以上です。