kenoです。
皆さんご存知でしょうか。見る角度によって違う絵がみえるカードとか。
あれレンチキュラーっていうらしいですね。
面白いのでUnityのShaderでつくってみました!
レンチキュラーの作り方
最近勉強してるんですよ。Shaderってやつを。
Shader Graphの方じゃなくてコードで書くshaderです。
基本的な構造は「Vertex Shader(頂点シェーダー)」と「Fragment Shader(画素のシェーダー)」によって成り立っています。
UnityのProject画面から「Create→Shader→Unlit Shader」でシェーダーを作成します。
名前は「LenticularShader」にしましょう。
そしたら、そのシェーダーを開いて中身を以下のように書き換えてください。
Shader "Unlit/LenticularShader"
{
Properties
{
_MainTex1 ("Texture1", 2D) = "white" {}
_MainTex2 ("Texture2", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
half3 normal : TEXCOORD1;
float4 worldPos : WORLD_POS;
};
sampler2D _MainTex1;
sampler2D _MainTex2;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.normal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
float3 camToMe = _WorldSpaceCameraPos - i.worldPos;
fixed val = dot(normalize(camToMe),i.normal);
//内積により2ベクトルが完全一致なら1で90°なら0になる
fixed4 col = lerp(tex2D(_MainTex1,i.uv),tex2D(_MainTex2,i.uv),val);
return col;
}
ENDCG
}
}
}
では、Unityのヒエラルキーで「Create→3D Object → Quad」で板を作成しましょう。
次に先程のshaderを右クリックで「Create→Material」でこのシェーダーのマテリアルを作成します。そしたらそのマテリアルをQuadにアタッチ!
マテリアルを見てみると2種類のSpriteを登録することが出来るところがあると思います。ここではcopilot君につくってもらった猫と犬の画像を登録します。↓
これでレンチキュラーができると思いますね。Playボタンを押さなくても実際にカメラで横から見たり真正面から見たりして角度を変えればぽくなってるのがわかると思います。できた!
仕組み
中でやってることとしては、アプリケーション側から渡されるデータである(じつはよくわかってない)appdataから法線情報(normal)を取得し、vertexからfragmentに渡される情報の塊であるv2fで法線情報とワールド座標の変数を取得します。
そして、Quadの法線とQuadからカメラへのベクトルを内積して値を算出してます。内積の値が1ならおんなじ方向(真正面)だし、0に近いならベクトルが90°に近いということ。
あとは2種類の画像情報をlerpでなんとなく入れかえちゃえば完成です。
(いろいろシェーダーの勉強してる跡がのこっちゃってる!すみません!)