So, I have been experimenting with animated wrinkle maps from the blacksmith demo. The example given along with black smith demo is in a custom surface shader. I want to replicate the same in a fragment shader. I have coded a very basic Normal Map shader and incorporated the normal map lines from the surface shader and made some adjustments.
This is what I have understood from the surface shader code. The _NormalAndOcclusion is being written to from in screenspace buffer and is being handled by a different shader and script. I output the normal map themselves as color from the fragment shader to visualize. Here are the screen shots
Fragment Shader Test Failed(The normals are in world space? Not sure)
Blacksmith surface shader with normal as Albedo output from surface shader.
Here is surface shader given by unity in blacksmith the demo. Line number 128 onwards is where the wrinkle map part is.
Shader "Volund/Standard Character (Specular, Surface)" {
Properties {
_Color("Color", Color) = (1,1,1,1)
_MainTex("Albedo", 2D) = "white" {}
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
_Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
_SpecColor("Specular", Color) = (0.2,0.2,0.2)
_SpecGlossMap("Specular", 2D) = "white" {}
_BumpScale("Scale", Float) = 1.0
_BumpMap("Normal Map", 2D) = "bump" {}
_Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02
_ParallaxMap ("Height Map", 2D) = "black" {}
_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
_OcclusionMap("Occlusion", 2D) = "white" {}
_EmissionColor("Color", Color) = (0,0,0)
_EmissionMap("Emission", 2D) = "white" {}
_DetailMask("Detail Mask", 2D) = "white" {}
_DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
_DetailNormalMapScale("Scale", Float) = 1.0
_DetailNormalMap("Normal Map", 2D) = "bump" {}
[Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0
// Blending state
[HideInInspector] _Mode ("__mode", Float) = 0.0
[HideInInspector] _SrcBlend ("__src", Float) = 1.0
[HideInInspector] _DstBlend ("__dst", Float) = 0.0
[HideInInspector] _ZWrite ("__zw", Float) = 1.0
// Volund properties
[HideInInspector] _CullMode ("__cullmode", Float) = 2.0
[HideInInspector] _SmoothnessInAlbedo ("__smoothnessinalbedo", Float) = 0.0
[HideInInspector] _SmoothnessTweaks ("__smoothnesstweaks", Vector) = (1,0,0,0)
_SmoothnessTweak1("Smoothness Scale", Range(0.0, 2.0)) = 1.0
_SmoothnessTweak2("Smoothness Bias", Range(-1.0, 1.0)) = 0.0
_SpecularMapColorTweak("Specular Color Tweak", Color) = (1,1,1,1)
}
SubShader {
Tags { "RenderType"="Opaque" "Special"="Wrinkles" "PerformanceChecks"="False" }
LOD 300
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]
Cull [_CullMode]
CGPROGRAM
// - Physically based Standard lighting model, specular workflow
// - 'fullforwardshadows' to enable shadows on all light types
// - 'addshadow' to ensure alpha test works for depth/shadow passes
// - 'keepalpha' to allow alpha blended output options
// - 'interpolateview' because that's what the non-surface Standard does
// - Custom vertex function to setup detail UVs as expected by Standard shader
// - Custom finalcolor function to output controlled final alpha
// - 'nolightmap' and 'nometa' since this shader is only for dynamic objects
// - 'exclude_path:prepass' since we have no use for this legacy path
#pragma surface SurfSpecular StandardSpecular fullforwardshadows addshadow keepalpha interpolateview vertex:StandardSurfaceVertex finalcolor:StandardSurfaceSpecularFinal nolightmap nometa exclude_path:deferred exclude_path:prepass
// Use shader model 3.0 target, to get nicer looking lighting (PBS toggles internally on shader model)
#pragma target 3.0
// This shader probably works fine for console/mobile platforms as well, but
// these are the ones we've actually tested.
#pragma only_renderers d3d11 d3d9 opengl glcore
// Standard shader feature variants
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _SPECGLOSSMAP
#pragma shader_feature _DETAIL_MULX2
// Standard, but unused in this project
//#pragma shader_feature _EMISSION
//#pragma shader_feature _PARALLAXMAP
// Volund additional variants
#pragma multi_compile _ WRINKLE_MAPS
#pragma multi_compile UNITY_SAMPLE_FULL_SH_PER_PIXEL
// Volund uniforms
uniform sampler2D _NormalAndOcclusion;
uniform half3 _SpecularMapColorTweak;
uniform half2 _SmoothnessTweaks;
// Need screen pos if wrinkle maps are active
#ifdef WRINKLE_MAPS
struct SurfaceInput {
float4 texcoord;
#ifdef _PARALLAXMAP
half3 viewDir;
#endif
float4 screenPos;
};
#define Input SurfaceInput
#endif
// Include all the Standard shader surface helpers
#include "UnityStandardSurface.cginc"
// Our main surface entry point
void SurfSpecular(Input IN, inout SurfaceOutputStandardSpecular o)
{
StandardSurfaceSpecular(IN, o);
// Apply specular color tweak if we sampled spec color from a texture
#ifdef _SPECGLOSSMAP
o.Specular *= _SpecularMapColorTweak;
#endif
// Optionally sample smoothness from albedo texture alpha channel instead of sg texture
#ifdef SMOOTHNESS_IN_ALBEDO
o.Smoothness = tex2D(_MainTex, IN.texcoord.xy).a;
#endif
// Apply smoothness scale and bias (always active)
o.Smoothness = saturate(o.Smoothness * _SmoothnessTweaks.x + _SmoothnessTweaks.y);
// Sample occlusion and normals from screen-space buffer when wrinkle maps are active
#ifdef WRINKLE_MAPS
float3 normalOcclusion = tex2D(_NormalAndOcclusion, IN.screenPos.xy / IN.screenPos.w).rgb;
o.Occlusion = normalOcclusion.r;
#ifdef _NORMALMAP
o.Normal.xy = normalOcclusion.gb * 2.f - 1.f;
o.Normal.z = sqrt(saturate(1.f - dot(o.Normal.xy, o.Normal.xy)));
o.Albedo = o.Normal;
#endif
#endif
}
ENDCG
}
CustomEditor "VolundMultiStandardShaderGUI"
FallBack "Diffuse"
}
Here is my fragment Shader. Line number 77 onward should be where wrinkle map lines have been pasted and modified a bit.
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom/VidRimTex" {
Properties {
_MainTex("Texture", 2D) = "white" {}
_NormalMap("Normal Map", 2D) = "bump" {}
_BumpDepth("Bump Depth", Float) = 1
}
SubShader {
Pass{
Tags{ "LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#pragma multi_compile _ WRINKLE_MAPS
#include "UnityCG.cginc"
struct VertexInput {
float4 position: POSITION;
float3 normal: NORMAL;
float4 tex: TEXCOORD0;
float4 tangent: TANGENT;
};
struct VertexOutput {
float4 position: POSITION;
float4 tex: TEXCOORD0;
float3 posWorld: POS;
float3 normalWorld: TEXCOORD1;
float3 tangentWorld: TEXCOORD2;
float3 binormalWorld: TEXCOORD3;
float4 screenPos: TEXCOORD4;
};
sampler2D _MainTex;
sampler2D _NormalMap;
sampler2D _NormalAndOcclusion;
float4 _MainTex_ST;
float4 _LightColor0;
float _BumpDepth;
VertexOutput vert(VertexInput i){
VertexOutput o;
o.posWorld = mul(unity_ObjectToWorld, i.position);
o.position = mul(UNITY_MATRIX_MVP, i.position);
o.tex = i.tex;
float4 pos = UnityObjectToClipPos(i.position);
o.screenPos = ComputeScreenPos (pos);
o.normalWorld = normalize(mul(float4(i.normal, 0.0), unity_WorldToObject).xyz);
o.tangentWorld = normalize(mul(unity_ObjectToWorld, i.tangent).xyz);
o.binormalWorld = normalize(cross(o.normalWorld, o.tangentWorld) * i.tangent.w);
return o;
}
float4 frag(VertexOutput o) : COLOR{
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
float3 viewDirection = normalize( _WorldSpaceCameraPos.xyz - o.posWorld.xyz );
// float3x3 local2WorldTranspose = float3x3(
// float3(o.tangentWorld.x, o.binormalWorld.x, o.normalWorld.x),
// float3(o.tangentWorld.y, o.binormalWorld.y, o.normalWorld.y),
// float3(o.tangentWorld.z, o.binormalWorld.z, o.normalWorld.z)
// );
float3x3 local2WorldTranspose = float3x3(
o.tangentWorld,
o.binormalWorld,
o.normalWorld
);
#ifdef WRINKLE_MAPS
//Taken from source exactly
float3 normalOcclusion = tex2D(_NormalAndOcclusion, o.screenPos.xy / o.screenPos.w).rgb;
// float3 rescaledNormal = float3((2 * normalOcclusion.gb) - float2( 1, 1 ), _BumpDepth);
float3 rescaledNormal;
rescaledNormal.xy = normalOcclusion.gb * 2.f - 1.f;
rescaledNormal.z = sqrt(saturate(1.f - dot(rescaledNormal.xy, rescaledNormal.xy)));
//End of Taken from source exactly
float3 normalDirection = mul( rescaledNormal, local2WorldTranspose );
return float4(normalDirection, 1);
#else
float3 rescaledNormal = UnpackNormal(tex2D(_NormalMap, o.tex.xy));
// float4 normalColor = tex2D(_NormalMap, o.tex.xy);
// float3 rescaledNormal = float3((2 * normalColor.ag) - float2( 1, 1 ), _BumpDepth);
float3 normalDirection = normalize( mul( rescaledNormal, local2WorldTranspose ));
float3 finalDiffuseColor = _LightColor0 * saturate(dot(normalDirection, lightDirection));
float4 texColor = tex2D(_MainTex, o.tex.xy);
return float4(normalDirection, 1);
// return float4(finalDiffuseColor * texColor, 1);
#endif
}
ENDCG
}
}
FallBack "Diffuse"
}

