覚え書きブログ

読者です 読者をやめる 読者になる 読者になる

Unity覚え書き(全天球画像を球体に貼り付ける)

MCS Male Liteのキャラクターを、全天球画像(360度パノラマ画像)を貼り付けた球体のなかで歩かせてみた。

まず、下記のサイトで公開されているSphere100.fbxをダウンロードし、UnityプロジェクトのAssetsフォルダに置く。https://dl.dropboxusercontent.com/u/5911974/Sphere100.fbx

次に、Unityの画面で、Project->Assetsに、Sphere100.fbxが現れるので、それをSceneにドラッグアンドドロップする。
f:id:hirotaka_hachiya:20160703163224p:plain

次に、Sphere100のpositionを(0,0,0)に、Scaleを(100,100,100)に変更する。
f:id:hirotaka_hachiya:20160703163855p:plain
f:id:hirotaka_hachiya:20160703163753p:plain

次に、全天球画像をダウンロードする。適当にGoogleで「360 panorama image」などのキーワードで検索するといっぱいでてくる。
例えば、
http://www.hdrlabs.com/sibl/archive.html
http://rocket9.net/Japan_Trip_Panorama.htm
http://www.freegreatpicture.com/seamless-360-degree-panorama/degree-seamless-panoramic-13972
などから画像をダウンロードして、Assetsフォルダに置く。

今回は、下記のサイトのチャイニーズシアターの写真(Mans_Outside_8k_TMap.jpg)を用いてみた。
http://www.hdrlabs.com/sibl/archive.html

画像を、下図のようにSphere100のMesh Rendererのあたりにドラッグアンドドロップする。
f:id:hirotaka_hachiya:20160703191324p:plain

そして、光源の位置を、画像の太陽の位置に合わせて調整する。再生すると以下のような感じに、キャラクターがチャイニーズシアターの前をうろうろと歩かせることができた。ただし、キャラクターの影が球の下側に投影されて不自然な状態になっている。
f:id:hirotaka_hachiya:20160703200650p:plain

下記のサイトに従って、透明だけど影を表示するShaderの床(plane)を追加してみた。
http://tsubakit1.hateblo.jp/entry/2015/10/03/001105
http://forum.unity3d.com/threads/transparent-shader-receive-shadows.325877/
f:id:hirotaka_hachiya:20160703205756p:plain

手順は以下の通りである。
1)HierarchyにScaleが(2,2,2)のPlateを追加する

2)TransparentShadowCollector.shaderを追加
https://gist.github.com/tsubaki/055575f78334ed727350のshaderそのままでは床が透明にならなかったので、下記のように少し修正を加えたShaderを作る。

Shader "Custom/TransparentShadowCollector"
{
	Properties
	{
		_Color("Main Color", Color) = (1,1,1,0.5)	// 影の色
		_ShadowIntensity("Shadow Intensity", Range(0, 1)) = 0.6		// 影の強さ
	}


	SubShader
	{

//		Tags{ "Queue" = "Geometry-1" } // QueueをGeometry-1に設定すると球体より前にレンダリングしてしまうので、透明にならない?

		Pass
		{
			Tags{
				"RenderType" = "Transparent" 
				"Queue" = "Transparent"
				"LightMode" = "ForwardBase"
			}
			Blend SrcAlpha OneMinusSrcAlpha
			CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase

#include "UnityCG.cginc"
#include "AutoLight.cginc"
			uniform fixed4  _Color;
			uniform float _ShadowIntensity;

			struct v2f
			{
				float4 pos : SV_POSITION;
				LIGHTING_COORDS(0,1)
			};

			//vertex shader
			v2f vert(appdata_base v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);	// 頂点の位置を取得
				TRANSFER_VERTEX_TO_FRAGMENT(o);			// 照明の情報をflagment shaderに渡す
				return o;
			}

			//flagment shader
			fixed4 frag(v2f i) : COLOR
			{
				float attenuation = LIGHT_ATTENUATION(i);	// 照明の減衰率を計算
				return fixed4(0,0,0,(1 - attenuation)*_ShadowIntensity) * _Color;	// 影のレンダリング	
			}
			ENDCG
		}
	}
	Fallback "VertexLit"
}

オリジナルのものとの差分は、「Tags{ "Queue" = "Geometry-1" }」をコメントアウトしたところだけである。
Queueは、シェーダーが設定されているオブジェクトのレンダリングする順番を決めるものであり、下記のようにGeometryはBackgroundの次に大きな値をとるため、Backgroundの次にレンダリングされる。※Queueの値の小さいものからレンダリングされる。

Background 1000
Geometry 2000
AlphaTest 2450
Transparent 3000
Overlay 4000

通常の床の場合、それ以外のオブジェクトより先にレンダリングするので、「Geometry-1」に設定しBackgroundの次にレンダリングするので問題はない。ただし、今回の場合、全天球画像を貼り付けてある球体が床の外側にあり、その球体より先に床をレンダリングしてしまうというのはおかしなことになる。。。そのため、今回はコメントアウトした。

3)Materialを追加
Project->Assetsにて右クリックして、Create->Materialを選択する。Materialの名前を、transparent_shadow(任意)にする。

4)Materialのshaderを設定
3)で作ったMaterialのShaderをCustomize->TransparentShadowCollector.shaderに設定する。

5)PlaneのMaterialを設定
1)で作ったPlaneのMesh Renderer->Materials->Element 0に、3)のMaterialをドラッグアンドドロップして、Materialを設定する。そうすると下図のように透過しつつ影が投影されるようになる。

f:id:hirotaka_hachiya:20160703213610p:plain