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 section:

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
 }
 SubShader
 {
 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"
 //Use shadow to add
   #include "AutoLight.cginc"
 #pragma vertex vert
 #pragma fragment frag
 //Shadow the main directional light
   #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;
 //Shadow statement
 SHADOW_COORDS(4)
 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
 TRANSFER_SHADOW(o);
 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;
 //Make objects receive shadows
 UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
 return float4(hatchColor.rgb*_Color.rgb*atten, 1.0);
 }
 ENDCG
 } 
 }
}

The above is the whole content of this article, I hope to help you in your study, and I hope you can support developeppaer more.

Recommended Today

Simple implementation of Baidu translation by Python crawler

Series of articles: Simple implementation of Baidu translation by Python crawler Python crawler music Simple crawling of bleeding skin Simple crawling of little skin on MC skin station of Python crawler Python crawler to send the weather forecast of the day to learnku friends Python crawler automatically switches the daytime / nighttime mode of learnku […]