UnityShader入门——纹理应用和透明效果

渐变纹理

最简单的,用一张贴图去实现,给出的贴图应该是渐变的色块

1
2
3
float halfLambert = dot(i.worldNormal,lightDir)* 0.5 + 0.5;
//漫反射
float3 diffue = _LightColor0.rgb * _Diffse.rgb * tex2D(_RampTex,float2(halfLambert,halfLambert));

渐变纹理按照半兰伯特光照的颜色排序,在 x 轴上渐变

遮罩纹理

对blinn phong高光使用该效果,可以控制高光颜色强度

局部着色器实现

1
2
3
4
5
6
float3 halfPhongMask = tex2D(_SpecularMask,i.uvMask).r * _SpecularMaskStrength;//提取遮罩贴图并 和强度进行相关

//高光反射
//float3 halfView = normalize(_WorldSpaceCameraPos + _WorldSpaceLightPos0);
float3 halfView = normalize(viewDir + lightDir);
float3 phong = _LightColor0.rgb * _Specular.rbg * pow(max(0,dot(i.worldNormal,halfView)),_Gloss) * halfPhongMask; //加入遮罩

透明效果

  1. 透明度测试:

    只要一个片元的透明度不满足条件(通常小于某个阈值),那么就舍弃对应的片元。被舍弃的片元不会在进行任何的处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的不透明物体来处理,即进行深度测试,深度写入等等。虽然简单,但是很极端,要么完全透明,要么完全不透明。

  2. 透明度混合:

    可以得到真正的半透明效果,它会使当前片元的透明度作为混合因子,与已经储存在颜色缓冲中的颜色值进行混合么,得到新的颜色。但是,透明度混合需要关闭深度写入,这使得我们要非常小心物体的渲染顺序。注意:透明度混合只关闭了深度写入,但没有关闭深度测试。这表示当使用透明度混合渲染一个片元时,还是会比较它的深度值与当前深度缓冲中的深度值,如果深度值距离摄像机更远,那么就不会在进行混合操作。比如一个不透明物体在透明物体前面,我们先渲染不透明物体,可以正常的挡住不透明物体。

正确的渲染顺序

首先将所有的不透明物体开始深度测试和深度写入,然后将所有透明物体排序,从远到近进行渲染

渲染队列

名称 队列索引号 描述
Background 1000 这个渲染队列会在其他任何队列之前被渲染,通常用来渲染背景
Geometry 2000 默认的渲染对了,大多数物体使用这个队列,不透明物体使用这个队列
AlphaTest 2450 需要透明度测试的物体使用的队列
Transparent 3000 这个队列的物体会在所有Geometry和AlphatTest物体渲染之后,再按照从后往前的顺序进行渲染。任何透明物体都使用该队列
Overlay 4000 该队列实现一些叠加效果。任何最后渲染的物体在该对了。

输入地方在Tags中进行选择,渲染顺序是根据队列索引号从效到大,如果想要使用不同的队列索引号,需要在Tags中使用

1
"Queue"="Transparent - 500"//渲染顺序

以上操作使用的就是 2500 的队列索引号

透明度测试

使用基础的 if 判断,将透明度小于给定裁剪透明值的给抛弃掉

1
2
3
4
5
6
7
8
9

float4 uvColor = tex2D(_MainTex,i.uv);

if(uvColor.a - _Alpha_CullOf < 0 )
{
discard;//裁剪
}

float3 diffuseColor = _LightColor0.rbg * _Diffse.rbg * (max(0,dot(viewDir,i.worldNormal)) *0.5 + 0.5) * uvColor.rbg;

Tags中的设置

1
2
Tags { "Queue"="AlphaTest" "IgnoreProjector" = "true" }

为了性能考虑,建议规范化书写Tags里面的内容

FallBack

不同的类型的FallBack也不同

Diffuse - Diffuse

目前对于AlphaTest没找到一个合适的

image-20241101171559468

透明混合

在UnityShader中,只要有关键字Blend,就代表开启混合(除Blend off以外),OpenGL和DX的使用是需要手动开启的

命令 描述
Blend SrcFactor DstFactor 开启混合,并设置混合因子。源颜色(该片元颜色)乘以SrcFactor,目标颜色(已经存在于颜色缓冲的颜色)会乘以DstFactor,然后把两者相加后在存入颜色缓冲区
Blend SrcFactor DstFactor,SrcFactorA DstFactorA 与上面一样,只是使用不同的因子来混合透明通道

混合因子

参数 描述
One 因子为1
Zero 因子为0
SrcColor 因子为元颜色值。当用于混合RGB的混合等式时,使用SrcColor的RGB分量作为混合因子;当用于混合A的混合公式的时候,使用SrcColor的A分量作为混合因子。
SrcAlpha 因子为源颜色的透明度值(A通道)
DstColor 因子目标颜色值。相当于混合RGB通道的混合等式时,使用DstColor的RGB分量作为混合因子;当用于混合A通道的混合等式时,使用DstColor的A分量作为混合因子。
DstAlpha 因子为目标颜色的透明度值(A通道)
OneMinusSrcColor 因子为(1-源颜色)。相当于混合RGB通道的混合等式时,使用结果RGB分量作为混合因子;当用于混合A通道的混合等式时,使用结果的A分量作为混合因子。
OneMinusSrcAlpha 因子为(1-源颜色的透明度值)
OneMinusDstColor 因子为(1-目标颜色)。相当于混合RGB通道的混合等式时,使用结果RGB分量作为混合因子;当用于混合A通道的混合等式时,使用结果的A分量作为混合因子。
OneMinusDstAlpha 因子为(1-目标颜色的透明度值)

混合操作

image-20241101165115772

image-20241101165125154

常见混合操作类型

  1. //正常(Normal)透明度混合

    Blend SrcAlpha OneMinusSrcAlpha

  2. //柔和相加

    Blend OneMinusDstColor One

  3. //正片叠底

    Blend DstColor Zero

  4. //两倍相乘

    Blend DstColor SrcColor

  5. //变暗

    BlendOp min

  6. Blend One One

    //变亮

  7. Blend OneMinusDstColor One

  8. Blend One OneMinusSrcColor

    //线性减淡

  9. Blend One One

基本格式

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
Shader "Unlit/06"
{
Properties
{
_MainTex("MainTex",2D) = "white" {}

_Diffse("Diffuse",Color) = (1,1,1,1)

_AlphaRange("AlphaRange",Range(0,1))= 0.5

}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector" = "true" "RenderType" = "Transparent" }
LOD 100

ZWrite Off //关闭深度写入
Blend SrcAlpha OneMinusSrcAlpha //选择合适的混合模式

Pass
{
Tags{"LightMode"= "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc "



struct v2f
{
float4 vertex : SV_POSITION;
float2 uv: TEXCOORD0;
float3 worldPos: TEXCOORD1;
float3 worldNormal : TEXCOORD2;


};

sampler2D _MainTex;
float4 _MainTex_ST;

float4 _Diffse;

float _AlphaRange;




v2f vert (appdata_tan v)
{
v2f o;

o.vertex = UnityObjectToClipPos(v.vertex);

o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

o.worldNormal = UnityObjectToWorldNormal(v.normal);


return o;
}

fixed4 frag (v2f i) : SV_Target
{

//切线空间的视线和光线方向获取

float3 environmentLightColor = UNITY_LIGHTMODEL_AMBIENT.xyz;

float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));

float3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));




float4 uvColor = tex2D(_MainTex,i.uv);




float3 diffuseColor = _LightColor0.rbg * _Diffse.rbg * (dot(viewDir,i.worldNormal) * 0.5 + 0.5) * uvColor.rbg;



float3 resColor = environmentLightColor + diffuseColor;


float4 col = float4(resColor,uvColor.a * _AlphaRange);//源物体的a值操作 关键点

return col;
}
ENDCG
}
}

FallBack "Transparent/VertexLit"
}

容易出错

透明混合中对于半透明物体前后关系交叉,深度判断容易出错的情况,在原有的pass上方新建一个下面这个就行

image-20241101172238962