【Unity】せっかくなのでプロジェクターでノーマルマップを投影してみた【Shader】
2020年2月2日
ノーマルマップの仕組みもわかったので、プロジェクターで投影したらどうなるか試してみました。
このような感じになりました。なんか違う。
深度バッファを書き換えてるのではなく、白気味でブレンドしているだけなので想像とは違うものになってしまった。
これはこれでなにかに使えるかもしれない。
プロジェクターのシェーダーコードになります。
Shader "Neko/Projector"
{
Properties
{
[Normal]_NormalMap("Normal Map", 2D) = "bump" {}
}//Properties
SubShader
{
Pass
{
Tags
{
"RenderType" = "Opaque"
"Queue" = "Transparent"
}
Blend OneMinusDstColor One // スクリーン / 比較(明)
// Blend Zero SrcColor // 乗算
// Blend One One // 加算
// Blend OneMinusDstColor Zero // 反転
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 uv : TEXCOORD0;
float4 frustum : TEXCOORD1; // left right
float depth : TEXCOORD2; // near far
float3 lightDir : TEXCOORD3;
float3 viewDir : TEXCOORD4;
};
float4x4 unity_Projector;
float4x4 unity_ProjectorClip;
sampler2D _NormalMap;
float4 _NormalMap_ST;
float4 _NormalMap_TexelSize;
v2f vert( appdata v)
{
v2f o = (v2f)0;
o.vertex = UnityObjectToClipPos( v.vertex);
o.uv = mul( unity_Projector, v.vertex);
o.frustum = mul( unity_Projector, mul( UNITY_MATRIX_M, v.vertex));
o.depth = mul( unity_ProjectorClip, v.vertex);
float3 n = normalize( v.normal);
float3 t = normalize( v.tangent.xyz);
float3 b = cross( n, t) * v.tangent.w;
float3x3 invM = float3x3( t, b, n);
o.lightDir = mul( invM, ObjSpaceLightDir( v.vertex));
o.viewDir = mul( invM, ObjSpaceViewDir( v.vertex));
return o;
}
sampler2D _MainTex;
fixed4 frag( v2f i) : SV_Target
{
// フラスタム カリング
// left right top bottom チェック
clip( 1-abs( (i.frustum.xy / i.frustum.w)*2-1));
// near far チェック
clip( 1-abs( i.depth*2-1));
// テクスチャ外だったらカリング
clip( 1-abs( (i.uv.xy / i.frustum.w)*2-1));
float3 L = normalize( i.lightDir);
float3 V = normalize( i.viewDir);
float3 halfDir = normalize( L + V);
float3 N = UnpackNormal( tex2Dproj( _NormalMap, i.uv));
float3 diff = saturate( dot( N, L))/10;
float spec = pow( max( 0, dot( N, halfDir)), 10);
float3 color = diff + spec;
return float4( color, 1);
}
ENDCG
} // Pass
}//SubShader
}//Shader
ピクセルシェーダーのカリング周りがだいぶシンプルになりました。
i.frustum.xy / i.frustum.w
この部分で 視錐台 の 幅と高さを算出して 0~1 の範囲外だと 台の外になります。
clip() で一度に ピクセルの破棄をしたいため 2倍して1を引いた値の 絶対値 が 0と1の範囲外であるかどうかをチェックしています。
unity_ProjectorClip は Near Far の計算に利用でき 0から1の範囲外であれば 破棄しています。
あとはライトをブレンドしているだけです。
もう少し凸凹感が出るかと思ったけど、要調整ですね。
加算でなく減算すれば凹んだ感じになるかな?
関連記事
One Comment