// 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 #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 // Float types #define float_t half #define float2_t half2 #define float3_t half3 #define float4_t half4 #define float3x3_t half3x3 // 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 half4 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 = normalize( tex2D( _NormalMapSampler, input.uv ).xyz * 2.0 - 1.0 ); float3x3_t localToWorldTranspose = float3x3_t( input.tangent, input.binormal, input.normal ); normalVec = normalize( mul( normalVec, localToWorldTranspose ) ); 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 ); }