UnityでGoogleストリートビューを使ったハコスコ対応アプリを作る

#UnityでGoogleストリートビューを使ったハコスコ対応アプリを作る
[Google Street View Image API](https://developers.google.com/maps/documentation/streetview/?hl=ja)を使うとHTTPリクエストでストリートビューの画像を取得することができます。Unityの[WWWクラス](http://docs-jp.unity3d.com/Documentation/ScriptReference/WWW.html)を使ってストリートビューの画像を取得し、全周囲画像を作って[ハコスコ](http://hacosco.com/)で体験してみましょう。Unity無料版で動作させることができます。

##全周囲画像の作成
カメラを中心に、上下左右前後に配置したPlaneにストリートビュー画像を貼付けて全周囲画像を作ります。はじめにカメラを原点に置きます。カメラを中心に上下左右前後にPlaneを置きます。向きや裏表面は後で調整しましょう。また、RenderSettingsのAmbient Lightは白にしておきます。

![スクリーンショット 2014-07-20 1.31.48.png](https://qiita-image-store.s3.amazonaws.com/0/26034/03ed60dd-e1ec-6059-ff18-8dba466c1696.png)

次に、ストリートビュー画像を取得するスクリプトを書きます。プログラム実行時に、指定された緯度経度、heading、pitchのストリートビュー画像を取得しPlaneにテクスチャとして貼付けます。[Google Street View Image API](https://developers.google.com/maps/documentation/streetview/?hl=ja)の仕様についてはリンク先を参照してください。今回は緯度経度は固定で、headingとpitchを外から与えるようにしています。

```csharp:StreetViewImageLoader.cs
using UnityEngine;
using System.Collections;

public class StreetViewImageLoader : MonoBehaviour {

	public double heading = 0.0;
	public double pitch = 0.0;

	private int width = 640;
	private int height = 480;

	private double longitude = 139.667431;
	private double latitude = 35.697408;

	// Use this for initialization
	void Start () {
		StartCoroutine(GetStreetViewImage(latitude, longitude, heading, pitch));
	}

	private IEnumerator GetStreetViewImage(double latitude, double longitude, double heading, double pitch) {
		string url = "http://maps.googleapis.com/maps/api/streetview?" + "size=" + width + "x" + height + "&location=" + latitude + "," + longitude + "&heading=" + heading + "&pitch=" + pitch + "&fov=90&sensor=false";

		WWW www = new WWW(url);
		yield return www;

		renderer.material.mainTexture = www.texture;
	}
}

```

スクリプトを各Planeに追加します。まずは実行して画像が取得できることを確認しましょう。

![スクリーンショット 2014-07-20 1.54.09.png](https://qiita-image-store.s3.amazonaws.com/0/26034/118e7b68-7f10-edc6-bbaf-46fd35ff0981.png)

画像が取得できることを確認できたら、それぞれの面ごとに、面の向きや取得するストリートビューの方向を設定します。カメラはPlaneの内側にあるので、面を内側に向ける必要があります。ストリートビューの方向はheadingとpitchで設定します。前後左右のPlaneにはheadingを0(前)、90(右)、180(後)、270(左)に、上下のPlaneにはpitchを90(上)、-90(下)と設定します。Sceneビューのライトを切って、実行時の画面を確認しながら調整しましょう。

![スクリーンショット 2014-07-20 2.00.36.png](https://qiita-image-store.s3.amazonaws.com/0/26034/6caf085a-674f-8dfc-d9f5-80b137c72091.png)

(ちなみに今回の方法では各面の境目に多少のずれが発生します。特に空と地面は大きなずれが出ます)

##端末のジャイロの値をカメラの姿勢に反映する
端末のジャイロの値をカメラの姿勢に反映するスクリプトを書きます。

```csharp:MyCameraController.cs
using UnityEngine;
using System.Collections;

public class MyCameraController : MonoBehaviour {
	
	// Update is called once per frame
	void Update () {
		Quaternion gyro = Input.gyro.attitude;
		this.transform.localRotation = Quaternion.Euler(90, 0, 0) * (new Quaternion(-gyro.x, -gyro.y, gyro.z, gyro.w));
	}
}

```

スクリプトをカメラに追加して端末に出力してみましょう。ここではiPhoneで動作させてみます。PlayerSettingsのOrientationをLandscape Leftに設定します。また、自動スリープを無効にするよう、以下のスクリプトをカメラに追加します。

```csharp:NeverSleep.cs
using UnityEngine;
using System.Collections;

public class NeverSleep : MonoBehaviour {

	void Awake () {
		Screen.sleepTimeout = SleepTimeout.NeverSleep;
	}
}
```

端末に出力し、端末を色々な方向に向けてみて正しく見えるか確認してみましょう。

#ストリートビュー画像上でUnityちゃんを動かす
せっかくUnityで作っているので、ストリートビュー画像上でUnityちゃんを動かしてみましょう。この[動画](https://vine.co/v/MQtEXvW2v6E)のように、道路を突っ走ってもらうことにします。

Asset StoreからUnityちゃんをダウンロードしてインポートします。HierarchyにunitychanのPrefabとDirectional light for UnityChanを追加します。Unityちゃんのスケールを調整します。ここでは2.5としました。

![スクリーンショット 2014-07-21 1.25.49.png](https://qiita-image-store.s3.amazonaws.com/0/26034/f6ccd12c-ac91-734b-6459-dea6f263907a.png)

また、Directional lightの影響をUnityちゃんにだけに与えるため、BrightというLayerを追加し、UnityちゃんのLayerをBrightに、Directional lightのCulling MaskをBrightに設定します。

後の作業をシンプルにするために、今回は影は[丸影の画像](https://qiita-image-store.s3.amazonaws.com/0/26034/a630f455-4b1e-86c0-642b-f6b12b39efd9.png)をPlaneに貼付けただけの影を使います(Projectorも使用しません)。Directional lightのShadow TypeをNo Shadowsに変更します。Unityちゃんを地面に立たせて影の位置を調整しましょう。

![スクリーンショット 2014-07-21 1.30.45.png](https://qiita-image-store.s3.amazonaws.com/0/26034/da2932f7-e6e7-ff1a-fbd8-09721302ef18.png)

Unityちゃんを遠くに配置します。Unityちゃんに走るモーションを割り当てておきましょう。

![スクリーンショット 2014-07-21 1.31.23.png](https://qiita-image-store.s3.amazonaws.com/0/26034/ba1ab716-6e69-fe37-fb5e-45dc76654a05.png)


次にUnityちゃんを移動させるスクリプトを書きます。実装を楽にするためにiTweenを使います。Asset StoreからiTweenをダウンロードしてインポートします。次のようなスクリプトを書きます。

```csharp:UnityChan.cs
using UnityEngine;
using System.Collections;

public class UnityChan : MonoBehaviour {

	// Use this for initialization
	void Start () {
		iTween.MoveTo(gameObject, iTween.Hash("x", 50, "y", -4.980127, "z", 5.0, "time", 6.0f, "easetype", iTween.EaseType.linear, "looptype", iTween.LoopType.loop));
	}
}

```

これでUnityちゃんが走るようになってくれます。が、Planeの奥にいる場合にはUnityちゃんの姿は隠れて見えません。常にPlaneの前面に描画されるようにします。

Shaderを追加して編集します。"Queue"="Background”とZWrite Offを追加して、先にレンダリングするようにし、その際にZバッファへの書き込みを行わないようにします。

```shader:Background.shader
Shader "Custom/Background" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" "Queue"="Background" }
		LOD 200
		
		ZWrite Off
		
		CGPROGRAM
		#pragma surface surf Lambert

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}


```

Unityちゃんの進行方向に配置されているPlaneに、このShaderをセットします。

![スクリーンショット 2014-07-21 1.50.16.png](https://qiita-image-store.s3.amazonaws.com/0/26034/e5706f32-f484-ae6f-6d8b-b96099d02e9d.png)

これでUnityちゃんが常にPlaneの前面に表示されるようになります。

![写真 2014-07-21 2 00 00.png](https://qiita-image-store.s3.amazonaws.com/0/26034/33750ee4-9bd2-2029-2537-014bde91eb69.png)

#Unityちゃんライセンス
![imageLicenseLogo.png](https://qiita-image-store.s3.amazonaws.com/0/26034/919afa36-96cc-9dc9-bc4e-ab362d220699.png)
このコンテンツは、[『ユニティちゃんライセンス』](http://unity-chan.com/download/license.html)で提供されています。