Unity Shader 进阶教程:透明效果、溶解效果、旗帜飘动与点云(附完整代码)
1. 透明与混合效果
1.1 透明度基础
在 Shader 中,透明度通过 Alpha 通道控制。可以通过修改片段的 Alpha 值来实现透明效果。例如:
Shader "Custom/TransparentShader" {
Properties{
_MainTex("Texture", 2D) = "white" {}
_Transparency("Transparency", Range(0,1)) = 0.5
}
SubShader{
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
Blend SrcAlpha OneMinusSrcAlpha // 使用标准的透明度混合模式
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Transparency;
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.uv);
col.a *= _Transparency; // 应用透明度属性
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
在 Unity 中,透明效果需要启用混合模式(Blend)。常见的混合模式包括:
- Alpha 混合:
Blend SrcAlpha OneMinusSrcAlpha
- 加法混合:
Blend One One
- 乘法混合:
Blend DstColor Zero
1.2 实现溶解效果
溶解效果是一种常见的透明效果,通过噪声纹理控制物体的消失过程。以下是实现溶解效果的代码:
Shader "Custom/DissolveShaderWithTransparency"
{
Properties
{
_MainTex("Texture", 2D) = "white" {} // 主纹理
_NoiseTex("Noise Texture", 2D) = "white" {} // 噪声纹理
_DissolveThreshold("Dissolve Threshold", Range(0, 1)) = 0.5 // 溶解阈值
_EdgeColor("Edge Color", Color) = (1, 0, 0, 1) // 边缘颜色
_EdgeWidth("Edge Width", Range(0, 0.2)) = 0.1 // 边缘宽度
}
SubShader
{
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } // 透明渲染队列
LOD 200
Pass
{
Blend SrcAlpha OneMinusSrcAlpha // 启用透明度混合
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 定义输入结构
struct appdata
{
float4 vertex : POSITION; // 顶点位置
float2 uv : TEXCOORD0; // 纹理坐标
};
// 定义输出结构
struct v2f
{
float2 uv : TEXCOORD0; // 主纹理坐标
float2 uvNoise : TEXCOORD1; // 噪声纹理坐标
float4 vertex : SV_POSITION; // 裁剪空间顶点位置
};
// 属性变量
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _NoiseTex;
float4 _NoiseTex_ST;
float _DissolveThreshold;
float4 _EdgeColor;
float _EdgeWidth;
// 顶点 Shader
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); // 顶点变换到裁剪空间
o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 主纹理坐标变换
o.uvNoise = TRANSFORM_TEX(v.uv, _NoiseTex); // 噪声纹理坐标变换
return o;
}
// 片段 Shader
fixed4 frag(v2f i) : SV_Target
{
// 采样噪声纹理
float noise = tex2D(_NoiseTex, i.uvNoise).r;
// 溶解效果
if (noise < _DissolveThreshold) // 如果噪声值小于阈值,丢弃像素
discard;
// 计算边缘透明度
float edgeAlpha = smoothstep(_DissolveThreshold, _DissolveThreshold + _EdgeWidth, noise);
// 采样主纹理
fixed4 texColor = tex2D(_MainTex, i.uv);
// 计算边缘颜色
fixed4 edgeColor = _EdgeColor * (1 - edgeAlpha);
// 最终颜色 = 主纹理颜色 + 边缘颜色
fixed4 col = texColor * edgeAlpha + edgeColor;
col.a = edgeAlpha; // 设置透明度
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
调整 _DissolveThreshold
可以控制物体的溶解过程。
2. 顶点动画与几何 Shader
2.1 顶点动画基础
顶点动画通过修改顶点位置来实现动态效果。例如,我们可以实现一个简单的旗帜飘动效果:
Shader "Custom/FlagWaveShader"
{
Properties
{
_MainTex("Texture", 2D) = "white" {} // 主纹理
_WindStrength("Wind Strength", Float) = 1.0 // 风强度
_WindFrequency("Wind Frequency", Float) = 1.0 // 风频率
_WindDirection("Wind Direction", Vector) = (1, 0, 0, 0) // 风方向
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 200
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 定义输入结构
struct appdata
{
float4 vertex : POSITION; // 顶点位置
float2 uv : TEXCOORD0; // 纹理坐标
};
// 定义输出结构
struct v2f
{
float2 uv : TEXCOORD0; // 纹理坐标
float4 vertex : SV_POSITION; // 裁剪空间顶点位置
};
// 属性变量
sampler2D _MainTex;
float4 _MainTex_ST;
float _WindStrength;
float _WindFrequency;
float4 _WindDirection;
// 顶点 Shader
v2f vert(appdata v)
{
v2f o;
// 计算顶点位移
float wave = sin(v.uv.x * _WindFrequency + _Time.y) * _WindStrength; // 波浪效果
v.vertex.xyz += _WindDirection.xyz * wave; // 根据风向和强度修改顶点位置
// 顶点变换到裁剪空间
o.vertex = UnityObjectToClipPos(v.vertex);
// 传递纹理坐标
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
// 片段 Shader
fixed4 frag(v2f i) : SV_Target
{
// 采样主纹理
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
这段代码通过正弦函数模拟了旗帜的飘动效果。调整 _WaveFrequency
和 _WaveAmplitude
来控制波浪的频率和幅度。
2.2 几何 Shader 简介
几何 Shader 是一种强大的工具,可以在渲染管线中生成新的几何图元。虽然 Unity 对几何 Shader 的支持有限,但我们仍然可以实现一些简单的效果。例如,生成一个简单的点云:
Shader "Custom/PointCloudShader"
{
Properties
{
_PointSize("Point Size", Float) = 5.0 // 点的大小
_PointColor("Point Color", Color) = (1, 1, 1, 1) // 点的颜色
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 200
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
#include "UnityCG.cginc"
// 定义输入结构
struct appdata
{
float4 vertex : POSITION; // 顶点位置
};
// 定义几何 Shader 输入结构
struct v2g
{
float4 vertex : POSITION; // 顶点位置
};
// 定义几何 Shader 输出结构
struct g2f
{
float4 vertex : SV_POSITION; // 裁剪空间顶点位置
float4 color : COLOR; // 点颜色
float size : PSIZE; // 点大小
};
// 属性变量
float _PointSize;
float4 _PointColor;
// 顶点 Shader
v2g vert(appdata v)
{
v2g o;
o.vertex = v.vertex; // 直接传递顶点位置
return o;
}
// 几何 Shader
[maxvertexcount(3)] // 每个输入顶点生成 3 个点
void geom(point v2g input[1], inout PointStream<g2f> stream)
{
g2f o;
// 生成随机偏移
float3 randomOffset = float3(
frac(sin(input[0].vertex.x * 123.456) * 43758.5453),
frac(sin(input[0].vertex.y * 123.456) * 43758.5453),
frac(sin(input[0].vertex.z * 123.456) * 43758.5453)
);
// 生成 3 个点
for (int i = 0; i < 3; i++)
{
float3 offset = randomOffset * 0.1 * i; // 随机偏移
o.vertex = UnityObjectToClipPos(input[0].vertex + float4(offset, 0)); // 顶点变换到裁剪空间
o.color = _PointColor; // 设置点颜色
o.size = _PointSize; // 设置点大小
stream.Append(o); // 将点添加到输出流
}
}
// 片段 Shader
fixed4 frag(g2f i) : SV_Target
{
return i.color; // 返回点颜色
}
ENDCG
}
}
FallBack "Diffuse"
}