1.遮罩的意义,就是让某个颜色的部分透明,其他的不透明。
实现思路很简单,但如果你是从这个系列一步一步上学过来的,那肯定很简单啦
1.1我们先定义一个标准Shader,然后慢慢改
Shader "Custom/Mask001" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
关于surf函数,起点,和终点的问题,在前面有过介绍。但是这里我们不喜欢用这玩意。删掉。我们还是两个过程
1.顶点着色
2.片元着色
1.2 我们先改出一个简单的渲染流水线。
Shader "Custom/Mask001" {
Properties {
//遮罩图
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
Pass{
CGPROGRAM
//定义顶点着色器
#pragma vertex vertex
//定义片元着色器
#pragma fragment fragment
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
//CG变量的遮罩图,你可以调用这个变量的数据,并通过前面章节提供的函数进行采样
sampler2D _MainTex;
//来自于cpu的数据模型
struct fromCpu {
//传入的mesh的基本组成:顶点和UV
};
//来自顶点着色器的数据模型
struct v2f {
//传入的mesh的基本组成:顶点和UV
};
//运行顶点着色器,输入data数据,输出计算后的数据。注意流水线
v2f vertex(fromCpu data) {
}
//运行片元着色器,返回最终计算出来的颜色数据,输入是顶点着色器的输出。
fixed4 fragment(v2f data) : SV_Target{
}
ENDCG
}
}
FallBack "Diffuse"
}
1.3我们改出了这个流水线后,直接返回一个简单的颜色作为测试
1.我们得思考从缓存中将什么数据丢到流水线里面?
mesh的顶点
mesh的uv
Shader "Custom/Mask001" {
Properties {
//遮罩图
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
Pass{
CGPROGRAM
//定义顶点着色器
#pragma vertex vertex
//定义片元着色器
#pragma fragment fragment
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
//CG变量的遮罩图,你可以调用这个变量的数据,并通过前面章节提供的函数进行采样
sampler2D _MainTex;
//来自于cpu的数据模型
struct fromCpu {
//传入的mesh的基本组成:顶点和UV
fixed4 vertex : POSITION;
float2 uv:TEXCOORD0;
};
//来自顶点着色器的数据模型
struct v2f {
//传入的mesh的基本组成:顶点和UV
fixed4 vertex : POSITION;
float2 uv:TEXCOORD0;
};
//运行顶点着色器,输入data数据,输出计算后的数据。注意流水线
v2f vertex(fromCpu data) {
v2f o;
//转到世界坐标
o.vertex = UnityObjectToClipPos(data.vertex);
return o;
}
//运行片元着色器,返回最终计算出来的颜色数据,输入是顶点着色器的输出。
fixed4 fragment(v2f data) : SV_Target{
return fixed4(0,1,0,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
此时的效果如下:
1.4 我们希望采样一张图片
既然是采样图片,那你就得有uv,uv存放在哪?存放在内存里,也就是vertex着色操作里面输入的fromCpu的结构体。
你得把它传过来!!!,然后用tex2D(_MainTex,data.uv)进行采样,返回就可以啦!
Shader "Custom/Mask001" {
Properties {
//遮罩图
_MainTex("Texture", 2D) = "white" {}
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
Pass{
CGPROGRAM
//定义顶点着色器
#pragma vertex vertex
//定义片元着色器
#pragma fragment fragment
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
//CG变量的遮罩图,你可以调用这个变量的数据,并通过前面章节提供的函数进行采样
sampler2D _MainTex;
//来自于cpu的数据模型
struct fromCpu {
//传入的mesh的基本组成:顶点和UV
fixed4 vertex : POSITION;
float2 uv:TEXCOORD0;
};
//来自顶点着色器的数据模型
struct v2f {
//传入的mesh的基本组成:顶点和UV
fixed4 vertex : POSITION;
float2 uv:TEXCOORD0;
};
//运行顶点着色器,输入data数据,输出计算后的数据。注意流水线
v2f vertex(fromCpu data) {
v2f o;
//转到世界坐标
o.vertex = UnityObjectToClipPos(data.vertex);
o.uv = data.uv;
return o;
}
half4 c1;
//运行片元着色器,返回最终计算出来的颜色数据,输入是顶点着色器的输出。
fixed4 fragment(v2f data) : SV_Target{
c1 = tex2D(_MainTex,data.uv);
return c1;
}
ENDCG
}
}
FallBack "Diffuse"
}
现在展示的效果如下:
1.5 现在,问题来了,我们要采样的数据是UI的Image的Sprite数据
我们定义的片元操作如下:
我们给_MainTex赋值的贴图如下:
此时Mesh显示出来的效果居然是UI的Image的Sprite
也就是:
按道理不应该是,比如一个cube这种:
但是,如果我将Image的Sprite设置为空,显示效果如下:
然后经过我们种种测试之后,真相只有一个:
在Image的材质的2D采样中,当你对名称为“_MainTex”进行采样时,采样数据优先采样Image的Sprite!
就是上面这个。
然后,我们来验证,此时的效果
当我定义名称为_MainTex的属性后,我们的UI效果:
当我定义_MainTex1的属性后:
结果则:
所以,我们可以采样到当前UI的Sprite的图像 。
而能够采样到这个图像,那么你在片元里面就能够修饰这个图像的数据,也就是最终的遮罩!
代码如下:
Shader "Custom/Mask001" {
Properties {
_MainTex("ts", 2D) = "white" {}
_Mask("Mask",2D) = "white"{}
}
SubShader{
Tags {
"Queue" = "Transparent"
}
LOD 200
Pass{
//开启混合
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
//定义顶点着色器
#pragma vertex vertex
//定义片元着色器
#pragma fragment fragment
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
//CG变量的遮罩图,你可以调用这个变量的数据,并通过前面章节提供的函数进行采样
sampler2D _Mask;
sampler2D _MainTex;
//来自于cpu的数据模型
struct fromCpu {
//传入的mesh的基本组成:顶点和UV
fixed4 vertex : POSITION;
float2 uv:TEXCOORD0;
float4 color : COLOR;
};
//来自顶点着色器的数据模型
struct v2f {
//传入的mesh的基本组成:顶点和UV
fixed4 vertex : POSITION;
float2 uv:TEXCOORD0;
float4 color : COLOR;
};
//运行顶点着色器,输入data数据,输出计算后的数据。注意流水线
v2f vertex(fromCpu data) {
v2f o;
//转到世界坐标
o.vertex = UnityObjectToClipPos(data.vertex);
o.uv = data.uv;
//o.color = data.color;
return o;
}
half4 c1;
half4 c2;
//运行片元着色器,返回最终计算出来的颜色数据,输入是顶点着色器的输出。
fixed4 fragment(v2f data) : SV_Target{
c1 = tex2D(_MainTex,data.uv);
c2 = tex2D(_Mask, data.uv);
c2.a = c2.r;
return c1*c2;
}
ENDCG
}
}
FallBack "Diffuse"
}
遮罩图如下:
对于ts来说本身是没有意义的,所以,我们可以隐藏掉。可以使用
[PerRendererData]
关键字:
然后,贴图选项里面:
就只有遮罩图了。