Unity3d shader Cartoon Coloring Toon Shading

Source: Internet
Author: User
Tags diff mathematical functions mul pow

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 FrontCutting 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;

_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 wolf96http://blog.csdn.net/wolf96




Unity3d shader Cartoon Coloring Toon Shading

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.