0x07.Shader函数clamp
在 Unity Shader 中,clamp
是一个常用的内置函数,用于将值限制在指定的范围内。
基本语法
clamp
函数有两种主要形式:
-
标量形式:
float clamp(float value, float min, float max);
将
value
限制在[min, max]
范围内。若value < min
,返回min
;若value > max
,返回max
;否则返回value
本身。 -
向量形式:
float2 clamp(float2 value, float2 min, float2 max); float3 clamp(float3 value, float3 min, float3 max); // 其他向量类型(float4、half2 等)同理
对向量的每个分量分别进行 clamping 操作。
常见应用场景
1. 限制纹理坐标
防止纹理坐标超出 [0, 1]
范围,避免采样错误:
float2 clampedUV = clamp(uv, 0.0, 1.0); // 将 UV 限制在 [0,1] 内
fixed4 texColor = tex2D(_MainTex, clampedUV);
2. 颜色值归一化
确保颜色值在 [0, 1]
范围内,避免过亮或过暗:
fixed3 color = someCalculation();
color = clamp(color, 0.0, 1.0); // 防止颜色溢出
3. 平滑过渡阈值
结合 smoothstep
实现渐变效果:
float t = someValue;
t = clamp(t, 0.0, 1.0); // 确保 t 在 [0,1] 内,避免 smoothstep 异常
float smoothValue = smoothstep(0.2, 0.8, t);
4. 光照计算
限制点积结果为非负值,避免阴影区域出现负值:
float ndotl = dot(normal, lightDir);
ndotl = clamp(ndotl, 0.0, 1.0); // 确保点积结果在 [0,1] 内
代码示例
以下是一个完整的 Shader 示例,展示 clamp
的用法:
Shader "Custom/ClampExample" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_ClampMin ("Clamp Min", Range(0, 1)) = 0.2
_ClampMax ("Clamp Max", Range(0, 1)) = 0.8
}
SubShader {
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;
float _ClampMin;
float _ClampMax;
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target {
// 示例1:限制纹理坐标(防止超出边界)
float2 clampedUV = clamp(i.uv, 0.0, 1.0);
fixed4 texColor = tex2D(_MainTex, clampedUV);
// 示例2:调整亮度并限制在 [_ClampMin, _ClampMax] 范围内
fixed3 brightenedColor = texColor.rgb * 1.5; // 增加亮度
brightenedColor = clamp(brightenedColor, _ClampMin, _ClampMax;
return fixed4(brightenedColor, texColor.a);
}
ENDCG
}
}
}
注意事项
- 性能:
clamp
是一个轻量级操作,但在复杂计算中频繁调用可能影响性能。 - 向量分量:对向量使用
clamp
时,确保min
和max
向量的每个分量都符合逻辑。 - 替代实现:若需要自定义 clamping 逻辑,可手动实现:
float customClamp(float value, float min, float max) { return value < min ? min : (value > max ? max : value); }