The purpose of cartoon coloring is to make the color of the object appear not so good, the light and dark intersection is obvious, and so on a series of characteristics of cartoon style,

Also known as **non-photorealisticrendering non-real rendering**

The key point is to achieve two points:

1. Strokes

2. Coloring

Another: The CG function in this film is marked with green, want to understand the function and function of the internal composition please see this article NVIDIA CG language function of all the mathematical class functions (mathematical Functions)

Just start with the initial stroke.

Declare variables first

*_outline* Extrusion stroke thickness

How far *_factor* Extrusion

Properties {_color ("Main Color", color) = (1,1,1,1) _outline ("Thick of Outline", Range (0,0.1)) =0.02_factor ("Factor", Range (0,1)) =0.5}

Our extrusion operation is carried out in the first pass.

*Cull Front*Cutting the front of the object (facing the camera), extruding the back

*Zwrite* onThe depth of the pixel is written to the depth buffer, and if it is turned off, the object overlaps with the object will not be stroked, because the object rendered here without Z-values will "cover" The Strokes that are extruded here.

Extrude points in the function vert that handle vertices

**dir=normalize(V.VERTEX.XYZ);**
Set up a float3 direction variable dir

The position of the point as a unit vector of the direction of the distance geometric center

**FLOAT3 Dir2=v.normal;**
Set up a float3 direction variable dir

Dir2 for normal direction

**d=dot(DIR,DIR2);**
D to calculate the point product of the point position and the normal direction, by positive negative value can be determined to point or deviate from the geometric center, is a divergence, negative to point

**dir=dir*sign (D);**
Multiply positive negative values, true direction value

dir=dir*_factor+dir2* (1-_factor);
Control how far the extrusion is made by blending the position of the point toward the _factor of the external variable in the normal direction.

**V.vertex.xyz+=dir*_outline;**
Extrude the point outward from the back of the object

v2f Vert (Appdata_full v) {v2f o;float3 dir=normalize (v.vertex.xyz); FLOAT3 dir2=v.normal;float D=dot (DIR,DIR2);d Ir=dir *sign (D);d ir=dir*_factor+dir2* (1-_factor); V.vertex.xyz+=dir*_outline;o.pos=mul (Unity_matrix_mvp,v.vertex); return o;}

The vertex function ends,

Next, paint the Strokes

In the Frag function

Extrude the color of the contour, here the color is arbitrary

The effect is as follows:

The contour is clearly profiled and can be changed by changing the value of the _outline in the material to change the thickness

**The strokes are shader as follows:**

Shader "Tut/shader/toon/miaobian" {Properties {_color ("Main Color", color) = (1,1,1,1) _outline ("Thick of Outline", range (0,0.1)) =0.02_factor ("Factor", Range (0,1)) =0.5}subshader {pass{tags{"lightmode" = "Always"}cull frontzwrite oncgprogram# pragma vertex vert#pragma fragment frag#include "Unitycg.cginc" float _outline;float _factor;float4 _color;struct v2f { Float4 pos:sv_position;}; v2f Vert (Appdata_full v) {v2f o;float3 dir=normalize (v.vertex.xyz); FLOAT3 dir2=v.normal;float D=dot (DIR,DIR2);d Ir=dir *sign (D);d ir=dir*_factor+dir2* (1-_factor); V.vertex.xyz+=dir*_outline;o.pos=mul (Unity_matrix_mvp,v.vertex); return o;} FLOAT4 Frag (v2f i): color{float4 c = _color/5;return C;} endcg}pass{tags{"Lightmode" = "forwardbase"}cull backcgprogram#pragma vertex vert#pragma fragment Frag#include " Unitycg.cginc "Float4 _lightcolor0;float4 _color;float _steps;float _tooneffect;struct v2f {float4 Pos:SV_POSITION; FLOAT3 lightdir:texcoord0;float3 viewdir:texcoord1;float3 Normal:texcoord2;}; v2f Vert (Appdata_full v) {v2f O; O.pos=mul (Unity_matrix_mvp,v.vertex); O.normal=v.normal;o.lightdir=objspacelightdir (V.vertex); o.viewDir= Objspaceviewdir (V.vertex); return o;} FLOAT4 Frag (v2f i): Color{float4 c=1;float3 n=normalize (i.normal); Float3 viewdir=normalize (I.viewdir); FLOAT3 Lightdir =normalize (I.lightdir), float Diff=max (0,dot (n,i.lightdir));d iff= (diff+1)/2;diff=smoothstep (0,1,diff); c=_Color*_ lightcolor0* (diff); return c;} endcg}//}}

Start Cartoon coloring Journey

After the stroke is the play coloring

A few simple examples

Explain the cartoon coloring

Turn the diffuse diffuse color into a distinct number of levels (in this case, four)

Ordinary diffuse diffuse reflection dragon, no color class, color transition is very good, no cartoon feeling

Normal diffuse material

The lovely river sauce is a second-order color coloring, plus the edge of the black stroke, this is a real cartoon, not rendered out = =

"Abyss Legend" is one of the early works of the legend series, with cartoon rendering

The feeling is mostly cartoon texture mapping in the output

"Fairy tale" battle end screen

There is a clear line of intersection (two levels), and with the camera (view direction) changes, the characters have obvious stroke processing, cartoon coloring played a big role

"Endless Legends 2", is a series of relatively close to the legend of the works, the screen is significantly better than before a lot of, but original aim, or with the cartoon coloring, (= = did not play this)

The character has an obvious stroke.

In addition, I feel that the effect of the light is very good ah, it should be bloom or HDR, such as, off the topic =

Start fencing Cartoon Coloring

The first pass is the top stroke pass.

Coloring of a diffuse cartoon in the second pass

Declare variables first

*_color* The color of the object

*_outline* Extrusion stroke thickness

How far *_factor* Extrusion

*_tooneffect* Cartoon degree (two-dimensional and three-dimensional junction lines)

*_steps* Color stratum number

Properties {_color ("Main Color", color) = (1,1,1,1)//object's Color _outline ("Thick of Outline", Range (0,0.1)) =0.02//Extrusion Stroke Thickness _ Factor ("Factor", Range (0,1)) =0.5//extrusion How far _tooneffect ("Toon Effect", Range (0,1)) =0.5//the degree of animation (two-dimensional and three-dimensional junction lines) _steps ("Steps of Toon ", Range (0,9)) =3//color Hierarchy}

Cartoon coloring is mainly done in the coloring function Frag

**float diff=Max(0,dot (N,i.lightdir));**
Find the normal diffuse color

**diff= (diff+1)/2;**

Do light processing

**diff=smoothstep(0,1,diff);**

Make the color smooth within the [0,1] range

**Float toon=Floor (diff*_steps)/_steps;**

The color is discretized, the diffuse color is limited to _steps species (_steps order color), simplifying the color, so that the color scale between the smooth display

**diff=lerp(diff,toon,_tooneffect);**

According to the external we controllable cartoon degree value _tooneffect, adjust the proportion of cartoon and reality

**c=_color*_lightcolor0* (diff);**

Mix the final color

The second pass ends,

FLOAT4 Frag (v2f i): Color{float4 c=1;float3 n=normalize (i.normal); Float3 viewdir=normalize (I.viewdir); FLOAT3 Lightdir =normalize (I.lightdir), float Diff=max (0,dot (N,i.lightdir)),//Find normal diffuse color diff= (diff+1)/2;//do light processing diff=smoothstep ( 0,1,diff);//make the color smooth within the [0,1] range float Toon=floor (diff*_steps)/_steps;//The color is discretized, the diffuse color is limited to _steps species (_steps order color), Simplify the color, such processing so that the color scale can be smooth display diff=lerp (diff,toon,_tooneffect);//According to the external we can control the value of the cartoon degree of _tooneffect, adjust the proportion of the cartoon and reality C=_color*_ lightcolor0* (diff);//Mix the final color return c;}

The third pass is the addition of a discrete highlight on the basis of the second pass.

The float variable dist is established to find the distance from the light source, float

**float atten=1/(dist);**
The attenuation is obtained according to the distance from the light source;

The Diffuse reflection section is the same as the second pass;

Half3 h = normalize (Lightdir + viewdir);
Find the half-width vector

**Float NH = Max (0, Dot (N, h));**

Float spec = pow (NH, 32.0);
Find out the high light intensity under normal conditions

**float toonspec=Floor (spec*atten*2)/2;**
Also discretization of the highlights

**spec=lerp(spec,toonspec,_tooneffect);**
Adjust the proportion of cartoons and realistic highlights

FLOAT4 Frag (v2f i): Color{float4 c=1;float3 n=normalize (i.normal); Float3 viewdir=normalize (I.viewdir); float dist= Length (i.lightdir);//Find out the distance from the light source FLOAT3 lightdir=normalize (i.lightdir); float Diff=max (0,dot (n,i.lightdir));d iff= ( diff+1)/2;diff=smoothstep (0,1,diff); float atten=1/(dist);//based on distance from the light source to find the attenuation float Toon=floor (diff*atten*_steps)/_ Steps;diff=lerp (Diff,toon,_tooneffect); Half3 h = normalize (Lightdir + viewdir);//Find out half-width vector float NH = max (0, Dot (N, h)); Flo At spec = POW (NH, 32.0);//find high light intensity float Toonspec=floor (spec*atten*2)/2;//to disperse the highlights also Spec=lerp (Spec,toonspec,_tooneffect) ;//Adjust the proportion of cartoon and reality high Light c=_color*_lightcolor0* (DIFF+SPEC);//Find out the final color return c;}

You can get this cartoon effect:

Shader as follows:

Shader "Tut/shader/toon/toon" {Properties {_color ("Main color", color) = (1,1,1,1)//object's Color _outline ("Thick of Outline", Range (0,0.1) =0.02//extrusion stroke thickness _factor ("Factor", Range (0,1)) =0.5//extrusion How far _tooneffect ("Toon Effect", Range (0,1)) =0.5// Cartoon degree (two-and three-dimensional junction lines) _steps ("Steps of Toon", Range (0,9)) =3//color hierarchy}subshader {pass{//Pass rendering before lighting is processed tags{"lightmode" = " Always "}cull frontzwrite oncgprogram#pragma vertex vert#pragma fragment frag#include" Unitycg.cginc "float _outline; Float _factor;struct v2f {float4 pos:sv_position;}; v2f Vert (Appdata_full v) {v2f o;float3 dir=normalize (v.vertex.xyz); FLOAT3 dir2=v.normal;float D=dot (DIR,DIR2);d Ir=dir *sign (D);d ir=dir*_factor+dir2* (1-_factor); V.vertex.xyz+=dir*_outline;o.pos=mul (Unity_matrix_mvp,v.vertex); return o;} FLOAT4 Frag (v2f i): Color{float4 c=0;return C;} Endcg}//end of passpass{//parallel light pass rendering tags{"Lightmode" = "forwardbase"}cull backcgprogram#pragma vertex vert#pragma Fragment Frag#include "Unitycg.cginc" float4 _lightcolor0;float4 _color;float _steps;float _tooneffect;struct V2f {float4 POS:SV_POSITION;FLOAT3 lightdir:texcoord0;float3 viewdir:texcoord1;float3 normal:texcoord2;}; v2f Vert (Appdata_full v) {v2f o;o.pos=mul (Unity_matrix_mvp,v.vertex);//switch to world coordinates o.normal=v.normal;o.lightdir= Objspacelightdir (V.vertex); O.viewdir=objspaceviewdir (V.vertex); return o;} FLOAT4 Frag (v2f i): Color{float4 c=1;float3 n=normalize (i.normal); Float3 viewdir=normalize (I.viewdir); FLOAT3 Lightdir =normalize (I.lightdir), float Diff=max (0,dot (N,i.lightdir)),//Find normal diffuse color diff= (diff+1)/2;//do light processing diff=smoothstep ( 0,1,diff);//make the color smooth within the [0,1] range float Toon=floor (diff*_steps)/_steps;//The color is discretized, the diffuse color is limited to _steps species (_steps order color), Simplify the color, such processing so that the color scale can be smooth display diff=lerp (diff,toon,_tooneffect);//According to the external we can control the value of the cartoon degree of _tooneffect, adjust the proportion of the cartoon and reality C=_color*_ lightcolor0* (diff);//Mix the final color return c;} endcg}//pass{//the pass rendering of the additional point light tags{"lightmode" = "Forwardadd"}blend one onecull backzwrite offcgprogram#pragma vertex Vert#pragma fragment Frag#include "Unitycg.cginc" float4 _lightcolor0;float4 _color;float _steps;float _ToonEffect; struct V2F {fLOAT4 pos:sv_position;float3 lightdir:texcoord0;float3 viewdir:texcoord1;float3 normal:texcoord2;}; v2f Vert (Appdata_full v) {v2f o;o.pos=mul (Unity_matrix_mvp,v.vertex); O.normal=v.normal;o.viewdir=objspaceviewdir ( V.vertex); O.lightdir=_worldspacelightpos0-v.vertex;return o;} FLOAT4 Frag (v2f i): Color{float4 c=1;float3 n=normalize (i.normal); Float3 viewdir=normalize (I.viewdir); float dist= Length (i.lightdir);//Find out the distance from the light source FLOAT3 lightdir=normalize (i.lightdir); float Diff=max (0,dot (n,i.lightdir));d iff= ( diff+1)/2;diff=smoothstep (0,1,diff); float atten=1/(dist);//based on distance from the light source to find the attenuation float Toon=floor (diff*atten*_steps)/_ Steps;diff=lerp (Diff,toon,_tooneffect); Half3 h = normalize (Lightdir + viewdir);//Find out half-width vector float NH = max (0, Dot (N, h)); Flo At spec = POW (NH, 32.0);//find high light intensity float Toonspec=floor (spec*atten*2)/2;//to disperse the highlights also Spec=lerp (Spec,toonspec,_tooneffect) ;//Adjust the proportion of cartoon and reality high Light c=_color*_lightcolor0* (DIFF+SPEC);//Find out the final color return c;} endcg}//}}

This has been able to make a good cartoon effect, you can on this basis to develop a strengthened version

Enhanced version 1:

With the Edge light rim

Beautiful blue Planet of water (= =; texture)

is to add a rim value to the second pass.

The added external variables;

*_rimpower*Degree of edge brightness

*_toonrimstep*Edge Light Color Scale

In the Frag function

**Float rim = 1.0- saturate(dot(N,normalize (Viewdir)));**
Find out the normal edge light level

**rim = rim+1;**
Make It brighter

**rim = Pow(rim, _rimpower);**
External variable _rimpower control edge brightness Size

**float Toonrim = Floor (RIM * _toonrimstep)/_toonrimstep;**
Further discretization of the edge Light

**rim = lerp(rim, Toonrim, _tooneffect);**
Adjust the proportion of cartoons to reality

**c=_color*_lightcolor0* (diff) * rim * MC*2;**
Make final color blending

FLOAT4 Frag (v2f i): Color{half4 mc = tex2d (_maintex, I.uv_maintex); Float4 c=1;float3 n=normalize (i.normal); float3 Viewdir=normalize (I.viewdir); Float3 lightdir=normalize (I.lightdir); float Diff=max (0,dot (n,i.lightdir));d iff= ( diff+1)/2;diff=smoothstep (0,1,diff); float Toon=floor (diff*_steps)/_steps;diff=lerp (diff,toon,_tooneffect); float rim = 1.0-saturate (dot (N, normalize (Viewdir)));//Find out the normal edge light level rim = rim+1;//make it brighter rim = POW (rim, _rimpower);//external variable _rimpower Control edge Brightness size float Toonrim = Floor (RIM * _toonrimstep)/_toonrimstep;//then discretization of edge light rim = Lerp (rim, Toonrim, _tooneffect);//Adjustment card c=_color*_lightcolor0* (diff) * Rim * mc*2;//The final color mix return C;

3d fabric living in three-dimensional world and 3d fabric living in two-dimensional world

Enhanced Version 2:

With texture map version

Enhanced Version 3:

RIM version with texture map

RIM version with texture map variant

The texture map is not recommended to disperse, the effect is not good, = =;

The next is waiting for you crossing to continue to develop, what better effect must tell me

**-----------------------by wolf96**http://blog.csdn.net/wolf96

Unity3d shader Cartoon Coloring Toon Shading