# Unity shader for sketch effect

Time：2020-10-28

In this paper, we share the specific code of unity shader to achieve sketch effect for your reference. The specific content is as follows

This is the unreal rendering in Lele’s book. The algorithm is very interesting. If you are interested, you can have a try.

The basic principle of sketch effect: first, draw the outline of the object, and calculate the diffuse part of the object. The darker the diffuse reflection is, the darker the color is. Then set the weight of the sampling map according to the value of the diffuse reflection.

Sample map:

``````Shader "Unlit/Sketch"
{
Properties
{
_Color("Color",Color) = (1,1,1,1)
//Map tiling factor
_TileFactor("TileFactor", Range(0, 10)) = 1
_Hatch0("Hatch0",2D)="white"{}
_Hatch1("Hatch1",2D) = "white"{}
_Hatch2("Hatch2",2D) = "white"{}
_Hatch3("Hatch3",2D) = "white"{}
_Hatch4("Hatch4",2D) = "white"{}
_Hatch5("Hatch5",2D) = "white"{}
//Stroke coefficient
_OutlineFactor("OutlineFactor",Range(0.0,0.1))=0.01
}
{
Tags{ "Queue" = "Transparent" }
//Two passes are used for stroke. The first pass extrudes a little along the normal, and only the color of stroke is output
Pass
{
//Cull the front and render only the back
Cull Front
//Turn off deep writing
ZWrite Off
//Control the depth offset, stroke pass away from the camera to prevent the normal pass from interleaving
Offset 1,1

CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
float _OutlineFactor;

struct v2f
{
float4 pos : SV_POSITION;
};

v2f vert(appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//Convert normal direction to view space
float3 vnormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
//Transform the view space normal XY coordinate into the projection space
float2 offset = TransformViewToProjection(vnormal.xy);
//In the final projection phase, the output is used for offset operation
o.pos.xy += offset * _OutlineFactor;
return o;
}

fixed4 frag(v2f i) : SV_Target
{
return float4(0,0,0,1);
}
ENDCG
}

Pass
{
CGPROGRAM
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase

float4 _Color;
float _TileFactor;
sampler2D _Hatch0;
sampler2D _Hatch1;
sampler2D _Hatch2;
sampler2D _Hatch3;
sampler2D _Hatch4;
sampler2D _Hatch5;

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
//6 deepening maps in turn
float3 hatchWeights0:TEXCOORD1;
float3 hatchWeights1:TEXCOORD2;
float3 worldPos:TEXCOORD3;
};

v2f vert (appdata_full v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
//The larger the tiling factor, the denser the map is displayed
o.uv = v.texcoord* _TileFactor;
float3 worldLightDir = normalize(WorldSpaceLightDir(v.vertex));
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
//Diffuse reflection
float diffuse = max(0, dot(worldLightDir, worldNormal));
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz ;
//Weight of six pictures
o.hatchWeights0 = float3(0, 0, 0);
o.hatchWeights1 = float3(0, 0, 0);
//The weight is calculated based on the diffuse value, the darker the diffuse, the denser the lines
float hatchFactor = diffuse * 7.0;
if (hatchFactor > 6.0) {
}
else if (hatchFactor > 5.0) {
o.hatchWeights0.x = hatchFactor - 5.0;
}
else if (hatchFactor > 4.0) {
o.hatchWeights0.x = hatchFactor - 4.0;
o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;
}
else if (hatchFactor > 3.0) {
o.hatchWeights0.y = hatchFactor - 3.0;
o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;
}
else if (hatchFactor > 2.0) {
o.hatchWeights0.z = hatchFactor - 2.0;
o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;
}
else if (hatchFactor > 1.0) {
o.hatchWeights1.x = hatchFactor - 1.0;
o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;
}
else {
o.hatchWeights1.y = hatchFactor;
o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;
}
//Transfer the calculated shadow to fragment
return o;
}

fixed4 frag (v2f i) : SV_Target
{
float4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;
float4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;
float4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;
float4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;
float4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;
float4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;
//Diffuse reflection暗色部分权重越大，白色越少
float4 whiteColor = float4(1, 1, 1, 1)*(1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z - i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);
float4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5+ whiteColor;
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
return float4(hatchColor.rgb*_Color.rgb*atten, 1.0);
}
ENDCG
}
}
}``````