卡通渲染的主要原理包含两个方面:

1.轮廓线的描边效果

2.模型漫反射离散和纯色高光区域的模拟

描边

描边的实现方法采用将模型的轮廓线顶点向法线(或顶点)的方向扩展一定的像素得到。也可通过边缘检测(基于法线和深度)来实现。

漫反射离散

利用离散的Ramp纹理对漫反射光照效果进行采样,可以实现不同效果梯度的卡通渲染效果,例如:

注意此纹理的灰度变化并非均匀变化,而是类似于一种突变,仅在灰度变化的交界处进行了平滑过渡。这样的Ramp纹理正是卡通渲染所需要的颜色过渡模式,也是卡通渲染实现的核心内容。

也可增加阶度的个数实现更多层次的卡通渲染效果。

纯色高光区域

不同于真实渲染,卡通渲染的高光部分通常就是一个色块,这里主要的问题是处理高光边缘的锯齿问题。

这里可以利用smoothstep(-w,w,spec-threshold);在边缘范围[-w,w]进行平滑插值处理,其中w可以通过fwidth(spec);得到。

fwidth(spec);用于得到邻域像素的近似导数值。

Shader脚本如下,光照模型采用半兰伯特:

 Shader "MyUnlit/CartoonShading"
{
Properties
{
_Color("Color Tint",Color)=(,,,)
_MainTex ("Texture", 2D) = "white" {}
_Ramp("Ramp Texture",2D)="white"{}
_Outline("Outline",Range(,0.1))=0.02
_Factor("Factor of Outline",Range(,))=0.5
_OutlineColor("Outline Color",Color)=(,,,)
_Specular("Specular",Color)=(,,,)
_SpecularScale("Specular Scale",Range(,0.1))=0.01
}
SubShader
{
Tags { "RenderType"="Opaque" }
//此Pass渲染描边
Pass
{
//命名用于之后可重复调用
NAME "OUTLINE"
//描边只用渲染背面,挤出轮廓线,所以剔除正面
Cull Front
//开启深度写入,防止物体交叠处的描边被后渲染的物体盖住
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag #include "UnityCG.cginc" float _Outline;
float _Factor;
fixed4 _OutlineColor; struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
}; struct v2f
{
float4 vertex : SV_POSITION;
}; v2f vert (appdata v)
{
v2f o;
float3 pos=normalize(v.vertex.xyz);
float3 normal=normalize(v.normal); //点积为了确定顶点对于几何中心的指向,判断此处的顶点是位于模型的凹处还是凸处
float D=dot(pos,normal);
//校正顶点的方向值,判断是否为轮廓线
pos*=sign(D);
//描边的朝向插值,偏向于法线方向还是顶点方向
pos=lerp(normal,pos,_Factor);
//将顶点向指定的方向挤出
v.vertex.xyz+=pos*_Outline;
o.vertex=UnityObjectToClipPos(v.vertex);
return o;
} fixed4 frag (v2f i) : SV_Target
{
return fixed4(_OutlineColor.rgb,);
}
ENDCG
}
//此Pass渲染卡通着色效果,主要运用半兰伯特光照模型配合渐变纹理
Pass
{
Tags{"LightMode"="ForwardBase"}
Cull Back
CGPROGRAM #pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase #include "UnityCG.cginc"
//引入阴影相关的宏
#include "AutoLight.cginc"
//引入预设的光照变量,如_LightColor0
#include "Lighting.cginc" fixed4 _Color;
sampler2D _MainTex;
sampler2D _Ramp;
fixed4 _Specular;
fixed _SpecularScale;
float4 _MainTex_ST; struct appdata
{
float4 vertex:POSITION;
float2 uv:TEXCOORD0;
float3 normal:NORMAL;
float4 tangent:TANGENT;
}; struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
SHADOW_COORDS()
}; v2f vert(appdata v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=TRANSFORM_TEX(v.uv,_MainTex);
o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
o.worldPos=mul(unity_ObjectToWorld,v.vertex);
TRANSFER_SHADOW(o); return o;
} fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal=normalize(i.worldNormal);
fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldViewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 worldHalfDir=normalize(worldLightDir+worldViewDir); //计算材质反射率
fixed4 c=tex2D(_MainTex,i.uv);
fixed3 albedo=c.rgb*_Color.rgb; //计算环境光
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo; //处理阴影
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos); //计算半兰伯特漫反射系数,亮化处理,将结果从[-1,1]映射到[0,1],以便作为渐变纹理的采样uv
fixed diff=dot(worldNormal,worldLightDir);
diff=(diff*0.5+0.5)*atten; //卡通渲染的核心内容,对漫反射进行区域色阶的离散变化
fixed3 diffuse=_LightColor0.rgb*albedo*tex2D(_Ramp,float2(diff,diff)).rgb; //计算半兰伯特高光系数,并将高光边缘的过渡进行抗锯齿处理,系数越大,过渡越明显
fixed spec=dot(worldNormal,worldHalfDir);
fixed w=fwidth(spec)*3.0; //计算高光,在[-w,w]范围内平滑插值
fixed3 specular=_Specular.rgb*smoothstep(-w,w,spec-(-_SpecularScale))*step(0.0001,_SpecularScale); return fixed4(ambient+diffuse+specular,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}

效果如下:

Unity Shader NPR 卡通渲染的更多相关文章

  1. shader forge卡通渲染!

    自从用了shader forge,妈妈我再也不写shader了...... 写了3种,分别用的顶点法线.法线贴图.顶点法线+法线贴图,然后还有自发光和受光两种模式,那就是6种了吧... 最后来一张sh ...

  2. 【转】《Unity Shader入门精要》冯乐乐著 书中彩图

    为方便个人手机学习时候查阅,从网上转来这些彩图. 如属过当行为,联系本人删除. 勘错表 http://candycat1992.github.io/unity_shaders_book/unity_s ...

  3. Unity Shader 知识点总结(一)

    在学习了一段时间的Unity Shader后,打算写一些知识总结,便于今后的查找.如有错误,希望大家指出更改. 本文参照的unity入门精要一书,做一个知识归纳,如有兴趣可以看看其开源的部分,是一本比 ...

  4. 【Unity Shader】Shader基础

    目录 Chapter3 Unity Shader 基础 Chapter3 Unity Shader 基础 概述 在Unity需要材质(Material)与Unity Shader配合使用来达到满意的效 ...

  5. Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础

    来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...

  6. Unity Shader 卡通渲染 基于退化四边形的实时描边

    从csdn转移过来,顺便把写过的文章改写一下转过来. 一.边缘检测算法 3D模型描边有两种方式,一种是基于图像,即在所有3D模型渲染完成一张图片后,对这张图片进行边缘检测,最后得出描边效果.一种是基于 ...

  7. 【Unity Shader】Unity Chan的卡通材质

    写在前面 时隔两个月我终于来更新博客了,之前一直在学东西,做一些项目,感觉没什么可以分享的就一直没写.本来之前打算写云彩渲染或是Compute Shader的,觉得时间比较长所以打算先写个简单的. 今 ...

  8. 【NPR】卡通渲染

    写在前面 我的博客讲过好几篇卡通渲染了,比如[Unity Shader实战]卡通风格的Shader(一).[Unity Shader实战]卡通风格的Shader(二).[NPR]漫谈轮廓线的渲染.[S ...

  9. Unity Shader入门精要学习笔记 - 第14章非真实感渲染

    转载自 冯乐乐的 <Unity Shader 入门精要> 尽管游戏渲染一般都是以照相写实主义作为主要目标,但也有许多游戏使用了非真实感渲染(NPR)的方法来渲染游戏画面.非真实感渲染的一个 ...

随机推荐

  1. XML与DTD(够用)

    1: 概述 1.1 什么是XML 1.2 三个重点 1.3规则 1.4 常用转义 2: Xml声明 XML 中,空格会被保留 XML 以 LF 存储换行 3:Xml标签 4:Xml元素 5:XML 属 ...

  2. flex——justify-content属性引起的一个样式问题

     前言  在flex布局出现以前,我一般习惯使用浮动布局(float)来实现下列布局   现在尽量少用浮动布局,虽然好用,但有时会带来一些意想不到的问题,甚至导致布局错位,   一开始浮动布局只是为了 ...

  3. 为何我建议1-3年的Java程序员仔细看看这篇文章

    此文的目的是为了督促自己去不断学习,让自己有更明确的方向去提升自己.以技能树为基础,以面试要点为大纲,我觉得比抓住什么看什么要更有目的,更能坚持下去.世界瞬息万变,我们要时刻准备着.时刻提高着自己,才 ...

  4. 【CF933E】A Preponderant Reunion(动态规划)

    [CF933E]A Preponderant Reunion(动态规划) 题面 CF 洛谷 题解 直接做很不好搞,我们把条件放宽,我们每次可以选择两个相邻的非零数让他们减少任意值,甚至可以减成负数(虽 ...

  5. Docker - 快速入门(一)

    概念 下面这三个概念一开始可能不好理解,等大家跟着博客把例子做完了,再回头来看应该就能理解了. docker image  # docker镜像 镜像就是一个只读的模板.镜像可以用来创建Docker容 ...

  6. 【趣学程序】Linux上安装Tengine(Nginx)

    linux 安装tengine tengine是什么 tengine是由淘宝网发起的Web服务器项目.它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性.Tengine的性能和稳 ...

  7. Dynamics CRM定制子网格添加按钮实例之二:调试代码、打开Web资源及获取选择的记录

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复222或者20160501可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  8. 11. ==和equals方法 & 常量池

    一.使用==来判断两个变量是否相等 1. 如果两个变量是基本类型变量,且都是数值类型,则只要两个变量的值相等,就将返回true 2. 如果两个变量是引用类型变量,则只有它们指向同一个对象时,才返回tr ...

  9. nginx代理ambassador,再转到mlfow-tracking服务

    这个服务的代理,相对于服务网关来说,有些典型, 今天调通了,作个记录. 一,nginx配置 upstream ai_ambassador { ip_hash; server 1.2.3.4:30080 ...

  10. OpenGL基础代码整理

    3-1:画点,连成线 // OPENGL.cpp : Defines the entry point for the console application. // #include "st ...