oynix

于无声处听惊雷,于无色处见繁花

Unity Shader常用API总结

查询手册

源码路径:
UnityCG.cginc
UnityShaderUtilities.cginc
UnityShaderVariables.cginc

1. 数学函数

Name Desc
dot(A,B) 点积,结果为标量,主要用于求向量的夹角或B向量在A向量上的投影
cross(A, B) 叉积,结果为向量,与这两个向量组成的平面垂直
mul(M, N) 矩阵M和矩阵N的积
mul(M, v) 矩阵M和列向量v的积
mul(v, M) 行向量v和矩阵M的积
abs(x) 取绝对值
rap(x) 倒数1/x
staturate(x) 把x限制在[0,1]之间
clamp(x, a, b) 把x限制到[a,b]之间
pow(x) 计算幂函数
sqrt(x) x的平方根,x必须大于0
rsqrt(x) x的平方根的倒数,x必须大于0
all(x) 所有不为0,返回true,否则返回false
any(x) 任何一个不为0,返回true,否则返回false
lerp(a, b, f) 返回(1-f)*a + f*b,在下限a和上限b之间进行差值,f表示权重。如果a和b是向量,则f必须是标量或者等长的向量
ceil(x) 向上取整
floor(x) 向下取整
round(x) 返回四舍五入
step(a, b) 如果a>b,返回0;如果a<=b,返回1;当a、b是向量时,每个分量独立判断,如:step(fixed2(1,1),fixed(0,2))=(0,1)
sign(x) x大于0返回1;小于0返回-1;否则返回0
exp(x) 计算e^x,e=2.71828
exp2(x) 计算2^x
fmod(x, y) 返回x/y的余数,如果y为0,则结果不可预料
modf(x, out ip) 把x分解为整数和分数两部分,每部分都和x有着相同的符号,整数部分保存在ip中,分数部分是返回值
max(a, b) 返回最大值
min(a, b) 返回最小值
determinant(M) 计算矩阵的行列式因子
transpose(M) 矩阵M的转置矩阵
degree(x) 将弧度值x转化为角度值
radians(x) 将角度值x转化为弧度值
log(x) 计算ln(x)的值,x必须大于0
log2(x) 计算log2^x的值,x必须大于0
log10(x) 计算log10^x的值,x必须大于0
frac(x) 返回标量或矢量的小数
frexp(x, out i) 将浮点数x分解为尾数和指数,即返回m,指数存入i中;如果x为0,则尾数和指数都返回0
isfinite(x) 判断标量或者向量中的每个数据是否有限数,是则返回true,否则返回false
isinf(x) 判断标量或者向量中的每个数据是否是无限,是则返回true,否则返回false
isnan(x) 判断标量或者向量中的每个数据是否是Not a number,如果是返回true,否则返回false
lit(NdotL, NdotH, m) N表示法向量,L表示入射光向量。H表示半角向量。m表示高光向量。函数计算环境光,散射光,镜面光的共享,返回四元向量:X表示环境光的共享,总是1;Y表示散射光的贡献,如果N.L<0,则为0,否则为N.L;Z表示镜面光的贡献,如果N.L<0或者N.H<0,则为0,否则为(N.H)^m;w始终为1
noise(x) 根据它的参数类型,这个函数可以是一元、二元或三元噪音函数。返回值在0和1之间,并且通常与给定的输入值一样
    |ldexp(x, n)|计算`x*(2^n)`的值

|smoothstep(min, max, x)|x位于min和max之间,若x=min返回0;若x=max返回1;否则返回:-2*((x-min)/(max-min))^3+3*((x-min)/(max-min))^2
|sin(x)|正弦值
|cos(x)|余弦值
|tan(x)|正切值
|asin(x)|反正弦值
|acos(x)|反余弦值
|atan(x)|反正切值
|sinh(x)|计算x的双曲线正弦值
|cosh(x)|计算x的双曲线余弦值
|tanh(x)|计算x的双曲线切线值
|sincos(float x, out s, out c)|同时计算x的sin值和cos值

2. 几何函数

Name Desc
normalize(v) 返回向量v的单位向量
reflect(I, N) 根据入射光方向I和表面法向量N计算反射向量,仅对三元向量有效
length(v) 返回向量v的模,即sqrt(dot(v, v))
distance(pt1, pt2) 两点之间的欧几里得距离
faceforward(N, I, Ng) 如果dot(I, Ng)<0,返回N;否则返回-N
reflect(I, N) 根据入射向量和法线向量,计算反射向量(I和N不需要归一化)
refrace(I, N, eta) 根据入射光线I,表面法向量N和折射相对细数eta,计算折射向量。如果对给定的eta,I和N之间的角度太大,返回(0,0,0)。只对三元向量有效

3. 纹理映射函数

Name Desc
tex1D(sampler1D tex, float s) 一维纹理查询
tex1D(sampler1D tex, float s, float dsdx, float dsdy) 使用导数值(derivatives)查询一维纹理
tex1D(sampler1D tex, float2 sz) 一维纹理查询,并进行深度值比较
tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy) 使用导数值查询一维纹理, 并进行深度值比较
tex1Dproj(sampler1D tex, float2 sq) 一维投影纹理查询
tex1Dproj(sampler1D tex, float3 szq) 一维投影纹理查询,并比较深度值
tex2D(sampler2D tex, float2 s) 二维纹理查询(常用)
tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy) 使用导数值查询二维纹理
tex2D(sampler2D tex, float3 sz) 二维纹理查询,并进行深度值比较
tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy) 使用导数值查询二维纹理,并进行深度值比较
tex2Dproj(sampler2D tex, float3 sq) 二维投影纹理查询
tex2Dproj(sampler2D tex, float4 szq) 二维投影纹理查询,并进行深度值比较
texRECT(samplerRECT tex, float2 s) 二维非投影矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) 二维非投影使用导数的矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz) 二维非投影深度比较矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) 二维非投影深度比较并使用导数的矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 sq) 二维投影矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 szq) 二维投影矩形纹理深度比较查询(OpenGL独有)
tex3D(sampler3D tex, float s) 三维纹理查询
tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值查询三维纹理
tex3Dproj(sampler3D tex, float4 szq) 查询三维投影纹理,并进行深度值比较
texCUBE(samplerCUBE tex, float3 s) 查询立方体纹理
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值查询立方体纹理
texCUBEproj (samplerCUBE tex, float4 sq) 查询投影立方体纹理

4. Shader常量

Name Value
#define UNITY_PI 3.14159265359f
#define UNITY_TWO_PI 6.28318530718f
#define UNITY_FOUR_PI 12.56637061436f
#define UNITY_INV_PI 0.31830988618f
#define UNITY_INV_TWO_PI 0.15915494309f
#define UNITY_INV_FOUR_PI 0.07957747155f
#define UNITY_HALF_PI 1.57079632679f
#define UNITY_INV_HALF_PI 0.636619772367f

5. Shader变量

时间变量

1
2
3
4
5
// Time (t = time since current level load) values from Unity
float4 _Time; // (t/20, t, t*2, t*3)
float4 _SinTime; // sin(t/8), sin(t/4), sin(t/2), sin(t)
float4 _CosTime; // cos(t/8), cos(t/4), cos(t/2), cos(t)
float4 unity_DeltaTime; // dt, 1/dt, smoothdt, 1/smoothdt

相机和光源的世界坐标

1
2
float3 _WorldSpaceCameraPos; // 相机的世界坐标
half4 _WorldSpaceLightPos0; // 光源的世界坐标(当光源是平行光时, _WorldSpaceLightPos0表示灯光照射方向)

远近裁剪平面参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// x = 1 or -1 (-1 if projection is flipped)
// y = near plane
// z = far plane
// w = 1/far plane
float4 _ProjectionParams;

// 用于线性化深度, 如: LinearEyeDepth、Linear01Depth函数内部会调用
// x = 1-far/near
// y = far/near
// z = (near-far)/(near*far)
// w = 1/near
// 用于 reversed depth buffer (UNITY_REVERSED_Z is 1)
// x = -1+far/near
// y = 1
// z = (far-near)/(near*far)
// w = 1/far
float4 _ZBufferParams;

屏幕参数

1
2
3
4
5
// x = width
// y = height
// z = 1 + 1.0/width
// w = 1 + 1.0/height
float4 _ScreenParams;

纹理参数

1
2
3
4
5
// _MainTex的像素尺寸大小, float4(1/width, 1/height, width, height)
float4 _MainTex_TexelSize;
// _MainTex缩放和偏移
// UV空间是左手坐标系,U轴从左到右,V轴从下到上
float4 _MainTex_ST;

MVP矩阵

1
2
3
4
5
6
7
8
9
10
float4x4 UNITY_MATRIX_M, unity_ObjectToWorld; // [模型空间->世界空间]的变换矩阵M
float4x4 UNITY_MATRIX_V, unity_MatrixV; // [世界空间->观察空间]的变换矩阵V
float4x4 UNITY_MATRIX_P, glstate_matrix_projection; // [观察空间->裁剪空间]的变换矩阵P
float4x4 UNITY_MATRIX_MV, unity_MatrixMV; // [模型空间->观察空间]的变换矩阵MV
float4x4 UNITY_MATRIX_VP, unity_MatrixVP; // [世界空间->裁剪空间]的变换矩阵VP
float4x4 UNITY_MATRIX_MVP, unity_MatrixMVP; // [模型空间->裁剪空间]的变换矩阵MVP
float4x4 UNITY_MATRIX_I_V, unity_MatrixInvV; // V矩阵的逆矩阵
float4x4 UNITY_MATRIX_T_MV, unity_MatrixTMV; // MV矩阵的转置
float4x4 UNITY_MATRIX_IT_MV, unity_MatrixITMV; // MV矩阵的逆转矩阵
float4x4 unity_WorldToObject; // [世界空间->模型空间]的变换矩阵M

6. 坐标和向量变换

坐标变换

1
2
3
4
5
6
7
8
9
10
11
12
// 模型空间->观察空间
float3 UnityObjectToViewPos(float3 pos) // mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz
float3 UnityObjectToViewPos(float4 pos) // UnityObjectToViewPos(pos.xyz)
// 模型空间->裁剪空间
float4 UnityObjectToClipPos(float3 pos) // mul(UNITY_MATRIX_MVP, float4(pos, 1.0))
float4 UnityObjectToClipPos(float4 pos) // UnityObjectToClipPos(pos.xyz)
// 世界空间->观察空间
float3 UnityWorldToViewPos(float3 pos) // mul(UNITY_MATRIX_V, float4(pos, 1.0)).xyz
// 世界空间->裁剪空间
float4 UnityWorldToClipPos(float3 pos) // mul(UNITY_MATRIX_VP, float4(pos, 1.0))
// 观察空间->裁剪空间
float4 UnityViewToClipPos(float3 pos) // mul(UNITY_MATRIX_P, float4(pos, 1.0))

屏幕空间变换

1
2
3
4
// 裁剪空间->屏幕空间(输入: 裁剪空间坐标, 输出: 屏幕空间坐标)
// o.xy = 0.5 * (pos.xy + pos.w), o.zw = pos.zw
float4 ComputeScreenPos(float4 pos)
float4 ComputeGrabScreenPos(float4 pos)

向量变换

1
2
3
4
// 模型空间->世界空间
float3 UnityObjectToWorldDir(float3 dir) // normalize(mul((float3x3)unity_ObjectToWorld, dir))
// 世界空间->模型空间
float3 UnityWorldToObjectDir(float3 dir) // normalize(mul((float3x3)unity_WorldToObject, dir))

法线变换

1
2
3
4
5
6
7
8
// 模型空间->世界空间(已归一化)
float3 UnityObjectToWorldNormal(float3 norm) {
#ifdef UNITY_ASSUME_UNIFORM_SCALING // 统一缩放(x、y、z分量缩放系数一致)
return UnityObjectToWorldDir(norm); // normalize(mul((float3x3)unity_ObjectToWorld, norm))
#else
return normalize(mul(norm, (float3x3)unity_WorldToObject)); // mul(IT_M, norm) => mul(norm, I_M)
#endif
}

其他变换

1
2
3
// 观察空间->裁剪空间
float2 TransformViewToProjection (float2 v) // mul((float2x2)UNITY_MATRIX_P, v)
float3 TransformViewToProjection (float3 v) // mul((float3x3)UNITY_MATRIX_P, v)

7. 计算指向相机和光源的向量

计算顶点指向相机的向量

1
2
3
4
// _WorldSpaceCameraPos.xyz - worldPos
float3 ObjSpaceViewDir(float4 v) // 输入: 模型空间坐标, 输出: 模型空间坐标
float3 WorldSpaceViewDir(float4 localPos) // 输入: 模型空间坐标, 输出: 世界空间坐标
float3 UnityWorldSpaceViewDir(float3 worldPos) // 输入: 世界空间坐标, 输出: 世界空间坐标

计算顶点指向光源的向量

1
2
3
4
// mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz - v.xyz
float3 ObjSpaceLightDir(float4 v) // 输入: 模型空间坐标, 输出: 模型空间坐标
float3 WorldSpaceLightDir(float4 localPos) // 输入: 模型空间坐标, 输出: 世界空间坐标
float3 UnityWorldSpaceLightDir(float3 worldPos) // 输入: 世界空间坐标, 输出: 世界空间坐标

8. 深度纹理和法线纹理相关函数

深度纹理采样

1
2
3
4
5
6
// 非线性的深度(即计算的深度值与实际深度值不是线性关系)
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); // tex2D(_CameraDepthTexture, i.uv).r
// 观察空间中的线性的深度, 值域: [Near, Far], 公式: 1.0 / (_ZBufferParams.z * depth + _ZBufferParams.w)
float linearDepth = LinearEyeDepth(depth);
// 观察空间中的线性且归一化的深度, 值域: [0, 1], 公式: 1.0 / (_ZBufferParams.x * depth + _ZBufferParams.y)
float linear01Depth = Linear01Depth(depth);

深度&法线纹理采样

1
2
3
4
5
6
7
8
9
10
fixed4 tex = tex2D(_CameraDepthNormalsTexture, i.uv);
float depth = DecodeFloatRG(tex.zw); // 观察空间中的线性且归一化的深度
float3 normal = DecodeViewNormalStereo(tex); // 观察空间中的法线向量

也可以使用DecodeDepthNormal函数获取深度和法线信息:
inline void DecodeDepthNormal(float4 enc, out float depth, out float3 normal)
{ // 深度&法线采样, enc为tex2D采样结果, depth、normal为解码后的深度和法线
depth = DecodeFloatRG(enc.zw); // 观察空间中的线性且归一化的深度
normal = DecodeViewNormalStereo(enc); // 观察空间中的法线向量
}
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2024/06/abac05b839aa/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道