unity-shader常用函数

unity shader 常用函数 记录


在线画图工具, 数学公式


内置的矩阵变量

名称 说明
UNITY_MATRIX_MVP 当前模型视图投影矩阵,通常用于把顶点/方向矢量从模型空间转换到裁剪空间
UNITY_MATRIX_MV 当前模型视图矩阵,通常用于把顶点/方向矢量从模型空间转换到视角(相机)空间
UNITY_MATRIX_V 当前视图矩阵,通常用于把顶点/方向矢量从世界空间转换到视角(相机)空间
UNITY_MATRIX_P 当前的投影矩阵,通常用于把顶点/方向矢量从视角(相机)空间转换到裁剪空间
UNITY_MATRIX_VP 当前视图投影矩阵,通常用于把顶点/方向矢量从世界空间转换到裁剪空间
UNITY_MATRIX_T_MV UNITY_MATRIX_MV模型视图矩阵的转置
UNITY_MATRIX_IT_MV 模型视图矩阵的逆转置,通常用于把 法线 从模型空间转换到视角(相机)空间
unity_ObjectToWorld 当前模型转空间矩阵,通常用于把顶点/方向矢量从模型空间转换到世界空间
unity_WorldToObject 当前世界转模型矩阵,通常用于把顶点/方向矢量从世界空间转换到模型空间
  1. UnityObjectToClipPos方法,官方网站上说明,编写着色器脚本时,请始终使用 UnityObjectToClipPos(v.vertex) 而不是 mul(UNITY_MATRIX_MVP,v.vertex),因为所有内建的矩阵名字在 Instanced
    Shader 中都是被重定义过的,如果直接使用 UNITY_MATRIX_MVP,会引入一个额外的矩阵乘法运算,所以推荐使用 UnityObjectToClipPos
    / UnityObjectToViewPos 函数,它们会把这一次额外的矩阵乘法优化为向量-矩阵乘法。

  2. UNITY_MATRIX_IT_MV 的使用场景,专门针对法线进行变换。但是为什么法线的变换和顶点不一样呢?

    之所以法线不能直接使用UNITY_MATRIX_MV进行变换,是因为法线是向量,具有方向,在进行空间变换的时候,如果发生非等比缩放,方向会发生偏移。为什么呢?举个栗子,我们可以简单的把法线和切线当成三角形的两条边,显然,三角形在空间变换的时候,不管是平移,还是旋转,或者是等比缩放,都不会变形,但是如果非等比缩放,就会发生拉伸。所以法线和切线的夹角也就会发生变化。(而切线在变换前后,方向总是正确的,所以法线方向就不正确了)。下图,T、T’是切线,N、N’是法线

    经过非等比缩放后

  3. UnityObjectToWorldDirUnityObjectToWorldNormal 的区别

    第一个原图,红色箭头表示法线。第二张图,表示非等比缩放,使用 UnityObjectToWorldDir,把法线从模型空间转换到世界空间,法线也会被压扁并且不再垂直于曲面。第三张图,表示非等比缩放,使用 UnityObjectToWorldNormal,把法线从模型空间转换到世界空间,法线是正确的垂直于曲面的。

    当等比缩放时,使用 UnityObjectToWorldDirUnityObjectToWorldNormal 得到的结果是一样的。


内置 shader 辅助函数定义在 UnityCG.cginc

顶点转换函数:

Function: Description:
float4 UnityObjectToClipPos(float3 pos) Transforms a point from object space to the camera’s clip space in homogeneous coordinates. This is the equivalent of mul(UNITY_MATRIX_MVP, float4(pos, 1.0)), and should be used in its place.homogeneous coordinates:齐次坐标等价于:mul(UNITY_MATRIX_MVP, float4(pos, 1.0)),
float3 UnityObjectToViewPos(float3 pos) Transforms a point from object space to view space. This is the equivalent of mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz, and should be used in its place.等价于:mul(UNITY_MATRIX_MV, float4(pos, 1.0)).

Generic helper functions(定义在UnityCG.cginc文件中)

Function: Description:
float3 WorldSpaceViewDir (float4 v) Returns world space direction (not normalized) from given object space vertex position towards the camera.(参数是object space下的顶点坐标,取得world space下指向摄像机的方向,即视角方向)
float3 ObjSpaceViewDir (float4 v) Returns object space direction (not normalized) from given object space vertex position towards the camera.(同上,不过取到的视角方向是在object space上的)
float2 ParallaxOffset (half h, half height, half3 viewDir) calculates UV offset for parallax normal mapping.为视差法线贴图计算UV偏移
fixed Luminance (fixed3 c) Converts color to luminance (grayscale).将颜色转换为亮度(灰度)
fixed3 DecodeLightmap (fixed4 color) Decodes color from Unity lightmap (RGBM or dLDR depending on platform).从烘焙贴图解码,烘焙贴图生成的是EXR格式的HDR贴图,根据不同平台返回RGBM或dLDR
float4 EncodeFloatRGBA (float v) Encodes [0..1) range float into RGBA color, for storage in low precision render target.把float编码到RGBA8
float DecodeFloatRGBA (float4 enc) Decodes RGBA color into a float.上面方法的反编
float2 EncodeFloatRG (float v) Encodes [0..1) range float into a float2.编码 [0.0,1.0)float–> float2
float DecodeFloatRG(float2 enc) Decodes a previously-encoded RG float.float2解码–> [0.0,1.0)
float2 EncodeViewNormalStereo (float3 n) Encodes view space normal into two numbers in 0..1 range.视空间法线(float3)编码到float2
float3 DecodeViewNormalStereo (float4 enc4) Decodes view space normal from enc4.xy.上面方法的解码,只使用参数的xy值

Forwardrendering helper functions in UnityCG.cginc

These functions are only useful when using forward rendering(ForwardBase or ForwardAdd pass types).

仅用于前向渲染

Function: Description:
float3 WorldSpaceLightDir (float4 v) Computes world space direction (not normalized) to light, given object space vertex position.参数是object space下的顶点坐标,取得world space下指向光源的方向
float3 ObjSpaceLightDir (float4 v) Computes object space direction (not normalized) to light, given object space vertex position.参数是object space下的顶点坐标,取得object space下指向光源的方向
float3 Shade4PointLights (...) Computes illumination from four point lights, with light data tightly packed into vectors. Forward rendering uses this to compute per-vertex lighting.正向渲染中,最多有4个点光源会以逐顶点渲染的方式被计算。

Vertex-lithelper functions in UnityCG.cginc

These functionsare only useful when using per-vertex lit shaders (“Vertex” pass type).

仅用于per-vertex lit shaders

Function: Description:
float3 ShadeVertexLights (float4 vertex, float3 normal) Computes illumination from four per-vertex lights and ambient, given object space position & normal.参数为顶点跟法线,根据四个逐顶点光源跟环境光计算光照

mul(UNITY_MATRIX_MVP,v)跟ComputeScreenPos的区别

一个是model position->projection position 投影坐标
一个是projection position->screen position…屏幕坐标

投影坐标系->屏幕坐标系这是最简单的。2D坐标变换。也不多说。

使用例子:

1
2
3
o.position = mul(UNITY_MATRIX_MVP, v.vertex);
o.proj0 = ComputeScreenPos(o.position);
COMPUTE_EYEDEPTH(o.proj0.z);

有关深度的一些方法整理:

UNITY_TRANSFER_DEPTH**(o):**计算eye space的深度值,并写入变量o(float2)。

当需要渲染到一张深度贴图时,在vertex shader中使用该函数。

**UNITY_OUTPUT_DEPTH(i): **returns eye space depth from i (which must be a float2). Use it in a fragment programwhen rendering into a depth texture.

示例,制作深度贴图用:

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
Shader"Render Depth" {
SubShader{
​ Tags { "RenderType"="Opaque"}
​ Pass {

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include"UnityCG.cginc"
structv2f {
​ float4 pos : SV_POSITION;
​ float2 depth : TEXCOORD0;
}

v2fvert (appdata_base v) {
​ v2f o;
​ o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
​ UNITY_TRANSFER_DEPTH(o.depth);
​ return o;
}

half4frag(v2f i) : SV_Target {
​ UNITY_OUTPUT_DEPTH(i.depth);
}

ENDCG
​ }
}
}

**COMPUTE_EYEDEPTH(o):**computes eye spacedepth of the vertex and outputs it in o. Use it in a vertexprogram when not rendering into adepth texture

实现代码#define COMPUTE_EYEDEPTH(o) o =-mul( UNITY_MATRIX_MV, v.vertex ).z设置o为当前顶点视空间的z值,在vertex 函数中使用

**DECODE_EYEDEPTH(i):*given high precision value from depth texture i, returns corresponding eye space depth. This macro just returnsiFarPlane on Direct3D. On platforms withnative depth textures it linearizes and expands the value to match camera’s range.

返回深度纹理值在眼空间的深度。i为从深度纹理中取样得到的值

z-buffer值不是线性的。

opengl 中是一个 0-1的值。0近1远,

directx中是一个-1到1 的值

Linear01Depth参数是0-1的深度值,可得最后计算结果为z/f;就是说,是将[0, f]映射到[0,1]空间,若要映射[n, f]到[0, 1]则是(z-n)/(f-n)。

LinearEyeDepth中参数是0-1的深度值,可得最后计算结果为z。很明显,LinearEyeDepth是将经过透视投影变换的深度值还原了。DECODE_EYEDEPTH跟该函数实现一样


ObjSpaceLightDir

  • 计算出 模型空间 下,光线的方向向量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Computes object space light direction
inline float3 ObjSpaceLightDir( in float4 v )
{
float3 objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz;
#ifndef USING_LIGHT_MULTI_COMPILE
return objSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w;
#else
#ifndef USING_DIRECTIONAL_LIGHT
return objSpaceLightPos.xyz - v.xyz;
#else
return objSpaceLightPos.xyz;
#endif
#endif
}

ObjSpaceViewDir

  • 计算出 模型空间 下,顶点 到 相机 的方向向量
1
2
3
4
5
6
// Computes object space view direction
inline float3 ObjSpaceViewDir( in float4 v )
{
float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
return objSpaceCameraPos - v.xyz;
}

TANGENT_SPACE_ROTATION

  • 计算出 切线空间矩阵rotation
1
2
3
4
// Declares 3x3 matrix 'rotation', filled with tangent space basis
#define TANGENT_SPACE_ROTATION \
float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal ) (t=x轴,bi=y轴,n=z轴)

UnityObjectToWorldNormal

  • 转换 法线 从 模型空间 到 世界空间
1
2
3
4
5
6
7
8
9
10
// Transforms normal from object to world space
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return UnityObjectToWorldDir(norm);
#else
// mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
return normalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}

UnityObjectToWorldDir

  • 转换 方向 从 模型空间 到 世界空间
1
2
3
4
5
// Transforms direction from object to world space
inline float3 UnityObjectToWorldDir( in float3 dir )
{
return normalize(mul((float3x3)unity_ObjectToWorld, dir));
}

UnpackNormal

  • 传入值 packednormal 是从 法线贴图 采样出来的值,因为 贴图的存储 rgb 值 是在区间 [0,1],而法线的值是在[-1,1]之间,所以法线存储到贴图中的值是经过公式 (pixel = (normal + 1) / 2)转换的,所以要获取正确的法线值需要转换回来(normal = pixel * 2 - 1)
  • 使用这个 函数,必须在编辑器中设置法线图的 Texture Type 为 Normal,详情参考 :法线纹理(Normal Mapping)的实现细节
    • 可以让Unity根据不同平台对纹理进行压缩,通过UnpackNormal函数对法线纹理进行正确的采样,即“将把颜色通道变成一个适合于实时法向映射的格式”
1
2
3
4
5
6
7
8
inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(UNITY_NO_DXT5nm)
return packednormal.xyz * 2 - 1;
#else
return UnpackNormalDXT5nm(packednormal);
#endif
}

参考文章


UnityCG.cginc中一些常用的帮助函数:

Function Name Description
float3 WorldSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该顶点到摄像机的观察空间方向。 内部使用了UnityWorldSpaceViewDir函数
float3 UnityWorldSpaceViewDir(float4 v) 输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
float3 ObjSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从改点到摄像机的观察方向
float3 WorldSpaceLightDir(float4 v) 输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向。内部使用了UnityWorldSpaceLightDir,没有被归一化
float3 UnityWorldSpaceLightDir(float4 v) 输入一个世界空间中的顶点位置,返回世界空间中从该点到光源的光照方向。没有被归一化
float3 ObjSpaceLightDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间从该点到光源的光照方向。没有被归一化
float3 UnityObjectToWorldDir(float3 dir) 把方向矢量从模型空间变化到世界空间中
float3 UnityObjectToWorldNormal(float3 dir) 把法线方向从模型空间转换到世界空间中
float3 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间变化到模型空间


UNITY_LIGHT_ATTENUATION

参考 : 笔记十——光照衰减&阴影 - https://zhuanlan.zhihu.com/p/31805436

unity 内置的宏, 返回光照衰减值

UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);

atten : 是自定义命名变量, 衰减值, 不用提前声明
i 是片段着色器的输入值
i.worldPos 是世界坐标


mix 等价 lerp

mix

1
2
3
float mix(float a, float b, float w) {
return a(1-w) + b * w;
}

lerp

1
2
3
4
float lerp(float a, float b, float w) {
return a + w*(b-a);
// return a(1-w) + b * w; // 展开后就和mix一样
}

CG 标准函数库

1. 数学函数(Mathematical Functions)

函数 功能
abs(x) 返回输入参数的绝对值
acos(x) 反余切函数,输入参数范围为 [-1,1] ,返回 区间的角度值
all(x) 如果输入参数均不为 0 ,则返回 ture ;否则返回 flase 。 && 运算
any(x) 输入参数只要有其中一个不为 0 ,则返回 true 。 || 运算
asin(x) 反正弦函数 , 输入参数取值区间为 ,返回角度值范围为
atan(x) 反正切函数,返回角度值范围为
atan2(y,x) 计算 y/x 的反正切值。实际上和 atan(x) 函数功能完全一样,至少输入参数不同。 atan(x) = atan2(x, float(1)) 。
ceil(x) 对输入参数向上取整。例如: ceil(float(1.3)) ,其返回值为 2.0
clamp(x,a,b) 如果 x 值小于 a ,则返回 a ;如果 x 值大于 b ,返回 b ;否则,返回 x 。
cos(x) 返回弧度 x 的余弦值。返回值范围为
cosh(x) 双曲余弦( hyperbolic cosine )函数,计算 x 的双曲余弦值。
cross(A,B) 返回两个三元向量的叉积 (cross product) 。注意,输入参数必须是三元向量!
degrees(x) 输入参数为弧度值 (radians) ,函数将其转换为角度值 (degrees)
determinant(m) 计算矩阵的行列式因子。
dot(A,B) 返回 A 和 B 的点积 (dot product) 。参数 A 和 B 可以是标量,也可以是向量(输入参数方面,点积和叉积函数有很大不同)。
exp(x) 计算 的值, e= 2.71828182845904523536
exp2(x) 计算 的值
floor(x) 对输入参数向下取整。例如 floor(float(1.3)) 返回的值为 1.0 ;但是 floor(float(-1.3)) 返回的值为 -2.0 。该函数与 ceil(x) 函数相对应。
fmod(x,y) 返回 x/y 的余数。如果 y 为 0 ,结果不可预料。
frac(x) res = x - floor(x), 例如: Frac(0.2) = (0.2). Frac(-0.2) = (0.8). Frac(0.0,1.6,1.0) = (0.0,0.6,0.0).
frexp(x, out exp) 将浮点数 x 分解为尾数和指数,即x = m* 2^exp ,返回 m ,并将指数存入 exp 中;如果 x 为 0 ,则尾数和指数都返回 0
isfinite(x) 判断标量或者向量中的每个数据是否是有限数,如果是返回 true ;否则返回 false; 无限的或者非数据 (not-a-number NaN) ,
isinf(x) 判断标量或者向量中的每个数据是否是无限,如果是返回 true ;否则返回 false;
isnan(x) 判断标量或者向量中的每个数据是否是非数据 (not-a-number NaN) ,如果是返回 true ;否则返回 false;
ldexp(x, n) 计算 的值
lerp(a, b, f) 计算 或者 的值。即在下限 a 和上限 b 之间进行插值, f 表示权值。注意,如果 a 和 b 是向量,则权值 f 必须是标量或者等长的向量。
lit(NdotL, NdotH, m) N 表示法向量; L 表示入射光向量; H 表示半角向量; m 表示高光系数。函数计算环境光、散射光、镜面光的贡献,返回的 4 元向量:X 位表示环境光的贡献,总是 1.0 ;Y 位代表散射光的贡献,如果 ,则为 0 ;否则为 Z 位代表镜面光的贡献,如果 或者 ,则位 0 ;否则为 ;W 位始终位 1.0
log(x) 计算 的值, x 必须大于 0
log2(x) 计算 的值, x 必须大于 0
log10(x) 计算 的值, x 必须大于 0
max(a, b) 比较两个标量或等长向量元素,返回最大值。
min(a,b) 比较两个标量或等长向量元素,返回最小值。
modf(x, out ip) 在 Cg Reference Manual 中没有查到
mul(M, N) 计算两个矩阵相乘,如果 M 为 AxB 阶矩阵, N 为 BxC 阶矩阵,则返回 AxC 阶矩阵。下面两个函数为其重载函数。
mul(M, v) 计算矩阵和向量相乘
mul(v, M) 计算向量和矩阵相乘
noise( x) 噪声函数,返回值始终在 0 , 1 之间;对于同样的输入,始终返回相同的值(也就是说,并不是真正意义上的随机噪声)。
pow(x, y) $$res = x^{y}$$
radians(x) 函数将角度值转换为弧度值
round(x) Round-to-nearest ,或 closest integer to x 即四舍五入。
rsqrt(x) $$res = \frac{1}{\sqrt{x}}$$, (x > 0)
saturate(x) x < 0, res = 0
x > 1, res = 1
0 < x < 1, res = x
sign(x) x > 0, res=1;
x = 0, res = 0;
x < 0; res = -1
sin(x) 输入参数为弧度,计算正弦值,返回值范围为
sincos(float x, out s, out c) 该函数是同时计算 x 的 sin 值和 cos 值,其中 s=sin(x) , c=cos(x) 。该函数用于“同时需要计算 sin 值和 cos 值的情况”,比分别运算要快很多 !
sinh(x) 计算双曲正弦( hyperbolic sine )值。
smoothstep(min, max, x) 值 x 位于 min 、 max 区间中。如果 x=min ,返回 0 ;如果 x=max ,返回 1 ;如果 x 在两者之间,按照下列公式返回数据:参考: [smoothstep(min, max, x)](#smoothstep(min, max, x))
step(a, b) 如果 a <= b,返回 1 ;否则,返回 0 。
sqrt(x) $$res = \sqrt{x}$$, (x > 0) 。
tan(x) 输入参数为弧度,计算正切值
tanh(x) 计算双曲正切值
transpose(M) M 为矩阵,计算其转置矩阵
abs(x) 返回输入参数的绝对值
acos(x) 反余切函数,输入参数范围为 [-1,1] ,返回 区间的角度值

2. 几何函数 (Geometric Functions)

函数 功能
abs(x) 返回输入参数的绝对值
acos(x) 反余切函数,输入参数范围为 [-1,1] ,返回 区间的角度值
all(x) 如果输入参数均不为 0 ,则返回 ture ;否则返回 flase 。 && 运算
any(x) 输入参数只要有其中一个不为 0 ,则返回 true 。 || 运算
asin(x) 反正弦函数 , 输入参数取值区间为 ,返回角度值范围为
atan(x) 反正切函数,返回角度值范围为
atan2(y,x) 计算 y/x 的反正切值。实际上和 atan(x) 函数功能完全一样,至少输入参数不同。 atan(x) = atan2(x, float(1)) 。
ceil(x) 对输入参数向上取整。例如: ceil(float(1.3)) ,其返回值为 2.0
clamp(x,a,b) 如果 x 值小于 a ,则返回 a ;如果 x 值大于 b ,返回 b ;否则,返回 x 。
cos(x) 返回弧度 x 的余弦值。返回值范围为
cosh(x) 双曲余弦( hyperbolic cosine )函数,计算 x 的双曲余弦值。
cross(A,B) 返回两个三元向量的叉积 (cross product) 。注意,输入参数必须是三元向量!
degrees(x) 输入参数为弧度值 (radians) ,函数将其转换为角度值 (degrees)
determinant(m) 计算矩阵的行列式因子。
dot(A,B) 返回 A 和 B 的点积 (dot product) 。参数 A 和 B 可以是标量,也可以是向量(输入参数方面,点积和叉积函数有很大不同)。
exp(x) 计算 的值, e= 2.71828182845904523536
exp2(x) 计算 的值
floor(x) 对输入参数向下取整。例如 floor(float(1.3)) 返回的值为 1.0 ;但是 floor(float(-1.3)) 返回的值为 -2.0 。该函数与 ceil(x) 函数相对应。
fmod(x,y) 返回 x/y 的余数。如果 y 为 0 ,结果不可预料。
frac(x) res = x - floor(x), 例如: Frac(0.2) = (0.2). Frac(-0.2) = (0.8). Frac(0.0,1.6,1.0) = (0.0,0.6,0.0).
frexp(x, out exp) 将浮点数 x 分解为尾数和指数,即x = m* 2^exp ,返回 m ,并将指数存入 exp 中;如果 x 为 0 ,则尾数和指数都返回 0
isfinite(x) 判断标量或者向量中的每个数据是否是有限数,如果是返回 true ;否则返回 false; 无限的或者非数据 (not-a-number NaN) ,
isinf(x) 判断标量或者向量中的每个数据是否是无限,如果是返回 true ;否则返回 false;
isnan(x) 判断标量或者向量中的每个数据是否是非数据 (not-a-number NaN) ,如果是返回 true ;否则返回 false;
ldexp(x, n) 计算 的值
lerp(a, b, f) 计算 或者 的值。即在下限 a 和上限 b 之间进行插值, f 表示权值。注意,如果 a 和 b 是向量,则权值 f 必须是标量或者等长的向量。
lit(NdotL, NdotH, m) N 表示法向量; L 表示入射光向量; H 表示半角向量; m 表示高光系数。函数计算环境光、散射光、镜面光的贡献,返回的 4 元向量:X 位表示环境光的贡献,总是 1.0 ;Y 位代表散射光的贡献,如果 ,则为 0 ;否则为 Z 位代表镜面光的贡献,如果 或者 ,则位 0 ;否则为 ;W 位始终位 1.0
log(x) 计算 的值, x 必须大于 0
log2(x) 计算 的值, x 必须大于 0
log10(x) 计算 的值, x 必须大于 0
max(a, b) 比较两个标量或等长向量元素,返回最大值。
min(a,b) 比较两个标量或等长向量元素,返回最小值。
modf(x, out ip) 在 Cg Reference Manual 中没有查到
mul(M, N) 计算两个矩阵相乘,如果 M 为 AxB 阶矩阵, N 为 BxC 阶矩阵,则返回 AxC 阶矩阵。下面两个函数为其重载函数。
mul(M, v) 计算矩阵和向量相乘
mul(v, M) 计算向量和矩阵相乘
noise( x) 噪声函数,返回值始终在 0 , 1 之间;对于同样的输入,始终返回相同的值(也就是说,并不是真正意义上的随机噪声)。
pow(x, y) $$res = x^{y}$$
radians(x) 函数将角度值转换为弧度值
round(x) Round-to-nearest ,或 closest integer to x 即四舍五入。
rsqrt(x) $$res = \frac{1}{\sqrt{x}}$$, (x > 0)
saturate(x) x < 0, res = 0
x > 1, res = 1
0 < x < 1, res = x
sign(x) x > 0, res=1;
x = 0, res = 0;
x < 0; res = -1
sin(x) 输入参数为弧度,计算正弦值,返回值范围为
sincos(float x, out s, out c) 该函数是同时计算 x 的 sin 值和 cos 值,其中 s=sin(x) , c=cos(x) 。该函数用于“同时需要计算 sin 值和 cos 值的情况”,比分别运算要快很多 !
sinh(x) 计算双曲正弦( hyperbolic sine )值。
smoothstep(min, max, x) 值 x 位于 min 、 max 区间中。如果 x=min ,返回 0 ;如果 x=max ,返回 1 ;如果 x 在两者之间,按照下列公式返回数据:
step(a, b) 如果 a <= b,返回 1 ;否则,返回 0 。
sqrt(x) $$res = \sqrt{x}$$, (x > 0) 。
tan(x) 输入参数为弧度,计算正切值
tanh(x) 计算双曲正切值
transpose(M) M 为矩阵,计算其转置矩阵
distance( pt1, pt2) 两点之间的欧几里德距离( Euclidean distance )
faceforward(N,I,Ng) 如果 ,返回 N ;否则返回 -N 。
length(v) 返回一个向量的模,即 sqrt(dot(v,v))
normalize( v) 归一化向量
reflect(I, N) 根据入射光方向向量 I ,和顶点法向量 N ,计算反射光方向向量。其中 I 和 N 必须被归一化,需要非常注意的是,这个 I 是指向顶点的;函数只对三元向量有效。
refract(I,N,eta) 计算折射向量, I 为入射光线, N 为法向量, eta 为折射系数;其中 I 和 N 必须被归一化,如果 I 和 N 之间的夹角太大,则返回( 0 , 0 , 0 ),也就是没有折射光线; I 是指向顶点的;函数只对三元向量有效。

3. 纹理映射函数 (Texture Map Functions)

函数 功能
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) 使用导数值(derivatives)查询一维纹理, 并进行深度值比较
Tex1Dproj(sampler1D tex, float2 sq) 一维投影纹理查询
Tex1Dproj(sampler1D tex, float3 szq) 一维投影纹理查询,并比较深度值
Tex2D(sampler2D tex, float2 s) 二维纹理查询
Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy) 使用导数值(derivatives)查询二维纹理
Tex2D(sampler2D tex, float3 sz) 二维纹理查询,并进行深度值比较
Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy) 使用导数值(derivatives)查询二维纹理,并进行深度值比较
Tex2Dproj(sampler2D tex, float3 sq) 二维投影纹理查询
Tex2Dproj(sampler2D tex, float4 szq) 二维投影纹理查询,并进行深度值比较
texRECT(samplerRECT tex, float2 s)
texRECT (samplerRECT tex, float2 s, float2 dsdx, float2 dsdy)
texRECT (samplerRECT tex, float3 sz)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy)
texRECT proj(samplerRECT tex, float3 sq)
texRECT proj(samplerRECT tex, float3 szq)
Tex3d(sampler3D tex, float s) 三维纹理查询
Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询三维纹理
Tex3Dproj(sampler3D tex, float4 szq) 查询三维投影纹理,并进行深度值比较
texCUBE(samplerCUBE tex, float3 s) 查询立方体纹理
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询立方体纹理
texCUBEproj (samplerCUBE tex, float4 sq) 查询投影立方体纹理

4. 偏导数函数 (Derivative Functions)

函数 功能
ddx(a) 参数a对应一个像素位置,返回该像素再X轴上的偏导数
ddy(a) 参数a对应一个像素位置,返回该像素在Y轴上的偏导数
  1. 函数 ddx 和 ddy 用于求取相邻像素间某属性的差值;
  2. 函数 ddx 和 ddy 的输入参数通常是纹理坐标;
  3. 函数 ddx 和 ddy 返回相邻像素键的属性差值;

可以参考:


5. 调试函数 (Debugging Function)

void debug(float4 x)


相关函数解释

smoothstep(min, max, x)


frac(x)

$$
y=x-floor(x)
$$


clip(x)

展开代码

1
2
if (x < 0)
discard;

只要小于0时才丢弃片段

一般都会搭配 step 函数进行判断

1
2
float isShow = step(i.objPos.x, _DissolveThreshold);
clip(1 - isShow - 0.0001); // - 0.0001 确保值会小于0, 不然等于0时不会clip

fwidth(x)

意义: Returns abs(ddx(x)) + abs(ddy(x))

需要注意的是 fwidth(x) 是 DX11 的函数, ,

其他平台的需要用这个 abs(ddx(x)) + abs(ddy(x))

参考: https://blog.csdn.net/candycat1992/article/details/44673819

例如,当我们写下 fwidth(myVar) 时,GPU将会返回 myVar 这个值在当前像素和它的下一个相邻像素之间的差值(与X和Y方向上的下一个像素上该值差的绝对值和)。也就是说,这个值其实就是直线的线性差值。一旦我们知道了在当前像素上这个值的变化程度,我们就可以进行合适程度的滤波操作。因此,对于一张纹理才说,当我们给定它的UV坐标后,更恰当的方法是不仅仅用这个UV坐标直接采样,还应该考虑其周围方形区域内纹理采样的结果,而这个区域就是 ddx 和 ddy 给定的区域。幸运的是,当我们调用 tex2D 这样的函数时,系统背后已经为我们完成了这个操作。而在一些高级的profiles中,还会允许我们自定义滤波窗口的大小