基础shader分析

常见的语义词:

  1. 获取顶点 — float4 vertex : POSITION;
  2. 获取第一uv — float2 uv : TEXCOORD0;
  3. 获取发现 — float3 normal : NORMAL;
  4. 获取顶点色 — float4 color : COLOR;
  5. 获取切线 — float4 tan : TANGENT;

常用的数据类型对应

精度设置float – 32位,half – 16位, fixed – 8位

  1. float常用于坐标点
  2. half常用于UV和大部分向量
  3. fixed常用于颜色

基础shader内容:

获取位置坐标并输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1. 基础变换 -- 顶点着色器中将物体转换到裁剪空间
v2f vert(appdata v){
v2f o;
// 模型转换到世界空间
float4 pos_world = mul(_Object2World, v.vertex);
// 世界空间到相机空间
float4 pos_view = mul(UNITY_MATRIX_V, pos_world);
// 相机空间到裁剪空间
float4 pos_clip = mul(UNITY_MATRIX_P, pow_view);

// 以上变换可以用mvp代替
// o.pos = UnityObjectToClipPos(v.vertex);

o.pos = pos_clip;
return o;
}

2. 输出颜色 -- 片元着色器获取顶点并输出
float4 frag(v2f i) : SV_Target{
return float4(0.5,1.0,0.5,1.0);
}

需要注意的内容
在声明的构造体appdata和v2f中的TEXCOORD0是有差别的

1
2
3
4
5
6
7
8
9
10
11
struct appdata{
// 第一套uv
float2 uv : TEXCOORD0;
// 第二套uv
float2 uv2 : TEXCOORD1;
};

struct v2f{
// 这里表示的是存储器、插值器
float2 uv : TEXCOORD0;
};

获取uv贴图并输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. 基础变换 -- 顶点着色器中将物体转换到裁剪空间,获取uv
sampler2D _MainTex;
// 这个参数是跟贴图的tilling和offset链接
float4 _MainTex_ST;

v2f vert(appdata v){
v2f o;

o.pos = UnityObjectToClipPos(v.vertex);
// o.uv = v.uv;
o.uv = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
return o;
}

2. 输出颜色 -- 片元着色器获uv并输出
float4 frag(v2f i) : SV_Target{
//获取uv并输出
float4 col = tex2D(_MainTex, i.uv);
return col;
}

背面剔除

1
2
3
4
5
6
7
8
9
Properties{
[Enum(UnityEngine.Rendering.CullMode)]_CullMode("CullMode", float) = 2
}

SubShader{
Pass{
Cull[_CullMode]
}
}

Alpha Test

对clip()函数的使用:

大体思路:

  1. 通过tex2D获取r通道
  2. 对gradient进行操作
  3. 输出gradient.xxxx
1
2
3
4
5
6
half4 frag(v2f i): SV_Target{
half gradient = tex2D(_MainTex, i.uv+_Time.y * _Speed.xy).r;
half noise = tex2D(_NoiseTex, i.uv+_Time.y*_Speed.zw).r;
clip(gradient - noise - _Cutout);
return _MainColor;
}

半透明混合

大体思路:

  1. 在pass中打开Blend src dst
  2. 关掉Zwrite – Zwrite off
  3. Subshader中Tags = {“Queue” = “Transparent”}

在贴图没有alpha通道的时候怎么做

1
2
3
4
5
// 尽量将颜色和alpha分开写,最后再组合
half3 col = _MainColor.xyz;
// 用贴图灰度值 * 颜色的alpha代替alpha
half alpha = tex2D(_MainTex, i.uv).r * _MainColor.a;
return float4(col, alpha);

边缘光

实质,dot(n,v)

  1. 实现设置强度
  2. 实现设置对比度
  3. 预先写深度 — 通过提前写一个pass,并且在里面设置ColorMask 0将颜色信息的写入取消
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    // 这里顶点着色器仅写了相关代码
    v2f vert(appdata v){
    // normal计算方式
    o.normal_world = normalize(mul(float4(v.normal,0.0), _Object2World).xyz);

    // 视线计算方式,相机位置减去点的位置
    float3 pos_world = mul(_Object2World, v.vertex).xyz;
    float3 view_world = normalize(_WolrdSpaceCameraPos.xyz - pos_world);
    }


    // 片元着色器中计算 N dot V
    half4 frag(v2f i):SV_Target{
    float3 normal_world = normalize(i.normal_world);
    float3 view_world = normalize(i.view_world);
    float NdotV = saturate(dot(normal_world, view_world));

    float3 col = _MainColor.xyz * _Emiss;
    // 对比度
    float fresnel = pow((1.0 - NdotV), _RimPower);
    // 强度
    float alpha = saturate(fresnel * _Emiss);

    return float4(col, alpha);
    }

    // 如何设置强度
    float alpha = (1.0 - NdotV) * _Emiss;

    // 如何设置对比度
    float fresnel = pow((1.0 - NdotV), _RimPower);