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 operates in the first pass
cull Front clipped the front of the object (to the camera), Extrude the back of the
zwrite on pixels deep Write depth buffer, if closed, the object and object overlap will not be stroked, Because objects rendered without Z-values here "cover"
Extrude points in the function vert that handle vertices
dir=normalize (V.VERTEX.XYZ);
Establish a float3 dir
to position the point as a unit vector of the direction of the distance to the geometric center
FLOAT3 dir2=v.normal;
Establish a float3 direction variable dir
Dir2 for normal direction
d=dot (DIR,DIR2);
D is the point product that calculates the point position and the normal direction, with positive negative values to determine whether to point to or deviate from the geometric center, just as a divergence, negative to point to
dir=dir* (D);
Multiply positive negative values, true orientation value
dir=dir*_factor+dir2* (1-_factor);
Control how far the extrusion is made by blending the point position 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 [0,1] range float Toon=floor (diff*_steps)/_steps;//to disperse the color, The diffuse color is limited to _steps species (_steps-order color), simplifying 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 degree of cartoon value _ Tooneffect, adjust the proportion of cartoon and Reality c=_color*_lightcolor0* (diff);//Mix the final color return c;}
The third pass is to add a discretized highlight on top of the second pass
Create a float variable dist to find the distance from the light source float
float atten=1/ (dist);
The attenuation is calculated based on the distance from the light source;
The diffuse part is the same as the second pass;
Half3 h = normalize (Lightdir + viewdir);
Find half-width vector
float nh = max (0, Dot (N, h));
Float spec = pow (NH, 32.0);
Find highlight intensity under normal conditions
float toonspec=floor (spec*atten*2)/2;
The highlight is also discretized
spec=lerp (spec,toonspec,_tooneffect);
Adjust the proportion of cartoons to 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;
_rimpowerDegree of edge brightness
_toonrimstepEdge 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
Unity3d shader Cartoon Coloring Toon Shading