【GLSL】UnityのInspector上でレイマーチングはできる


※この記事で使っているUnityのバージョンは Unity5.2.1p3 です。

![image](https://qiita-image-store.s3.amazonaws.com/0/44288/21f2f4e7-8311-89b1-d364-5cbedc6aa16a.png)

# C#コード
以下のスクリプトを作成して適当なオブジェクトにアタッチ

``` NewBehaviourScript.cs
using UnityEngine;
using System.Collections;

public class NewBehaviourScript : MonoBehaviour
{

}
```

以下のスクリプトを作成してEditorフォルダ内へ入れる

``` NewBehaviourScriptEditor.cs
using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(NewBehaviourScript))]
public class NewBehaviourScriptEditor : Editor
{
  private Material material = null;
  public override bool HasPreviewGUI()
  {
    return true;
  }

  public override GUIContent GetPreviewTitle()
  {
    return new GUIContent("ほげ");
  }

  public override void OnPreviewGUI(Rect r, GUIStyle background)
  {
    if (material == null)
    {
      Shader shader = Resources.Load<Shader>("Shader/RayMarch");
      this.material = new Material(shader);
    }

    base.OnPreviewGUI(r, background);
    Graphics.DrawTexture(r, Texture2D.whiteTexture, this.material);
    Repaint();

  }

}

```

# シェーダーコード
レイマーチングは<a href ="http://www.demoscene.jp/?p=811"> 全能感UP! GLSLで進めレイマーチング </a>を参考にしました.
光と法線の内積をとって影をつけています.

ファイルパスがAssets/Resources/Shader/RayMarch.shaderとなるように
配置します.


``` RayMarch.shader
Shader "Unlit/RayMarch"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
	}

		SubShader
	{
		Tags{ "RenderType" = "Opaque" }

		Pass
	{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

	struct appdata
	{
		float4 vertex : POSITION;
		float2 uv : TEXCOORD0;
	};

	struct v2f
	{
		float2 uv : TEXCOORD0;
		float4 vertex : SV_POSITION;
		float4 screenPos : TEXCOORD1;
	};

	sampler2D _MainTex;
	float4 _MainTex_ST;

	v2f vert(appdata v)
	{
		v2f o;
		o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
		o.uv = TRANSFORM_TEX(v.uv, _MainTex);
		return o;
	}

	float distanceFunc(float3 p) {
		float sphereSize = 0.1;
		float3 spherePos = float3(0.0, 0.0, -4.0);
		return length(p - spherePos) - sphereSize;
	}

	float3 getNormal(float3 p)
	{
		const float d = 0.0001;
		return
			normalize
			(
				float3
				(
					distanceFunc(p + float3(d, 0.0, 0.0)) - distanceFunc(p + float3(-d, 0.0, 0.0)),
					distanceFunc(p + float3(0.0, d, 0.0)) - distanceFunc(p + float3(0.0, -d, 0.0)),
					distanceFunc(p + float3(0.0, 0.0, d)) - distanceFunc(p + float3(0.0, 0.0, -d))
					)
				);
	}

	fixed4 frag(v2f i) : SV_Target
	{
		// fragment position
		float2 p = i.uv - 0.5;
		p *= 0.3;

		// camera
		float3 cPos = float3(0.0, 0.0, 2.0);
		float3 cDir = float3(0.0, 0.0, -1.0);
		float3 cUp = float3(0.0, 1.0, 0.0);
		float3 cSide = cross(cDir, cUp);
		float targetDepth = 1.0;

		// ray
		float3 ray = normalize(cSide * p.x + cUp * p.y + cDir * targetDepth);

		// marching loop
		float distance = 0.0; // レイとオブジェクト間の最短距離
		float rLen = 0.0;     // レイに継ぎ足す長さ
		float3  rPos = cPos;  // レイの先端位置
		for (int i = 0; i < 4; i++) {
			distance = distanceFunc(rPos);
			rLen += distance;
			rPos = cPos + ray * rLen;

		}

		// hit check
		if (abs(distance) < 0.1) {
			float t = _Time.z;
			float3 normal = getNormal(rPos); 
			float3 light = float3(0.3 * cos(t), 0.3 * sin(t), 0.0);
			float env = 0.3; // 環境光
			float diffuse = dot(normal, light);
			float color = env + diffuse;
			return float4(color, color, color, 1.0);
		}else
		{
			return float4(0.0, 0.0, 0.0, 1.0);
		}
	}

ENDCG
	}
	}
}
```

#結果
![image](https://qiita-image-store.s3.amazonaws.com/0/44288/aa4490fa-7ed0-ad9f-babd-e603a59f53f4.png)

#参考
全能感UP! GLSLで進めレイマーチング
http://www.demoscene.jp/?p=811