-
课时52 Fragment shader - 边缘泛光shader 1
1.颜色的变换主要由法线N和视向量V有关。
2.代码:
Shader "Custom/Lesson52"
{
//课时52 Fragment shader - 边缘泛光shader 1
Properties{
_Scale("Scale",Range(1,8)) = 2
}
SubShader
{
Tags{"Queue"="Transparent"}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite off //否则交叉部分变黑
Pass
{
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
float _Scale;
struct v2f{
float4 pos:POSITION;
float3 normal:TEXCOORD0;
float4 vertex:TEXCOORD1;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal=v.normal;
o.vertex=v.vertex;
return o;
}
fixed4 frag (v2f IN):COLOR
{
float3 N=normalize(UnityObjectToWorldNormal(IN.normal));
float3 V=normalize(WorldSpaceViewDir(IN.vertex));// UnityWorldSpaceViewDir(IN.vertex);
float bright=1-saturate(dot(N,V));
bright=pow(bright,_Scale);
return fixed4(1,1,1,1)*bright;
}
ENDCG
}
}
}
效果:
-
课时53 Fragment shader - 边缘泛光shader 2
1.使用多个Pass通道融合的方式,实现外边缘泛光效果。blend操作说明见:ShaderLab: Blending
2.第一个通道沿着法线向外延展n个像素,渲染从内向外发光效果,设置混合模式为叠加;第二个通道不扩展像素,只渲染纯白色,设置令第一个通道结果减去第二通道结果;第三个通道不扩展像素,渲染从外向内发光效果,设置混合模式为叠加。
3.代码:
Shader "Custom/Lesson53"
{
//课时53 Fragment shader - 边缘泛光shader 2
Properties{
_MainColor("MainColor",Color)=(1,1,1,1)
_Scale("Scale",Range(1,8)) = 2
_Outer("Outer",range(0,1))=0.2
}
SubShader
{
Tags{"Queue"="Transparent"}
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
ZWrite off //否则交叉部分变黑
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _MainColor;
float _Scale;
float _Outer;
struct v2f{
float4 pos:POSITION;
float3 normal:TEXCOORD0;
float4 vertex:TEXCOORD1;
};
v2f vert (appdata_base v)
{
v.vertex.xyz+=v.normal*_Outer;
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal=v.normal;
o.vertex=v.vertex;
return o;
}
fixed4 frag (v2f IN):COLOR
{
float3 N=normalize(UnityObjectToWorldNormal(IN.normal));
float3 V=normalize(WorldSpaceViewDir(IN.vertex));// UnityWorldSpaceViewDir(IN.vertex);
float bright=saturate(dot(N,V));
bright=pow(bright,_Scale);
_MainColor.a*=bright;
return _MainColor;
}
ENDCG
}
//=======================第二通道==================================
Pass
{
BlendOp revsub //反转减法,即用目标(已渲染)减掉源(本通道)
Blend DstAlpha One //目标乘以1,源乘以目标的Alpha(然后相减)
ZWrite off //否则交叉部分变黑
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
struct v2f{
float4 pos:POSITION;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f IN):COLOR
{
return float4(1,1,1,1);
}
ENDCG
}
//========================第三通道=================================
Pass
{
// Blend zero one
Blend SrcAlpha OneMinusSrcAlpha
ZWrite off //否则交叉部分变黑
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
float _Scale;
struct v2f{
float4 pos:POSITION;
float3 normal:TEXCOORD0;
float4 vertex:TEXCOORD1;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.normal=v.normal;
o.vertex=v.vertex;
return o;
}
fixed4 frag (v2f IN):COLOR
{
float3 N=normalize(UnityObjectToWorldNormal(IN.normal));
float3 V=normalize(WorldSpaceViewDir(IN.vertex));// UnityWorldSpaceViewDir(IN.vertex);
float bright=1-saturate(dot(N,V));
bright=pow(bright,_Scale);
return fixed4(1,1,1,1)*bright;
}
ENDCG
}
}
}
效果:
-
课时54 Fragment shader - 片段级模型动态变色 1
1.需求:实现模型上下部分不同颜色,界限分明的效果。
2.代码:
Shader "Custom/Lesson54"
{
//课时54 Fragment shader - 片段级模型动态变色 1
Properties{
_MainColor("MainColor",Color)=(1,1,1,1)
_SecondColor("SecondColor",Color)=(1,1,1,1)
_Center("Center",Range(-0.5,0.5))=0
}
SubShader
{
Pass
{
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _MainColor;
fixed4 _SecondColor;
float _Center;
struct v2f{
float4 pos:POSITION;
float y:TEXCOORD0;//建议不要使用COLOR语义,否则可能舍弃负数
};
v2f vert (appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
// if(v.vertex.y<0)
// {
// o.col=_MainColor;
// }else
// {
// o.col=_SecondColor;
// }
o.y=v.vertex.y;
return o;
}
fixed4 frag (v2f IN):COLOR
{
fixed4 col=(0,0,0,0);
if(IN.y>_Center)
{
col=_MainColor;
}else
{
col=_SecondColor;
}
return col;
}
ENDCG
}
}
}
效果:
-
课时55 Fragment shader - 片段级模型动态变色 2
1.需求:在上个需求基础上,增加融合范围。
2.代码:
Shader "Custom/Lesson55"
{
//课时55 Fragment shader - 片段级模型动态变色 2
Properties{
_MainColor("MainColor",Color)=(1,1,1,1)
_SecondColor("SecondColor",Color)=(1,1,1,1)
_Center("Center",Range(-0.7,0.7))=0
_R("R",Range(0,0.5))=0.2
}
SubShader
{
Pass
{
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _MainColor;
fixed4 _SecondColor;
float _Center;
float _R;
struct v2f{
float4 pos:POSITION;
float y:TEXCOORD0;//建议不要使用COLOR语义,否则可能舍弃负数
};
v2f vert (appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.y=v.vertex.y;
return o;
}
fixed4 frag (v2f IN):COLOR
{
float d=IN.y-_Center;//-0.5~0.5 原始区间
float s=abs(d);//0~0.5 原始绝对区间
d=d/s;//-1,1 正负号
float f=s/_R;//0~1.x
f=saturate(f);//0~1 缩减绝对区间
d*=f;//-f,f 给绝对区间加正负号
d=d/2+0.5;//变换至0~1区间
return lerp(_MainColor,_SecondColor,d);
}
fixed4 frag333 (v2f IN):COLOR
{
fixed4 col=(0,0,0,0);
if(IN.y>_Center+_R)
{
col=_MainColor;
}else if(IN.y>_Center&&IN.y<_Center+_R)
{
float d=IN.y-_Center;//0~_R
d=d/_R/2+0.5;//0.5~1
col=lerp(_SecondColor,_MainColor,d);
}else if(IN.y<_Center&&IN.y>_Center-_R)
{
float d=-IN.y+_Center;
d=d/_R/2+0.5;//0.5~1
col=lerp(_MainColor,_SecondColor,d);
}else
{
col=_SecondColor;
}
return col;
}
fixed4 frag222 (v2f IN):COLOR
{
fixed4 col=(0,0,0,0);
float d=IN.y-_Center;//范围-1~1
d=d/abs(d);//范围-1,1
d=d/2+0.5;//范围0,1
col=lerp(_MainColor,_SecondColor,d);
return col;
}
fixed4 frag111 (v2f IN):COLOR
{
fixed4 col=(0,0,0,0);
if(IN.y>_Center)
{
col=_MainColor;
}else
{
col=_SecondColor;
}
return col;
}
ENDCG
}
}
}
效果:
-
课时56 Fragment shader - 片段级模型动态变色 3
1.Unity内模型面数超过65534个会自动分割出几个子模型。这个案例中,车身模型被分成3个,子模型的坐标原点位置和朝向是一致的,即在一个坐标空间内,所以可以不考虑模型拆分问题。
2.需求:使车身模型在x轴向上分成两种颜色。
3.首先计算出模型在x轴向上的值范围:求得范围±0.05。由此得出最大融合半径=0.05*2*0.2=0.02。中心范围±0.07。
/// <summary>
/// 求得mesh内位于X轴向上,最大和最小值。模型缩放不影响结果。
/// </summary>
/// <param name="mf">网格</param>
private void checkVertex(MeshFilter mf)
{
Vector3[] verts = mf.mesh.vertices;
float max = verts.Max(v => v.x);
float min = verts.Min(v => v.x);
Debug.Log("最大==" + max);
Debug.Log("最小==" + min);
}
4.修改上节课shader为y轴向
Shader "Custom/Lesson56"
{
//课时56 Fragment shader - 片段级模型动态变色 3
Properties{
_MainColor("MainColor",Color)=(1,1,1,1)
_SecondColor("SecondColor",Color)=(1,1,1,1)
_Center("Center",Range(-0.07,0.07))=0
_R("R",Range(0,0.02))=0.001
}
SubShader
{
Pass
{
CGPROGRAM
#include "unitycg.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _MainColor;
fixed4 _SecondColor;
float _Center;
float _R;
struct v2f{
float4 pos:POSITION;
float x:TEXCOORD0;//建议不要使用COLOR语义,否则可能舍弃负数
};
v2f vert (appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.x=v.vertex.x;
return o;
}
fixed4 frag (v2f IN):COLOR
{
float d=IN.x-_Center;//-0.5~0.5 原始区间
float s=abs(d);//0~0.5 原始绝对区间
d=d/s;//-1,1 正负号
float f=s/_R;//0~1.x
f=saturate(f);//0~1 缩减绝对区间
d*=f;//-f,f 给绝对区间加正负号
d=d/2+0.5;//变换至0~1区间
return lerp(_MainColor,_SecondColor,d);
}
ENDCG
}
}
}
5.效果:
6.进一步改进为Surfaceshader。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/Lesson56"
{
//课时56 Fragment shader - 片段级模型动态变色 3
Properties{
_MainColor("MainColor",Color)=(1,1,1,1)
_SecondColor("SecondColor",Color)=(1,1,1,1)
_Center("Center",Range(-0.07,0.07))=0
_R("R",Range(0,0.02))=0.001
_Glossiness("Smoothness",Range(0,1))=0
_Metallic("Metallic",Range(0,1))=0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
//等同于:pragma surface surf Standard vertex:vert fullforwardshadows
//有时会不识别vert函数,但不报错
#pragma surface surf Standard fullforwardshadows vertex:vert
#pragma target 3.0
sampler2D _MainTex;
fixed4 _MainColor;
fixed4 _SecondColor;
float _Center;
float _R;
half _Glossiness;
half _Metallic;
//surfaceshader的Input声明可以不加语义
struct Input{
float2 uv_MainTex;
float x;//可省略TEXCOORD0语义
};
void vert(inout appdata_full v,out Input o)
{
o.uv_MainTex=v.texcoord.xy;
o.x=v.vertex.x;
// v.vertex=UnityObjectToClipPos(v.vertex);
}
void surf(Input IN,inout SurfaceOutputStandard o){
fixed4 c=tex2D(_MainTex,IN.uv_MainTex);
o.Albedo=c.rgb;
o.Metallic=_Metallic;
o.Smoothness=_Glossiness;
o.Alpha=c.a;
float d=IN.x-_Center;//-0.5~0.5 原始区间
float s=abs(d);//0~0.5 原始绝对区间
d=d/s;//-1,1 正负号
float f=s/_R;//0~1.x
f=saturate(f);//0~1 缩减绝对区间
d*=f;//-f,f 给绝对区间加正负号
d=d/2+0.5;//变换至0~1区间
o.Albedo.rgb *= lerp(_MainColor,_SecondColor,d)*2;
}
ENDCG
}
Fallback "Diffuse"
}
效果:
-
课时57 Fragment shader - 2D纹理采样 1
1.图片的Wrap Mode设置分为:Repeat和Clamp,Repeat表示超出0~1采样区间采用平铺,可以用于平铺材质,Clamp表示超出后用最边缘像素填充。
2.图片的Filter Mode设置分为:No Filter(无过滤)就近点采样,Bilinear(双线性过滤)临近四个点插值采样,Trilinear(三线性过滤)三线性和双线性的差别在于三线性可以根据mip maps的变化来。
3.代码:
Shader "Custom/Lesson57"
{
//课时57 Fragment shader - 2D纹理采样 1
Properties{
_MainTex("MainTex",2D)="white"{}
_U("U",Range(-0.01,0.01))=0
}
SubShader
{
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float2 uv_MainTex;
float _U;
struct v2f{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=v.texcoord.xy;
return o;
}
fixed4 frag(v2f IN):COLOR
{
fixed4 color=tex2D(_MainTex,IN.uv);
return color;
}
ENDCG
}
}
Fallback "Diffuse"
}
效果:未实现Tiling和Offset功能。
-
课时58 Fragment shader - 2D纹理采样 2
1.需求:启用图片的平铺和偏移变换功能。
2.注意知识点:非表面Shader,需要声明图片变换属性name_ST,顶点函数中使用宏TRANSFORM_TEX(o.texcoord,name)得到uv值,片元函数中调用tex2D(name,IN.uv)。表面Shader,在Input结构体中声明uv_name,在surface函数中调用tex2D(name,IN.uv_name)
3.代码
Shader "Custom/Lesson58"
{
//课时58 Fragment shader - 2D纹理采样 2
Properties{
_MainTex("MainTex",2D)="white"{}
}
SubShader
{
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
//在片元函数中,纹理坐标对应uv_MainTex,并且声明在Input结构体内,直接在片元中调用tex2D(_Maintex,IN.uv_MainTex)
//在TRANSFORM_TEX宏中显式用到_MainTex,隐式用到_MainTex_ST,后在片元中调用tex2D(_Maintex,o.uv)
float4 _MainTex_ST;
// float tiling_x=1;
// float tiling_y=1;
// float offset_x;
// float offset_y;
struct v2f{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
//相当于 o.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
o.uv=TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f IN):COLOR
{
fixed4 color=tex2D(_MainTex,IN.uv);
return color;
}
ENDCG
}
}
Fallback "Diffuse"
}
效果:
-
课时59 Fragment shader - 2D纹理采样 3
1.搭建待烘焙场景,灯光设为baked模式,模型设为lightmap static。Lighting-Scene-EnvironmentLighting-Ambient GI设为Baked,然后点积生成光照贴图。
2.然后使用第58课的shader,显示下面的效果。要求能够支持光照贴图。
3.Unity官方文档,见Rendering Optimizations
4.代码:
// Upgrade NOTE: commented out 'float4 unity_LightmapST', a built-in variable
// Upgrade NOTE: commented out 'sampler2D unity_Lightmap', a built-in variable
// Upgrade NOTE: commented out 'float4 unity_LightmapST', a built-in variable
// Upgrade NOTE: commented out 'sampler2D unity_Lightmap', a built-in variable
// Upgrade NOTE: replaced tex2D unity_Lightmap with UNITY_SAMPLE_TEX2D
Shader "Custom/Lesson59"
{
//课时59 Fragment shader - 2D纹理采样 3
Properties{
_MainTex("MainTex",2D)="white"{}
}
SubShader
{
pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
//unity会自动传参,新版Unity不需重复声明
// sampler2D unity_Lightmap;
//对应unity_Lightmap,新版Unity不需重复声明
// float4 unity_LightmapST;
float4 _MainTex_ST;
struct v2f{
float4 pos:POSITION;
float2 uv:TEXCOORD0;
float2 uv2:TEXCOORD1;
};
v2f vert(appdata_full v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=TRANSFORM_TEX(v.texcoord, _MainTex);
o.uv2=v.texcoord1*unity_LightmapST.xy+unity_LightmapST.zw;
return o;
}
fixed4 frag(v2f IN):COLOR
{
//先对颜色贴图采样,再解码
float3 lm=DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap,IN.uv2));
fixed4 color=tex2D(_MainTex,IN.uv);
color.rgb*=lm*1.5;
return color;
}
ENDCG
}
}
Fallback "Diffuse"
}
效果:比标准着色器效果偏蓝