UnityShader实例05:Toon(卡通)材质
来源:互联网 发布:linux 杀死oracle进程 编辑:程序博客网 时间:2024/04/27 22:54
卡通材质
卡通着色也叫Non-photorealisticrendering非真实渲染,通常一些3D游戏用来做一些卡通风格的游戏,一般来说特点主要有两点,一是描边,二是风格化着色,表现为明暗渐变过渡为非线性梯度着色。如下图所示:火影忍者和无主之地
先做描边
关于描边网上有不少资料,这里就其中比较常用的Rim lighting和法线外拓来实现;
1.Rim lighting
原理在之前XRAY材质有提到过,通过视线和物体法线夹角的点积来获得轮廓。只不过这里我需要做一个线条比较硬一点的描边,因此需要对获取到的轮廓做个取整:
i.color=floor(i.color*2);另外外轮廓的颜色需要做lerp处理而不是乘法叠加,否则黑色叠上去是看不到的;
col=lerp(col,i.color*_OutlineColor,i.color);
VF版本代码01:
Shader "PengLu/Toon/OutlineOnePassVF" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_OutlineColor("OutlineColor",Color) = (0,1,1,1)_RimPower ("Rim Power", Range(0.1,8.0)) = 2}SubShader {Tags { "Queue"="Geometry" "RenderType"="Opaque" }LOD 200Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float4 _OutlineColor;float _RimPower;sampler2D _MainTex;float4 _MainTex_ST;struct appdata_t {float4 vertex : POSITION;float2 texcoord : TEXCOORD0;float4 color:COLOR;float4 normal:NORMAL;};struct v2f {float4 pos : SV_POSITION;float2 texcoord : TEXCOORD0;float4color:COLOR;} ;v2f vert (appdata_t v){v2f o;o.pos = mul(UNITY_MATRIX_MVP,v.vertex);o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);float3 viewDir = normalize(ObjSpaceViewDir(v.vertex)); float rim = 1 - saturate(dot(viewDir,v.normal )); o.color = pow(rim,_RimPower);return o;}float4 frag (v2f i) : COLOR{fixed4 col = tex2D(_MainTex, i.texcoord);i.color=floor(i.color*2);col=lerp(col,i.color*_OutlineColor,i.color);return col; }ENDCG}} FallBack "Diffuse"}VF版本代码01效果:
主要方法是在shader里面用两个pass渲染物体两次,第一个pass顶点外拓,用来打底作为描边,第二个pass正常渲染物体。下面这个例子做了一些改良:分别从顶点和法线方向挤出,然后做判断进行插值。
第一个pass作如下处理:
Cull Front 裁剪了物体的前面(对着相机的),把背面挤出
ZWrite On 像素的深度写入深度缓冲,如果关闭的话,物体与物体交叠处将不会被描边,因为此处无z值后渲染的物体会把此处挤出的描边“盖住”
在处理顶点的函数vert中把点挤出
float3 dir=normalize(v.vertex.xyz);建立一个float3方向变量dir,把该点的位置作为距离几何中心的方向的单位向量
float3 dir2=v.normal;dir2为法线方向
D=dot(dir,dir2);D为计算该点位置朝向和法线方向的点积,通过正负值可以确定是指向还是背离几何中心的,正为背离,负为指向
dir=dir*sign(D);乘上正负值,真正的方向值
dir=dir*_Factor+dir2*(1-_Factor);把该点位置朝向与法线方向按外部变量_Factor的比重混合,来控制挤出多远
v.vertex.xyz+=dir*_Outline;把物体背面的点向外挤出
v2f vert (appdata_full v) {v2f o;float3 dir=normalize(v.vertex.xyz);float3 dir2=v.normal;float D=dot(dir,dir2);dir=dir*sign(D);//dir=dir*_Factor+dir2*(1-_Factor);dir=lerp(dir,dir2,_Factor);v.vertex.xyz+=dir*_Outline;o.pos=mul(UNITY_MATRIX_MVP,v.vertex);return o;}
接下来在frag里面给描边上色
float4 frag(v2f i):COLOR{float4 c = _OutlineColor;return c;}
第二个pass正常渲染不做修改
VF版本代码02:
//one directional lightShader "PengLu/Toon/ToonOneLightVF" {Properties {_Color("Main Color",color)=(1,1,1,1)_OutlineColor("Outline Color",color)=(0.1,0.1,0.2,1)_MainTex ("Base (RGB)", 2D) = "white" {}_Outline("Thick of Outline",range(0,0.1))=0.01_Factor("Factor",range(0,1))=0.5_ToonEffect("Toon Effect",range(0,1))=0.5_Steps("Steps of toon",range(0,9))=3}SubShader {pass{Tags{"LightMode"="Always"}Cull FrontZWrite OnCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float _Outline;float _Factor;float4 _Color,_OutlineColor;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);dir=dir*sign(D);//dir=dir*_Factor+dir2*(1-_Factor);dir=lerp(dir,dir2,_Factor);v.vertex.xyz+=dir*_Outline;o.pos=mul(UNITY_MATRIX_MVP,v.vertex);return o;}float4 frag(v2f i):COLOR{float4 c = _OutlineColor;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;sampler2D _MainTex;float4 _MainTex_ST;struct v2f {float4 pos:SV_POSITION;float3 lightDir:TEXCOORD0;float3 viewDir:TEXCOORD1;float3 normal:TEXCOORD2;float2 texcoord:TEXCOORD3;};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);o.texcoord=TRANSFORM_TEX(v.texcoord, _MainTex);return o;}float4 frag(v2f i):COLOR{float4 c=1;float3 N=normalize(i.normal);float diff=max(0,dot(N,i.lightDir));diff=(diff+1)/2;diff=smoothstep(0,1,diff);float toon=floor(diff*_Steps)/_Steps;diff=lerp(diff,toon,_ToonEffect);c=_Color*_LightColor0*(diff);c*=tex2D(_MainTex, i.texcoord);return c;}ENDCG}} }
VF版本代码02效果
1.floor函数去整离散着色
卡通着色主要是frag函数里面处理
要做梯度着色,需要有渐变,因此需要先实现漫反射颜色
float3 N=normalize(i.normal);float diff=max(0,dot(N,i.lightDir));求出正常的漫反射颜色
diff=(diff+1)/2;
因为只有一个直射光没考虑环境光和其他光的,因此需要做亮化处理把暗部提亮。
diff=smoothstep(0,1,diff);使颜色平滑的在[0,1]范围之内
float toon=floor(diff*_Steps)/_Steps;把颜色做离散化处理,把diffuse颜色限制在_Steps种(_Steps阶颜色),简化颜色,这样的处理使色阶间能平滑的显示
diff=lerp(diff,toon,_ToonEffect);通过控制卡通化程度值_ToonEffect,调节卡通与写实的比重
VF版本代码03:
Shader "PengLu/Toon/ToonOnePassVF" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_OutlineColor("OutlineColor",Color) = (0,1,1,1)_RimPower ("Rim Power", Range(0.1,8.0)) = 2_ToonEffect("Toon Effect",range(0,1))=0.5_Steps("Steps of toon",range(0,9))=3}SubShader {Tags { "Queue"="Geometry" "RenderType"="Opaque" }LOD 200Pass{Tags{"LightMode"="ForwardBase"}Cull BackCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float4 _OutlineColor;float _RimPower;float4 _LightColor0;float _Steps;float _ToonEffect;sampler2D _MainTex;float4 _MainTex_ST;struct v2f {float4 pos : SV_POSITION;float3 lightDir:TEXCOORD0;float3 viewDir:TEXCOORD1;float3 normal:TEXCOORD2;float2 texcoord:TEXCOORD3;float4color:COLOR;} ;v2f vert (appdata_full v){v2f o;o.pos = mul(UNITY_MATRIX_MVP,v.vertex);o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);o.normal=v.normal;o.lightDir=normalize(ObjSpaceLightDir(v.vertex));o.viewDir=normalize(ObjSpaceViewDir(v.vertex)); float rim = 1 - saturate(dot(o.viewDir,v.normal )); o.color = pow(rim,_RimPower);return o;}float4 frag (v2f i) : COLOR{fixed4 col = tex2D(_MainTex, i.texcoord);//i.color=smoothstep(0,1,i.color*2);i.color=floor(i.color*2);col=lerp(col,i.color*_OutlineColor,i.color);float3 N=normalize(i.normal);float diff=max(0,dot(N,i.lightDir));diff=(diff+1)/2;diff=smoothstep(0,1,diff);float toon=floor(diff*_Steps)/_Steps;diff=lerp(diff,toon,_ToonEffect);col*=_LightColor0*(diff);return col; }ENDCG}} FallBack "Diffuse"}VF版本代码03效果:
2.RampMap 采样着色
RampMap采样着色是通过映射一张一维纹理(如下图)来实现卡通化着色,相对floor函数,RampMap映射方式比较容易控制卡通效果,美术师只需修改贴图就能修改卡通渐变的过渡等效果。
RampMap映射的代码基本和floor函数方式相同,只有离散方式不同,关键代码如下:
float toon=tex2D(_ToonMap,float2(diff,0.5)).r;将diff作为uv坐标在贴图上u方向查询获得对应的颜色。
VF版本代码04:
//one directional lightShader "PengLu/Toon/ToonRampMapVF" {Properties {_Color("Main Color",color)=(1,1,1,1)_OutlineColor("Outline Color",color)=(0.1,0.1,0.2,1)_MainTex ("BaseTex", 2D) = "white" {}_ToonMap("Ramp Map",2D)="white"{}_Outline("Thick of Outline",range(0,0.1))=0.02_Factor("Factor",range(0,1))=0.5_ToonEffect("Toon Effect",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 _OutlineColor;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);dir=dir*sign(D);dir=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=_OutlineColor;return c;}ENDCG}//end of passpass{Tags{"LightMode"="ForwardBase"}Cull BackCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _ToonMap;sampler2D _MainTex;float4 _MainTex_ST;float4 _LightColor0;float4 _Color;float _ToonEffect;struct v2f {float4 pos:SV_POSITION;float3 lightDir:TEXCOORD0;float3 normal:TEXCOORD1;float2 texcoord: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.texcoord=TRANSFORM_TEX(v.texcoord, _MainTex);return o;}float4 frag(v2f i):COLOR{float4 c=1;float3 N=normalize(i.normal);float3 lightDir=normalize(i.lightDir);float diff=max(0,dot(N,lightDir));diff=(diff+1)/2;diff=smoothstep(0,1,diff);float toon=tex2D(_ToonMap,float2(diff,0.5)).r;diff=lerp(diff,toon,_ToonEffect);c=_Color*_LightColor0*(diff);c*=tex2D(_MainTex,i.texcoord);return c;}ENDCG}} }
VF版本代码04效果:
- UnityShader实例05:Toon(卡通)材质
- unity中Toon(卡通)材质的下载与实现
- UnityShader实例10:广告牌(Billboard)材质
- UnityShader实例10:广告牌(Billboard)材质
- 卡通渲染(Toon Shading/Cel Shading)
- Unityshader实例01:冰块材质
- Unityshader实例02:Xray材质
- UnityShader实例11:积雪材质
- UnityShader实例18:火焰材质
- UnityShader实例:遮挡透明材质
- UnityShader实例08:溶解消融(Dissolve)材质
- UnityShader实例12:屏幕特效之马赛克(Mosaic)材质
- 卡通(Toon)着色
- Shader toon 卡通效果
- UnityShader实例03:边缘光材质
- UnityShader实例04:遮挡透明材质
- UnityShader实例04:遮挡透明材质
- 【Unity】Unity自带卡通shader(toon shader)分析(一)
- java 中xml转换为json对象
- 全文检索引擎Solr系列—–全文检索基本原理
- iOS判断是否是中文或者英文
- 文章标题
- sqlserver生成有序唯一标示
- UnityShader实例05:Toon(卡通)材质
- GridControl 选择列、复选框全选(下)
- 为PopupWindow设置动画效果
- Zookeeper 安装和配置
- webService之(四)CXF客户端
- 不锈钢雕塑马价格-曲阳不锈钢雕塑生产厂-曲阳县金铭雕塑品有限公司
- gre阅读题材:新GRE阅读内容题材涉及哪些方面
- 分享,支付,地图
- poj 1694 An Old Stone Game 树形dp