Cartoon Shader in Unity3d Tutorial
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

Cartoon Shader in Unity3d Tutorial

  • 9,618 views
Uploaded on

download pdf on: https://dl.dropboxusercontent.com/u/28326381/Tutorial_Cartoon%20Shader_Unity3d.pdf ...

download pdf on: https://dl.dropboxusercontent.com/u/28326381/Tutorial_Cartoon%20Shader_Unity3d.pdf

visit my website:
http://www.bytestyles.net

Tutorial for the creation of a toon shader for unity. Waiving the tradition approach of a ramp texture in the lighting. Instead we use a transition-Texture between bright and dark lighting values.

An assignment from the HTW-Berlin - Game Design Studies. Course: Unity Programming

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
9,618
On Slideshare
9,613
From Embeds
5
Number of Embeds
1

Actions

Shares
Downloads
113
Comments
0
Likes
10

Embeds 5

https://twitter.com 5

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. ContentIntroduction 1Getting Started 2Implementing the lightingmodellHow lighting works 4Implementation of our own Lighting Model 6Getting the UV to the Lightingfunction 9Finally Shading 10Some improvements to the lighting 12Finalizing the Lighting 13The rim-lightingExplanation 15Implementing 16Sources 171. IntroductionIn this tutorial we will create a Unity3dSurface shader which tries to achieve acartoony look beyond simply using a ramptexture in the lighting function.Instead I will try to create the look bydeterming the shading of the areabetween bright and dark areas with agreyscale mask. That‘s what the main partof this tutorial will be about. Later on wewill add a rim-effect to further improve thevisual appeal. I will also try to explain theconcepts behind the things we will bedoing.Introduction - Cartoon Shader Tutorial 1
  • 2. Getting Started - Cartoon Shader Tutorial 21. Getting StartedSetting Up the ProjectCreate a new Projectstep 1Import the AssetPackage you can download here.https://dl.dropboxusercontent.com/u/28326381/shader%20dnload%20package.unitypackagestep 2Fig1.: How to import a custom package to unitystep 3 Place the „ImprodLowPoly“-model in thescene. (Drag & Drop from the project view)step 4 Create a new Shader.Assets > Create > ShaderName it „CartoonShader“.step 5 Create a new Material.Assets > Create > MaterialName it „CartoonMaterial“.step 6 Apply the Cartoon Material to the modelyou‘ve placed in the scene in step 3.step 7 Create a direction Light.GameObject > Create Other > Directional LightYou can adjust the light-angle by rotating the light.
  • 3. Your Unityproject should look about like this right now. Youshould have:• Imported the downloaded Assets• Created the shader and the material and applied the material to themodel• Created a directional lightAssign the CartoonShaderto the CartoonMaterial.Select theCartoonMaterial in theproject view and hit thebutton next to „shader“and select„CartoonShader“ fromthe Custom section.step 9 Open the shader by doubleClicking the„CartoonShader“ in yourproject view. Monodevelopshould open. Give it a fewseconds and you should seesomething like in thisimage.This is our shader code.step 10Getting Started - Cartoon Shader Tutorial 3
  • 4. 2. Lighting ModelLet‘s begin with the most important part of this shader – the shading. Since thegoal of this shader is to mix the diffuse texture with greyscale textures based onthe lighting, we will write our own lightingfunction and use it in our shader.How the Surface Shader worksSince we use a surface shader, we calculate the actual color of the surface in thevoid surf (Input IN, inout SurfaceOutput o) – function. This function gets calledfor each surface fragment the engine is rendering. The function recievesimportant data via the IN struct. We take this data und use it, to calculate thecolors, normals, and anything else needed in the SurfaceOutPut-struct which getspassed on the next step, the lighting function. Here the data can be changed andused to let each light in the scene, modify our rendering fragment.This, off course, is only a very simplified explanation of a surface shader inUnity3d.Read More about how a Surfaceshader works here:http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaders.htmlWhat is a surface?What we are basically trying to do is, coloring and shadingsurfaces.A surface always has direction it is facing to. This direction isstored as a vector – the surface normal. A 3d mesh in ourrendering pipeline consists of many triangles each with itsown normal (Fig 2).What is a light?In terms of rendering the key elements forming a light are:• The position / direction of the light Source• The colorThat‘s basically it. And that‘s all we need to compute ourlighting.How lighting worksFig2.: surface normals of a meshLighting Model - Cartoon Shader Tutorial 4
  • 5. How lighting is computedThe shading of a surface is the result of a calculation between the incoming light directionand the surface normal. Different lighting models calculate this differently. But most modelsresemble the way lighting works in real life.The formula is easyThe more a surface is facing towards the light direction, the brighter it willappear.Or more mathematically speaking:The bigger the angle between the surface normal and the lightdirection gets, the less lightcolor is applied to the already calculatedsurface color.By calculating the dot product of two vectors we get the angle between two vectors as ascalar between 0 and 1. While dot(v1, v2) returns 1 when both vectors are facing towardseach other.We then use this value tomultiply it with our surfacecolor (red in fig.3). The morethe surface normals directionpoints towards the lightdirection, the higher thelightValue gets thus increasingthe amount of surfaceColor.Lighting Model - Cartoon Shader Tutorial 5
  • 6. 2. Implementation of our own Lighting Modelstep 1 Declaration of our own Lighting ModelOpen the editor with the shader code we have opened previously. (or justdouble-click the shader again).We can either use a built-in lighting model from unity like Lambert, Phongetc. but we also have the option to write our own little lighting function.In order to do that, we simply declare a new function after the Input Code-Block. By putting this code after the Input Struct-declaration:half4 LightingCartoon(SurfaceOutput s, half3 dir, half attend){}• Half4 means that this function will return a four-component vector (which will be used ascolor – (Red,Green,Blue,Alpha)• When naming the function LightingCartoon we tell Unity that this function may be usedto compute lighting• SurfaceOutput provides all the data previously calculated in the surf function• Dir is the light directionThis part of the code, should look like this right now:Shader "Custom/CartoonShader" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Lambertsampler2D _MainTex;struct Input {float2 uv_MainTex;};half4 LightingCartoon(SurfaceOutput s, half3 dir, half attend){}void surf (Input IN, inout SurfaceOutput o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.Albedo = c.rgb;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"}Lighting Model- Cartoon Shader Tutorial 6
  • 7. step 2 Lets return some stuffSince this function returns a color, we should write some code in order to test our ownlighting model.Our final lighting model will be based on a so called „Wrap-Lambert“ which only lets aportion of the light affect the surface color.In our in Step1 declared LightingCartoon function we put the following :dir = normalize(dir);half NdotL = saturate( dot (s.Normal, dir));This will normalize our light-direction vector leaving it with amagnitude of 1.0. Otherwise this will mess up the dot-productCalculate the dot product. Saturate(float) makes sure, the value is clampedbetween 0 and 1 because we don‘t want to multiply our surface colors withnegative values)Actually return a color, first we declar it.Then the Albedo (diffuse) – Colorfrom the surface shader gets multiplied with our light-angle. And finally welet the Lightcolor have a shot to modify or final color. _LightColor0 is aglobal value, describing the currently rendered lightcolorhalf4 c;c.rgb = ((NdotL * 0.2f)+0.8f) * s.Albedo * _LightColor0;c.a = s.Alpha;return c;Now we need to tell unity to use our lightingmodel – we do this in the pragma section.The default lightingmodel is the lambert lighting model. So we will change that bychanging lambert > Cartoon.half4 LightingCartoon(SurfaceOutput s, half3 dir, half attend){dir = normalize(dir);half NdotL = saturate( dot (s.Normal, dir));half4 c;c.rgb = ((NdotL * 0.2f)+0.8f) * s.Albedo * _LightColor0;c.a = s.Alpha;return c;}The LightingFunction should now like this:#pragma surface surf CartoonLighting Model - Cartoon Shader Tutorial 7step 2.1
  • 8. Save the shader, and switch back to the unity3d Editor, the shader will now compile and the material inthe viewport will update as soon as it‘s done giving you result looking like this:Notice how even the dark areas aren‘ttotally black that‘s because of thispiece of code we have just written:(NdotL * 0.2f)+0.8f)Making sure, there is at least 20%lighting.Additionally we have still some fairamount of Ambient light in the scene.Which we will turn of now…step 3 Turning off the ambient lightGo to Edit > Render Settings andAssign black to the Ambient Light Color-Slotstep 4 Declaring some propertiesWhat we are trying to achieve is having a a shading color for the bright and for the dark side. And a texturefor the transition zone.Lets start with the hardest part, getting the zones right.Just a reminder – this is ourplan:_BrightColor("Bright Color", Color) = (1,0,0)_Threshold1("Threshold Bright to Dark", range(0,1)) = 0.2_DarkColor("Dark Color", Color) = (0,1,0)_Threshold2("Threshold Middle to Dark", range(0,1)) = 0.9_TransitionTexture("Transition Texture", 2D) = "white" {}First we declare new properties forthe two colors. In our propertiescodeblock we put this code:sampler2D _TransitionTexture;half4 _BrightColor;half4 _DarkColor;half _Threshold1;half _Threshold2;Then we need to add the respectiveshader variables to get theproperties values to the shader. Addthis before the INPUT struct.Lighting Model - Cartoon Shader Tutorial 8
  • 9. Save the file. Go to the editor and check the material.The properties of the material on your object shouldlook like this (fig. 4)Unfortunately these colors don’t affect our shadermuch at the moment.Let’s change that!step 5 Getting the UV to the LightingfunctionWe do not have access to the uv-coordinates of the current rendered surface piece inthe lighting function. We will code our own struct which gets passed on through all thefunctions and use this one instead of the „SurfaceOutput“ struct. Let‘s declare theSurfaceOutputCustom struct right after the Input-struct declaration.struct SurfaceOutputCustom {fixed3 Albedo;fixed3 Normal;fixed3 Emission;half Specular;fixed Gloss;fixed Alpha;fixed viewFallof;half2 UV;};Getting our struct to workThis struct actually contains the usual data plusthe UV part. We will write the UV to the structwhich will then get passed to the lightingfunction. We need to change the arguments ofthe lighting and surface function to make thishappen.Change the lighting function declaration now to thisstep 5.1And we will change the surface function to this:half4 LightingCartoon(SurfaceOutputCustom s, half3 dir, half attend)void surf (Input IN, inout SurfaceOutputCustom o)Also add this line to the surf function – this will write the UV values to our struct sowe can access is it in the lighting.o.UV = IN.uv_MainTex;Lighting Models - Cartoon Shader Tutorial 9
  • 10. step 6 Finally Shading!First I have to introduce ternary expressions. You are probably familiar with the if-else structure inconditional statements. Although the shader code is able to handle if-else structures in this case weneed to express our conditions with a ternary operation.It works like this:We will use the treshold to determine which color for the light based shading we will use.ShadowColor = NdotL < _Threshold1 ? _DarkColor : NdotL < _Threshold2 ? lerp(_DarkColor,_BrightColor, tex2D(_TransitionTexture, s.UV)) : _BrightColor;In code – it looks like this (I‘ve left out the texturing for _BrightColor and _DarkColor fornow)lerp(DarkColor, BrightColor, tex2D(_TransitionTexture, s.UV) )Lerp(value1, value2, percent);Interpolates between Color1 and Color2using the percent valuetex2D(texture, UV);We will get the percent value from ourtransitionTexture @ the current UVpositionc.rgb = ((NdotL * 0.2f)+0.8f) * s.Albedo * _LightColor0 * ShadowColor;half3 ShadowColor = NdotL < _Threshold1 ? _DarkColor : NdotL < _Threshold2 ?lerp(_DarkColor, _BrightColor, tex2D(_TransitionTexture, s.UV)) : _BrightColor;Add this line to the LightingCartoon funcion, right after the NdotL declaration.… and multiply our previously calculated ShadowColor to the output color by changing it to this:Lighting Model - Cartoon Shader Tutorial 10
  • 11. Step 6 |CODEShader "Custom/CartoonShader"{Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_BrightColor("Bright Color", Color) = (1,0,0)_Threshold1("ThresholdBright to Dark", range(0,1)) = 0.2_DarkColor("Dark Color", Color) = (0,1,0)_Threshold2("ThresholdMiddle to Dark", range(0,1)) = 0.9_TransitionTexture("Transition Texture", 2D) = "white" {}}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Cartoonsampler2D _MainTex;sampler2D _TransitionTexture;half4 _BrightColor;half4 _DarkColor;half _Threshold1;half _Threshold2;struct Input {float2 uv_MainTex;};struct SurfaceOutputCustom{fixed3 Albedo;fixed3 Normal;fixed3 Emission;half Specular;fixed Gloss;fixed Alpha;fixed viewFallof;half2 UV;};half4 LightingCartoon(SurfaceOutputCustom s, half3 dir, half attend){dir = normalize(dir);half NdotL = saturate( dot (s.Normal, dir));half3 ShadowColor = NdotL < _Threshold1 ? _DarkColor : NdotL <_Threshold2 ? lerp(_DarkColor, _BrightColor, tex2D(_TransitionTexture, s.UV)) :_BrightColor;half4 c;c.rgb = ((NdotL * 0.4f)+0.6f) * s.Albedo * _LightColor0 * ShadowColor;c.a = s.Alpha;return c;}void surf (Input IN, inout SurfaceOutputCustom o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.UV = IN.uv_MainTex;o.Albedo = c;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"}Let‘s wrap it.The code should look like this at the moment.Assign tex1 to the transition texture slot in the material – which shouldproduce something like this:Lighting Model - Cartoon Shader Tutorial 11
  • 12. Step 7 Some improvements to the lighting.We definitely need to be able to influence the transitiontextures size.Since I don’t want to add a variable to our custom struct for each UV, we will simplyadd a float and scale the UV accordingly.Add this property right after the existing ones:_TransitionTextureSize("Transition Texture Size", range(0.1, 50)) = 1And the shader variable.. Just after “half Treshhold1”half _TransitionTextureSize;Now we will use this value to scale the transition texture. By changing the texturelookup in our ternary expresionhalf3 ShadowColor = NdotL < _Threshold1 ? _DarkColor : NdotL < _Threshold2 ?lerp(_DarkColor, _BrightColor, tex2D(_TransitionTexture, s.UV *_TransitionTextureSize)) :_BrightColor;Now we will use this value to scale the transition texture. By changing the texturelookup in our ternary expression.Step 7.1 Adding TexturesTo have more artistic control over the shading to make the colors look painted forexample, we are going to multiply the shades with a texture. Again, first – theproperties. Add those:_BrightTexture("Bright Color Texture", 2D) = "white"{}_BrightTextureSize("Bright Texture Size", range(0.1,50)) = 1_BrightTextureIntensity("Bright Texture Intensity", range(0.0,1)) = 0.5_DarkTexture("Dark Color Texture", 2D) = "white"{}_DarkTextureSize("Dark Texture Size", range(0.1,50)) = 1half _DarkTextureSize;half _BrightTextureSize;half _BrightTextureIntensity;sampler2D _BrightTexture;sampler2D _DarkTexture;Let’s add the Shader variables as well. Right before the Inputstruct, after the shader variable from step 7.Whenever we look up the _BrightColor or _DarkColor. We will multiply itwith a value from its texture. We Also want to set the intensity of the_BrightTexture. We need to change a lot of stuff in our LightingCartoonfunction. Between the NdotL and _Shadowcolor declaration!ADDhalf4 darkColor = _DarkColor * tex2D(_DarkTexture, s.UV * _DarkTextureSize);half4 brightColor = _BrightColor * ( tex2D(_BrightTexture, s.UV * _BrightTextureSize) * _BrightTextureIntensity +(1-_BrightTextureIntensity));With these lines we declare a new Color-Vector and multiply the Colors from the properties with the values from thetexture at that spot. While the darkColor is a simple multiplication. We craft in the _BrightTextureIntensity as a sort ofweight for the TextureValue of the brightColor.Now we only need to add the new colors to the ternary expression.half3 ShadowColor = NdotL < _Threshold1 ? darkColor : NdotL < _Threshold2 ? lerp(darkColor,brightColor, tex2D(_TransitionTexture, s.UV * _TransitionTextureSize)) : brightColor;Lighting Model - Cartoon Shader Tutorial 12
  • 13. Step 7.2 Finalizing the LightingAdd some texturesfor the differentshading zones, andplay around with thecolors, and texturesizes. Settings usedfor this Screenshot:BrightColor:(255,215,178)BrightTexture:Pencil_stroke_02DarkColor::(99,79,66)DarkTexture:Pencil_stroke_01TransitionTexture:Pencil_strokes_03Lighting Model - Cartoon Shader Tutorial 13
  • 14. CODEShader "Custom/CartoonShader" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_BrightColor("Bright Color", Color) = (1,0,0)_Threshold1("Threshold Bright to Dark", range(0,1)) = 0.2_DarkColor("Dark Color", Color) = (0,1,0)_Threshold2("Threshold Middle to Dark", range(0,1)) = 0.9_TransitionTexture("Transition Texture", 2D) = "white" {}_TransitionTextureSize("Transition Texture Size", range(0.1, 50)) = 1_BrightTexture("Bright Color Texture", 2D) = "white"{}_BrightTextureSize("Bright Texture Size", range(0.1,50)) = 1_BrightTextureIntensity("Bright Texture Intensity", range(0.0,1)) =0.5_DarkTexture("Dark Color Texture", 2D) = "white"{}_DarkTextureSize("Dark Texture Size", range(0.1,50)) = 1}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Cartoonsampler2D _MainTex;sampler2D _TransitionTexture;half4 _BrightColor;half4 _DarkColor;half _Threshold1;half _Threshold2;half _TransitionTextureSize;half _DarkTextureSize;half _BrightTextureSize;half _BrightTextureIntensity;sampler2D _BrightTexture;sampler2D _DarkTexture;struct Input {float2 uv_MainTex;};struct SurfaceOutputCustom {fixed3 Albedo;fixed3 Normal;fixed3 Emission;half Specular;fixed Gloss;fixed Alpha;fixed viewFallof;half2 UV;};half4 LightingCartoon(SurfaceOutputCustom s, half3 dir, halfattend){dir = normalize(dir);half NdotL = saturate( dot (s.Normal, dir));half4 darkColor = _DarkColor * tex2D(_DarkTexture, s.UV *_DarkTextureSize);half4 brightColor = _BrightColor * ( tex2D(_BrightTexture, s.UV *_BrightTextureSize) * _BrightTextureIntensity + (1-_BrightTextureIntensity));half3 ShadowColor = NdotL < _Threshold1 ? darkColor : NdotL <_Threshold2 ? lerp(darkColor, brightColor, tex2D(_TransitionTexture,s.UV * _TransitionTextureSize)) : brightColor;half4 c;c.rgb = ((NdotL * 0.4f)+0.6f) * s.Albedo * _LightColor0 *ShadowColor;c.a = s.Alpha;return c;}void surf (Input IN, inout SurfaceOutputCustom o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.UV = IN.uv_MainTex;o.Albedo = c;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"}Lighting Model - Cartoon Shader Tutorial 14
  • 15. Step 13. Rim Effect PropertiesTo improve the visual appeal of the shader we are going to add some Rim-Lighting.Polygons facing away from the Camera are going to get tinted. Usually this technique isused to simulate backlighting. But we will hijack the effect for our own purpose. Let‘smeet an old friend. The dot product. This time our scalar will reflect the angle betweenthe view Direction and the surface normal. The more a surface is facing away from theviewer the smaller the dot product will become.As usual we will calculate the dot product. We thenmultiply a Color, declared for this purpose, with thisvalue and finally we will output this color in theemission color of the surface.In a later step we will modify the Albedo color basedon the rim lighting so we can even use the rim-effectto darken the rims.Powering the dot product!We will modify the scalar with a pow() function totake control over the dispersion.We need some properties first._RimColorThis will be the color the surface is going to getbe tinted with._RimPowerThe value we are using in pow to flatten ourcurve._RimStrengthHow much of the calculated Color is going to beappliedWhen looking at asphere, the dot product„looks“ like this. Frominner to outerpolygons.We can modify thiscurve using the powfunction_RimColor("Rim Color", Color) = (1,0,0)_RimPower("Rim Position", range(0,3)) = 1_RimStrength("Rim Strength", range(0,1)) = 1Declare these properties in the properties block.And those in our shader code (Bevor the Input struct):half4 _RimColor;half _RimPower;half _RimStrength;Step 2 Getting the view directionWe have to tell Unity to provide a vector containing the view direction first.To do that, we simply modify the input struct. Add „float3 viewDir“ to the Input struct.struct Input {float2 uv_MainTex;float3 viewDir;};From now on, unity will writethe viewdirection to the Inputstruct so we can use it.There is even more data you canadd to your Input. Check out thereference:http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaders.htmlRim Effect- Cartoon Shader Tutorial 15
  • 16. Step 3 Let‘s Rimhalf NdotView = 1 - dot(normalize(IN.viewDir), o.Normal);With the viewdirection ready to use in our Input data, we can start adding code to theSurf function.The first step is to get the dot product between the view direction and the renderedpiece.It‘s very important to normalize the viewDir, because it actually reflects a vector FROMthe rendered piece TO the camera. So probably this vectors magnitude is quite long, orshort. However – to calculate a reasonable dot product we need both vectors to havea magnitude of 1. That‘s exaclty what normalize() does.The 1-dotProduct kind of „inverts“ the value. Meaning: The more the Normal ispointing away from the viewDir the larger our value gets.Facing Away = dot product = 0Facing Towards = dot product = 1The rim-effect should INCREASE when the faces are facing away. So we need anIncreasing value.NdotView = pow(NdotView, _RimPower);According to the last page we „power“-the resulting value to determine the size of therim-effect.o.Emission = NdotView * _RimColor * _RimStrength;Save the shader and go to theeditor. Hopefully it lookssomething like this.This is quite much the effect Iwanted to achieve. Although Iwould like to do a smallimprovment.Right now, we actually cannot doa rim effect which darkens themodel. That‘s because we areapplying the color to the emissionchannel. Which by nature getsmultiplied with the color.Step 4 TestStep 5 Messing with the AlbedoThe way we‘ll be working aroundthis, will be to reduce the albedostrength on faces because theEmission will illuminate theseareays anyway. Change theassignment of the Albedo ColorIn the surf function) to this.o.Albedo = c * ( 1 - NdotView * _RimStrength);Rim Effect - Cartoon Shader Tutorial 16According to the last page we „power“-the resulting value to determine the size of therim-effect.
  • 17. FINAL CODEShader "Custom/CartoonShader" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_BrightColor("Bright Color", Color) = (1,0,0)_Threshold1("Threshold Bright to Dark", range(0,1)) = 0.2_DarkColor("Dark Color", Color) = (0,1,0)_Threshold2("Threshold Middle to Dark", range(0,1)) = 0.9_TransitionTexture("Transition Texture", 2D) = "white" {}_TransitionTextureSize("Transition Texture Size", range(0.1, 50)) = 1_BrightTexture("Bright Color Texture", 2D) = "white"{}_BrightTextureSize("Bright Texture Size", range(0.1,50)) = 1_BrightTextureIntensity("Bright Texture Intensity", range(0.0,1)) = 0.5_DarkTexture("Dark Color Texture", 2D) = "white"{}_DarkTextureSize("Dark Texture Size", range(0.1,50)) = 1_RimColor("Rim Color", Color) = (1,0,0)_RimPower("Rim Position", range(0,4)) = 2_RimStrength("Rim Strength", range(0,1)) = 1}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Cartoonsampler2D _MainTex;sampler2D _TransitionTexture;half4 _BrightColor;half4 _DarkColor;half _Threshold1;half _Threshold2;half _TransitionTextureSize;half _DarkTextureSize;half _BrightTextureSize;half _BrightTextureIntensity;sampler2D _BrightTexture;sampler2D _DarkTexture;half4 _RimColor;half _RimPower;half _RimStrength;struct Input {float2 uv_MainTex;float3 viewDir;};struct SurfaceOutputCustom {fixed3 Albedo;fixed3 Normal;fixed3 Emission;half Specular;fixed Gloss;fixed Alpha;fixed viewFallof;half2 UV;};half4 LightingCartoon(SurfaceOutputCustom s, half3 dir, half attend){dir = normalize(dir);half NdotL = saturate( dot (s.Normal, dir));half4 darkColor = _DarkColor * tex2D(_DarkTexture, s.UV *_DarkTextureSize);half4 brightColor = _BrightColor * ( tex2D(_BrightTexture, s.UV *_BrightTextureSize) * _BrightTextureIntensity + (1-_BrightTextureIntensity));half3 ShadowColor = NdotL < _Threshold1 ? darkColor : NdotL <_Threshold2 ? lerp(darkColor, brightColor, tex2D(_TransitionTexture, s.UV *_TransitionTextureSize)) : brightColor;half4 c;c.rgb = ((NdotL * 0.4f)+0.6f) * s.Albedo * _LightColor0 *ShadowColor;c.a = s.Alpha;return c;}void surf (Input IN, inout SurfaceOutputCustom o) {half4 c = tex2D (_MainTex, IN.uv_MainTex);o.UV = IN.uv_MainTex;half NdotView = 1 - dot(normalize(IN.viewDir), o.Normal);NdotView = pow(NdotView, _RimPower);o.Emission = NdotView * _RimColor * _RimStrength;o.Albedo = c * ( 1 - NdotView * _RimStrength);o.Alpha = c.a;}ENDCG}FallBack "Diffuse"}
  • 18. SourcesDOWNLOADSTutorial Package – the stuff you need to start with this tuorialFinished Tutorial Package – everything is already done Links:The maker of the awesome model we‘re using through the tutorial:http://www.parkparkin.com/Sources - Cartoon Shader Tutorial 18https://dl.dropboxusercontent.com/u/28326381/shader%20tutorial%20final.unitypackagehttps://dl.dropboxusercontent.com/u/28326381/shader%20download%20package.unitypackage