【Unity/Shader】漫画に変換された世界を覗くコマの作り方

この記事では、「漫画に変換された世界を見ることができるコマ」のつくり方を紹介します。

初めて記事を見た方はどういうことかよく分からないと思うので、参考のTwitter動画をご覧ください。https://twitter.com/OEKA_AKI/status/1115272322217271296

以上のように、
①コマを通すと漫画に変わった背景
②コマ毎に違ったオブジェクト
が見えることを本記事の目標とします。

簡略化して説明するので、本記事で完成する具体的なイメージは以下のようになります。

赤い壁をコマを通して覗くと、漫画化した壁とそれぞれのコマから別の球体が見える

簡略化しますが、生成するファイル数や工程数はやや多いです。
とりあえずやり方を説明しながら、ところどころでどんな仕組みかを説明できたらしていきたいと思います。

特にこの方法はシェーダーの使い方が少しわからないと応用が難しいので、ぜひ覚えてください!

仕組みのざっくりとした説明

意味のわからない工程を一つ一つ追うだけだと間違えやすいと思うので、どういう流れで作っていくか書き出してみます。

① 背景となる壁(Wall)をつくる
② Wallを透過するコマをつくる

③ コマ内だけで表示される漫画化した壁(ComicWall)をつくる

④ 漫画の球体(ComicObject1)を映すためのコマを、②に重ねてつくる
⑤ コマ内だけで表示されるComicObject1をつくる

⑥ コマを複製して2つにする
⑦ 複製したコマだけで表示されるComicObject2をつくる

仕組みとしては、
1 ベースの壁と全く同じ大きさの漫画風の壁を配置する
2 背景となる壁を共有したままコマごとに違う球体を表示するためにコマを2重にする
の2点が重要な項目となっています。

以上がざっくりとした説明です。これらを踏まえて、さっそく①から実装していきましょう!

壁(Wall)とコマ(KOMA1)をつくる

今回使うUnityは2017.4.15f1です。2019.4月現在VRChatで推奨されているものですね。
そこまで複雑な機能は使ってない(はず)ので他のバージョンでもできると思います。

①背景となる壁(Wall)をつくる

ではUnityで新規Projectを作成したらHierarchy(Main CameraとかDirectional Lightとかあるところ)で右クリックして「3D Object」から「Cube」を選択。
これでScene内にオブジェクトが出現します。Cubeの名前を「Wall」に変更しましょう。

HierarchyProjectInspectorは頻出語!絶対覚えてください(記事中では斜体で表示します)

HierarchyのWallを選択するとInspectorに様々な情報が出てきます。
最上段のTransformはオブジェクトの変形や位置を設定できます。
では、WallのTranceFormの設定を以下のように入力してください。

これだけでベースの壁が完成。見やすいようにカメラの位置を調整しよう。

 

次にWallに適用する「Material」と「Shader」を作成します。
この2つはオブジェクトの見え方を決めるもので、これから作成する全てのオブジェクトにこの2つを設定していくことになります。

Projectの上で右クリック⇒Create⇒Folderを作成し、名前を「Wall」にします。
フォルダ内に入り、次はCreateでMaterialを作成し名前を「Wall」にします。
さらにCreate⇒Shader⇒Standard Surface Shaderを作成、名前を「Wall」にします。

次にShadarの中身を書き換えますが、開いてみると中身は難しい言語で書かれています。
なので、全部消してとりあえず以下をコピペしてください。意味はわからなくて大丈夫です。

Shader "Custom/Wall" {
	Properties {
		_Mask ("Mask", Int) = 100
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
		_Glossiness ("Smoothness", Range(0,1)) = 0.5
		_Metallic ("Metallic", Range(0,1)) = 0.0
	}
	SubShader {
		Tags
		{
			"RenderType"="Opaque"
			"Queue" = "Geometry-2"
		}
		LOD 200

		Stencil 
		{
			Ref [_Mask]
			Comp NotEqual
		}

		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
		// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
		// #pragma instancing_options assumeuniformscaling
		UNITY_INSTANCING_BUFFER_START(Props)
			// put more per-instance properties here
		UNITY_INSTANCING_BUFFER_END(Props)

		void surf (Input IN, inout SurfaceOutputStandard o) {
			// Albedo comes from a texture tinted by color
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			// Metallic and smoothness come from slider variables
			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

それでは作成したMaterialとShaderをHierarchyのWallに適用します。

まずMaterial「Wall」をドラッグしてHierarchyのWallにドロップ。
HierarchyのWallをクリックしてInspectorの最下段を見るとMaterialの「Wall」が表示されています。
ShaderがStandardになっているので、これをクリックしてCustom⇒Wallを選択しましょう。
これでMaterialとShaderが適用されました。

ついでに壁の色を変えてみましょう。
下の図を参考に、Shaderの設定からColorを変更します。

HierarchyのWallを選択。InspectorからShaderの設定を変更できる

以上で壁の設置は完了です。

②Wallを透過するコマをつくる

Hierarchyで何もないところをクリックし、何も選択していない状態で右クリック⇒「Create Empty」をクリックしてください。
「GameObject」ができるので名前を「KOMA1」と変更してください。この時InspectorのTranceformを見て、Positionを(0,0,0)にしておきます。

次にKOMA1を選択した状態で再び右クリックから3D Object内の「Quad」をクリック。

このQuadがコマになるので、枠を最初に作っておきます。
KOMA1を選択し直して、3D ObjectのCubeを作成。Inspectorの最上部にあるTransformを以下のように設定してください。

次に、Projectで右クリック⇒Create⇒Materialを作成。名前をFrameに変更してください。
FrameをHierarchyのCubeにドラッグ&ドロップ。
Cubeを選択してInspector最下段に表示されたFrameからShaderをUnlit/Colorに変更しましょう。
Main Colorから先ほどと同様に色を変更できるので、今回は黒を選択してください。

Shaderの効果でMaterialが黒くなったことで、適用されたCubeが黒くなる

これでコマの一辺ができたので複製(Ctrl+D)して4辺を埋めます。
まずCubeを「Frame」と名前を変更し、選択したまま3回複製。各InspectorのTransformを以下のように設定してください。

これでコマ枠ができました。
次にQuadの設定をやっていきましょう。
まず、Quadは「Wall_KOMA」と名前を変更します。

ProjectのFolder「Wall」内で、再びMaterialとShaderを作成。名前はどちらも「Wall_KOMA」にします。
Shader「Wall_KOMA」の中身は以下をコピペ。

Shader "Custom/Wall_KOMA"
{
	Properties
	{
		_Mask ("Mask", Int) = 100
	}

	SubShader
	{

		Tags 
		{ 
			"RenderType" = "Opaque" 
			"Queue" = "Geometry-3"
		}

		CGINCLUDE

		#include "UnityCG.cginc"

		struct v2f
		{
			float4 vertex : SV_POSITION;
			UNITY_VERTEX_OUTPUT_STEREO
		};

		v2f vert(appdata_base v)
		{
			v2f o;
			UNITY_SETUP_INSTANCE_ID(v);
			UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
			o.vertex = UnityObjectToClipPos(v.vertex);
			return o;
		}

		fixed4 frag (v2f i) : SV_Target
		{
			return 0;
		}

		ENDCG

		Pass
		{
			ColorMask 0
			ZWrite Off
			Stencil 
			{
				Ref [_Mask]
				Comp Always
				Pass Replace
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			ENDCG
		}

	}

}

作成したMaterial「Wall_KOMA」をHierarchyのWall_KOMAにD&D。InspectorからShader「Wall_KOMA」を選択。
すると白かったコマが透明になり、カメラの向きを調整して壁に向けると、透過することが確認できるはずです。

枠の中が透明になっている。実験は成功だ!

それでは次に、透過した場所に「漫画世界の壁」を出現させましょう。

覗くと漫画世界が見えるコマを完成させる

③ コマ内だけで表示される漫画化した壁(ComicWall)をつくる

Wallと全く同じ形のものを複製し、まずはコマの中だけで表示させるような設定をしていきます。
とは言ってもやることは同じで、MaterialとShaderを作成して適用するだけです。

それではスピードアップしていきましょう。

まずHierarchyのWallを選択し複製(Ctrl+D)。名前を「ComicWall」にします。

Wallと全く同じ形にすることで、裏世界を覗いたような表現になるのだ

Projectに素材を作っていきますが、同じ場所に作っていくと煩雑になってくるので、一旦Assetsに戻ってFolder「ComicWall」を作りましょう。

整理整頓もスムーズな制作には欠かせないポイントだ

ではフォルダ内でMaterial「ComicWall」とShader「ComicWall」を作成。
Shader「ComicWall」は以下をコピペ。
Shader "Custom/ComicWall" {
	Properties
	{
		_Mask ("Mask", Int) = 100
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags
		{
			"RenderType"="Opaque"
			"Queue" = "Geometry-2"	
		}
		LOD 100

		Stencil 
		{
			Ref [_Mask]
			Comp Equal
		}

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

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

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed4 col = tex2D(_MainTex, i.uv);
				// apply fog
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}

作成したMaterialとShaderをHierarchyのComicWallに適用。
するとコマの中だけが白く表示されるようになりました。

まだ漫画っぽくはない

壁を漫画風にする

ここで、この壁を漫画風にするためにTextureを使用します。
Textureとは、画像ファイルを使ってObjectの表面に模様をつけるものです。

漫画風のTextureを用意したので、PCのどこかに画像として保存してください。
保存した画像ファイルをUnityのProject内にドラッグ&ドロップしてください。Projectに追加されます。

フリー素材です。自由に使ってください。

HierarchyのComicWallを選択し、InspectorからMaterial「CW」をクリックして展開してください。
None(Texture)と書いてあるグレーの四角があるので、その中にProjectから画像ファイルをドラッグ&ドロップしてください。

すると枠内の背景に画像ファイルが適用され、コマの中がいよいよ漫画世界になってきました!
それでは次は、漫画世界に球体(ComicObject1)を配置していきましょう。

コマの中だけに描写されるObjectをつくる

④ 漫画の球体(ComicObject1)を映すためのコマを、②に重ねてつくる

まずは2枚目のコマをつくるためにHierarchyのWall_KOMAを複製(Ctrl+D)。名前を「ComicObject_KOMA」とします。

まずはProjectのAssetsにFolder「ComicObject」を作成。
ComicObjectの中でMaterial「CO_KOMA1」とShader「ComicObject_KOMA」と名前変更。
HierarchyのComicObject_KOMAにD&D。

さらにComicObjectの中で今度はShader⇒Standard Surfece Shaderを作成し「ComicObject_KOMA」と名前変更。
シェーダーは以下をコピペ。

Shader "Custom/ComicObject_KOMA"
{
	Properties
	{
		_Mask ("Mask", Int) = 1
	}

	SubShader
	{

		Tags 
		{ 
			"RenderType" = "Opaque" 
		"Queue" = "Geometry-1"
		}

		CGINCLUDE

		#include "UnityCG.cginc"

		struct v2f
		{
			float4 vertex : SV_POSITION;
			UNITY_VERTEX_OUTPUT_STEREO
		};

		v2f vert(appdata_base v)
		{
			v2f o;
			UNITY_SETUP_INSTANCE_ID(v);
			UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
			o.vertex = UnityObjectToClipPos(v.vertex);
			return o;
		}

		fixed4 frag (v2f i) : SV_Target
		{
			return 0;
		}

		ENDCG

		Pass
		{
			ColorMask 0
			ZWrite Off
			Stencil 
			{
				Ref [_Mask]
				Comp Always
				Pass Replace
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			ENDCG
		}

	}

}

ComicObject_KOMAにMaterial「CO_KOMA1」をD&D。Shaderを「ComicObject_KOMA」に変更します。
ComicObject用のコマの設定はこれでおわりです。

⑤ コマ内だけで表示されるComicObject1をつくる

Hierarchyの何もないところをクリックし何も選択されていない状態でSphereを作成、名前は「ComicObject1」にします。
ComicObjectのInspectorでTransform⇒Positionを(x,y,z)=(0,0,3)にしてKOMA1の正面にくるようにしましょう。

それではComicObjectのためのMaterialとShaderを作成します。Materialは「CO1」、Shaderは「ComicObject」という名前にします。
Shaderは以下をコピペ。

Shader "Custom/ComicObject"
{
	Properties
	{
		_Mask ("Mask", Int) = 1
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Stencil 
		{
			Ref [_Mask]
			Comp Equal
		}

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

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

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture
				fixed4 col = tex2D(_MainTex, i.uv);
				// apply fog
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}

例によってComicObjectにMaterialとShaderを適用していきます。

こうなっていたら成功。うまくいかなかったらInspectorを見直して、適用しているShaderが間違っていないか確認していこう。

これでコマひとつ目の設定は全て終了!
それでは最後に、コマをもう一つ増やしてみましょう。

2つ目のコマをつくる

⑥ コマを複製して2つにする

⑦ 複製したコマだけで表示されるComicObject2をつくる

コマをもう一つ用意し、それぞれ違う球体が見えるようにします。

まずHierarchyのKOMA1を選択し複製(Ctrl+D)。KOMA2と名前を変更します。
このままではKOMA1と重なっているので、KOMA2のInspectorからPositionのXを-1.1にしてください。

さらにHierarchyのComicObject1を選択し複製(Ctrl+D)。ComicObject2と名前を変更します。
このままではComicObject1と重なっているので、ComicObject2のInspectorからPositionのXを-1.1にしてください。

コマと球はふたつになったがどちらのコマも同じ2つの球が見える

次にProjectのFolder「ComicObject」の中にあるMaterial「CO1」「CO1_KOMA」を複製して、「CO2」「CO2_KOMA」を作ってください。

 

次が重要な操作です。
作成したCO2、CO2_KOMAのInspectorでMaskを2に変更してください。

Project上でもInspectorを修正することができる

 

作成したMaterial「CO2」をHierarchyのComicObject2に、Material「CO2_KOMA」をHierarchyKOMA2内の「ComicObject_KOMA」に適用してください。

Maskという値がコマとオブジェクトで一致している時のみ描写されるようになる、という仕組みになっています。
さらにコマを増やしたらさらにCOとCO_KOMAのMaterialを作ってMASKを3、4、5…としていけば同様の効果になります。

改めてWall・ComicWallのInspectorを見てもらうと分かると思いますが、そちらには100が設定されています。
WallとObjectを別のMASK値で管理することで、コマ同士でComicWallの描写を共有しながら、Objectだけを入れ替えていくことができます。
(逆にそうしないとコマごとに背景も複製することになるので、2枚重ねにすることで素材の配置を押さえることができます)

※ちなみにコマを1つしか運用しない(複数のコマを使用しない)想定であれば、WALL・ComicWallもComicObjectと同じMASK値でよくなります。
 コマを2枚重ねにする必要はありませんので用途によって使い分けてください。

 

最後に、球体が真っ白だと味気ないので、ComicObjectのtextureを適当に変えましょう。
以上で完成です。忘れずにFileからSave Seaneをしておきましょう。

お疲れさまでした!!!

ちなみにComicObjectのShaderはUnlit Shaderをベースに作成している

最後に

今回はShaderを用意しましたが、実際は色々なCustom Shaderを使いたい時があると思います。
KOMA側のShaderは変える必要はないですが、背景やObject側のShaderを変えるときは…

【Wall】

◇Propertiesの中に
_Mask ("Mask", Int) = 100

◇SubShaderの中のTagsの中に
"Queue" = "Geometry-2"

◇CGPROGRAM(または Pass{CGPROGRAM )の直前に
Stencil {Ref [_Mask] Comp NotEqual}

【ComicWall】

◇Propertiesの中に
_Mask ("Mask", Int) = 100

◇SubShaderの中のTagsの中に
"Queue" = "Geometry-2"

◇CGPROGRAM(または Pass{CGPROGRAM )の直前に
Stencil{Ref [_Mask] Comp Equal}

【ComicObject】

◇Propertiesの中に
_Mask ("Mask", Int) = 1

◇CGPROGRAM(または Pass{CGPROGRAM )の直前に
Stencil{Ref [_Mask] Comp Equal}

を記載してください。
CGPROGRAMが複数ある場合はその全ての直前にStencilを書いてください。

また、【Wall】【ComicWall】はAlphaTestやTransparentのShaderに適用するのは難しいです。
(【Wall】系はQueueを指定しているが、TransparentなどはQueueの値が決まっているため)
その他Custom ShaderでQueueの値を指定しているものやステンシルバッファ値を書き換えるものとは相性が悪い可能性があります。
その場合はQueueの値をずらすことで使用できる可能性があります。がんばって調べてください!!

大変長くなりましたが、コマで漫画世界を覗くやり方の説明でした。
漫画世界の表現については、今回はテクスチャを使用しましたが動画ではシェーダーを使用しています。
「漫画 シェーダー」などで検索して、気になるものがあったら上記の方法で設定して試してみてください!

以上、小江華あきでした。おつかれさまでした!