概要
前回、Shader Forgeを使用してMatCapシェーダーを作成した。
http://qiita.com/akerusoft/items/d58416d608cb3c76c153
しかしピクセルシェーダー内の処理が少し重く感じたので
同じノードベースシェーダーエディターのASEを使用してMatCapシェーダーを作成し違いがあるのか確認する。
環境
Unity 5.5.2p4
Amplify Shader Editor v1.2.1 dev 01
(バージョンをどこでみればいいかわからなかったのでChangeLogより)
実装内容
前回同様にFree MatCap ShadersのアセットをMatCapの基準とする。
https://www.assetstore.unity3d.com/jp/#!/content/8221
このアセットの「MatCap/Vertex/Plain」と同じ見た目になるように実装する。
実装内容
処理内容はShader Forgeと同じ。
実行結果
左から「MatCap/Vertex/Plain」のもの、Shader ForgeでのMatCapシェーダー、ASEでのMatCapシェーダー。
自動生成されたコード
Shader "ASEMatCap"
{
Properties
{
[HideInInspector] __dirty( "", Int ) = 1
_MatCap("MatCap", 2D) = "white" {}
}
SubShader
{
Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+0" "IsEmissive" = "true" }
Cull Back
CGINCLUDE
#include "UnityShaderVariables.cginc"
#include "UnityPBSLighting.cginc"
#include "Lighting.cginc"
#pragma target 2.0
#ifdef UNITY_PASS_SHADOWCASTER
#undef INTERNAL_DATA
#undef WorldReflectionVector
#undef WorldNormalVector
#define INTERNAL_DATA half3 internalSurfaceTtoW0; half3 internalSurfaceTtoW1; half3 internalSurfaceTtoW2;
#define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.internalSurfaceTtoW0,normal), dot(data.internalSurfaceTtoW1,normal), dot(data.internalSurfaceTtoW2,normal)))
#define WorldNormalVector(data,normal) fixed3(dot(data.internalSurfaceTtoW0,normal), dot(data.internalSurfaceTtoW1,normal), dot(data.internalSurfaceTtoW2,normal))
#endif
struct Input
{
float3 worldNormal;
};
uniform sampler2D _MatCap;
void surf( Input i , inout SurfaceOutputStandard o )
{
float2 componentMask6 = mul( UNITY_MATRIX_V , float4( i.worldNormal , 0.0 ) ).xy;
o.Emission = tex2D( _MatCap, ( 0.5 + ( 0.5 * componentMask6 ) ) ).rgb;
o.Alpha = 1;
}
ENDCG
CGPROGRAM
#pragma surface surf Standard keepalpha fullforwardshadows exclude_path:deferred
ENDCG
Pass
{
Name "ShadowCaster"
Tags{ "LightMode" = "ShadowCaster" }
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#pragma multi_compile_shadowcaster
#pragma multi_compile UNITY_PASS_SHADOWCASTER
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
# include "HLSLSupport.cginc"
#if ( SHADER_API_D3D11 || SHADER_API_GLCORE || SHADER_API_GLES3 || SHADER_API_METAL || SHADER_API_VULKAN )
#define CAN_SKIP_VPOS
#endif
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
sampler3D _DitherMaskLOD;
struct v2f
{
V2F_SHADOW_CASTER;
float3 worldPos : TEXCOORD6;
float4 tSpace0 : TEXCOORD1;
float4 tSpace1 : TEXCOORD2;
float4 tSpace2 : TEXCOORD3;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
v2f vert( appdata_full v )
{
v2f o;
UNITY_SETUP_INSTANCE_ID( v );
UNITY_INITIALIZE_OUTPUT( v2f, o );
UNITY_TRANSFER_INSTANCE_ID( v, o );
float3 worldPos = mul( unity_ObjectToWorld, v.vertex ).xyz;
half3 worldNormal = UnityObjectToWorldNormal( v.normal );
o.worldPos = worldPos;
TRANSFER_SHADOW_CASTER_NORMALOFFSET( o )
return o;
}
fixed4 frag( v2f IN
#if !defined( CAN_SKIP_VPOS )
, UNITY_VPOS_TYPE vpos : VPOS
#endif
) : SV_Target
{
UNITY_SETUP_INSTANCE_ID( IN );
Input surfIN;
UNITY_INITIALIZE_OUTPUT( Input, surfIN );
float3 worldPos = IN.worldPos;
fixed3 worldViewDir = normalize( UnityWorldSpaceViewDir( worldPos ) );
surfIN.worldNormal = float3( IN.tSpace0.z, IN.tSpace1.z, IN.tSpace2.z );
SurfaceOutputStandard o;
UNITY_INITIALIZE_OUTPUT( SurfaceOutputStandard, o )
surf( surfIN, o );
#if defined( CAN_SKIP_VPOS )
float2 vpos = IN.pos;
#endif
SHADOW_CASTER_FRAGMENT( IN )
}
ENDCG
}
}
Fallback "Diffuse"
CustomEditor "ASEMaterialInspector"
}
ピクセルシェーダー内からサーフェースシェーダー関数を呼んでいるので結果として
Shader Forgeと同じでピクセルシェーダー内で計算処理してますね。
早いシェーダーを書きたいなら手書きで書け、ということでしょうか。
感想
Shader Forgeになれているので、ASEの操作感はいまいち。
細かい設定はASEの方ができる感じがしてますが、どっちがどうなんでしょうね?