summaryrefslogtreecommitdiff
path: root/Assets/Art/Shaders/UnityChan/CharaMain.cginc
blob: fcb5530fbdef6dc1eee091d3e31e0ac62e0eda8d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

// Character shader
// Includes falloff shadow and highlight, specular, reflection, and normal mapping

#define ENABLE_CAST_SHADOWS

// Material parameters
float4 _Color;
float4 _ShadowColor;
float4 _LightColor0;
float _SpecularPower;

float4 _MainTex_ST;

// Textures
sampler2D _MainTex;
sampler2D _FalloffSampler;
sampler2D _RimLightSampler;
sampler2D _SpecularReflectionSampler;
sampler2D _EnvMapSampler;
sampler2D _NormalMapSampler;

// Constants
#define FALLOFF_POWER 0.3

// Float types
#define float_t    half
#define float2_t   half2
#define float3_t   half3
#define float4_t   half4
#define float3x3_t half3x3

#ifdef ENABLE_CAST_SHADOWS

// Structure from vertex shader to fragment shader
struct v2f
{
	float4 pos      : SV_POSITION;
	LIGHTING_COORDS( 0, 1 )
	float2 uv       : TEXCOORD2;
	float3 eyeDir   : TEXCOORD3;
	float3 lightDir : TEXCOORD4;
	float3 normal   : TEXCOORD5;
	#ifdef ENABLE_NORMAL_MAP
		float3 tangent  : TEXCOORD6;
		float3 binormal : TEXCOORD7;
	#endif
};

#else

// Structure from vertex shader to fragment shader
struct v2f
{
	float4 pos      : SV_POSITION;
	float2 uv       : TEXCOORD0;
	float3 eyeDir   : TEXCOORD1;
	float3 lightDir : TEXCOORD2;
	float3 normal   : TEXCOORD3;
	#ifdef ENABLE_NORMAL_MAP
		float3 tangent  : TEXCOORD4;
		float3 binormal : TEXCOORD5;
	#endif
};

#endif

// Vertex shader
v2f vert( appdata_tan v )
{
	v2f o;
	o.pos = UnityObjectToClipPos( v.vertex );
	o.uv.xy = TRANSFORM_TEX( v.texcoord.xy, _MainTex );	
	o.normal = normalize( mul( unity_ObjectToWorld, float4_t( v.normal, 0 ) ).xyz );
	
	// Eye direction vector
	float4 worldPos = mul( unity_ObjectToWorld, v.vertex );
	o.eyeDir.xyz = normalize( _WorldSpaceCameraPos.xyz - worldPos.xyz ).xyz;
	o.lightDir = WorldSpaceLightDir( v.vertex );
	
	#ifdef ENABLE_NORMAL_MAP	
		// Binormal and tangent (for normal map)
		o.tangent = normalize( mul( unity_ObjectToWorld, float4_t( v.tangent.xyz, 0 ) ).xyz );
		o.binormal = normalize( cross( o.normal, o.tangent ) * v.tangent.w );
	#endif

	#ifdef ENABLE_CAST_SHADOWS
		TRANSFER_VERTEX_TO_FRAGMENT( o );
	#endif

	return o;
}

// Overlay blend
inline float3_t GetOverlayColor( float3_t inUpper, float3_t inLower )
{
	float3_t oneMinusLower = float3_t( 1.0, 1.0, 1.0 ) - inLower;
	float3_t valUnit = 2.0 * oneMinusLower;
	float3_t minValue = 2.0 * inLower - float3_t( 1.0, 1.0, 1.0 );
	float3_t greaterResult = inUpper * valUnit + minValue;

	float3_t lowerResult = 2.0 * inLower * inUpper;

	half3 lerpVals = round(inLower);
	return lerp(lowerResult, greaterResult, lerpVals);
}

#ifdef ENABLE_NORMAL_MAP

	// Compute normal from normal map
	inline float3_t GetNormalFromMap( v2f input )
	{
		float3_t normalVec = tex2D( _NormalMapSampler, input.uv ).xyz * 2 - 1;

		// Fix for Metal graphics API
		float3_t xBasis = float3_t( input.tangent.x, input.binormal.x, input.normal.x );
		float3_t yBasis = float3_t( input.tangent.y, input.binormal.y, input.normal.y );
		float3_t zBasis = float3_t( input.tangent.z, input.binormal.z, input.normal.z );

		normalVec = float3_t(
			dot( normalVec, xBasis ),
			dot( normalVec, yBasis ),
			dot( normalVec, zBasis )
		);
		normalVec = normalize( normalVec );
		
		return normalVec;
	}

#endif

// Fragment shader
float4 frag( v2f i ) : COLOR
{
	float4_t diffSamplerColor = tex2D( _MainTex, i.uv.xy );

	#ifdef ENABLE_NORMAL_MAP
		float3_t normalVec = GetNormalFromMap( i );
	#else
		float3_t normalVec = i.normal;
	#endif

	// Falloff. Convert the angle between the normal and the camera direction into a lookup for the gradient
	float_t normalDotEye = dot( normalVec, i.eyeDir.xyz );
	float_t falloffU = clamp( 1.0 - abs( normalDotEye ), 0.02, 0.98 );
	float4_t falloffSamplerColor = FALLOFF_POWER * tex2D( _FalloffSampler, float2( falloffU, 0.25f ) );
	float3_t shadowColor = diffSamplerColor.rgb * diffSamplerColor.rgb;
	float3_t combinedColor = lerp( diffSamplerColor.rgb, shadowColor, falloffSamplerColor.r );
	combinedColor *= ( 1.0 + falloffSamplerColor.rgb * falloffSamplerColor.a );

	// Specular
	// Use the eye vector as the light vector
	float4_t reflectionMaskColor = tex2D( _SpecularReflectionSampler, i.uv.xy );
	float_t specularDot = dot( normalVec, i.eyeDir.xyz );
	float4_t lighting = lit( normalDotEye, specularDot, _SpecularPower );
	float3_t specularColor = saturate( lighting.z ) * reflectionMaskColor.rgb * diffSamplerColor.rgb;
	combinedColor += specularColor;
	
	// Reflection
	float3_t reflectVector = reflect( -i.eyeDir.xyz, normalVec ).xzy;
	float2_t sphereMapCoords = 0.5 * ( float2_t( 1.0, 1.0 ) + reflectVector.xy );
	float3_t reflectColor = tex2D( _EnvMapSampler, sphereMapCoords ).rgb;
	reflectColor = GetOverlayColor( reflectColor, combinedColor );

	combinedColor = lerp( combinedColor, reflectColor, reflectionMaskColor.a );
	combinedColor *= _Color.rgb * _LightColor0.rgb;
	float opacity = diffSamplerColor.a * _Color.a * _LightColor0.a;

	#ifdef ENABLE_CAST_SHADOWS
		// Cast shadows
		shadowColor = _ShadowColor.rgb * combinedColor;
		float_t attenuation = saturate( 2.0 * LIGHT_ATTENUATION( i ) - 1.0 );
		combinedColor = lerp( shadowColor, combinedColor, attenuation );
	#endif

	// Rimlight
	float_t rimlightDot = saturate( 0.5 * ( dot( normalVec, i.lightDir ) + 1.0 ) );
	falloffU = saturate( rimlightDot * falloffU );
	falloffU = tex2D( _RimLightSampler, float2( falloffU, 0.25f ) ).r;
	float3_t lightColor = diffSamplerColor.rgb; // * 2.0;
	combinedColor += falloffU * lightColor;

	return float4( combinedColor, opacity );
}