常用

最常用的函数

排名函数用途频率
1UnityObjectToClipPos顶点变换⭐⭐⭐⭐⭐
2UnityObjectToWorldNormal法线变换⭐⭐⭐⭐⭐
3UnityObjectToWorldDIr切线变换⭐⭐⭐⭐⭐
4normalize向量归一化⭐⭐⭐⭐⭐
5dot点积(光照)⭐⭐⭐⭐⭐
6tex2D纹理采样⭐⭐⭐⭐⭐
7UnityWorldSpaceLightDir光照方向⭐⭐⭐⭐
8UnityWorldSpaceViewDir视线方向⭐⭐⭐⭐
9mul(unity_ObjectToWorld, v.vertex)世界坐标⭐⭐⭐⭐
10lerp插值混合⭐⭐⭐⭐
11saturate限制[0,1]⭐⭐⭐
12TRANSFORM_TEX(v.texcoord, _MainTex)UV控制⭐⭐⭐⭐⭐
13clip();裁剪⭐⭐⭐⭐

最常用的5个矩阵

排名矩阵变换频率
1unity_ObjectToWorld模型→世界⭐⭐⭐⭐⭐
2UNITY_MATRIX_MVP模型→裁剪⭐⭐⭐⭐
3UNITY_MATRIX_V世界→视图⭐⭐⭐
4UNITY_MATRIX_P视图→裁剪⭐⭐⭐
5UNITY_MATRIX_VP世界→裁剪⭐⭐⭐

全部

一、Unity坐标空间变换函数总表

位置变换函数

函数名输入输出说明示例
UnityObjectToClipPos模型空间位置裁剪空间位置最常用,模型→裁剪float4 clipPos = UnityObjectToClipPos(v.vertex);
UnityObjectToViewPos模型空间位置视图空间位置模型→视图float3 viewPos = UnityObjectToViewPos(v.vertex);
UnityWorldToViewPos世界空间位置视图空间位置世界→视图float3 viewPos = UnityWorldToViewPos(worldPos);
UnityWorldToClipPos世界空间位置裁剪空间位置世界→裁剪float4 clipPos = UnityWorldToClipPos(worldPos);
mul(unity_ObjectToWorld, v.vertex)模型空间位置世界空间位置模型→世界(手动)float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

方向/法线变换函数

函数名输入输出说明示例
UnityObjectToWorldNormal模型空间法线世界空间法线自动处理转置逆float3 worldNormal = UnityObjectToWorldNormal(v.normal);
UnityObjectToWorldDir模型空间方向世界空间方向方向向量变换float3 worldDir = UnityObjectToWorldDir(v.tangent.xyz);
UnityWorldToObjectDir世界空间方向模型空间方向反向变换float3 objDir = UnityWorldToObjectDir(lightDir);

光照相关函数

函数名输入输出说明示例
UnityWorldSpaceLightDir世界空间位置光源方向(世界空间)自动处理点光源/方向光float3 lightDir = UnityWorldSpaceLightDir(worldPos);
ObjSpaceLightDir模型空间位置光源方向(模型空间)模型空间光照float3 lightDir = ObjSpaceLightDir(v.vertex);
UnityWorldSpaceViewDir世界空间位置视线方向(世界空间)从顶点指向相机float3 viewDir = UnityWorldSpaceViewDir(worldPos);
ObjSpaceViewDir模型空间位置视线方向(模型空间)模型空间视线float3 viewDir = ObjSpaceViewDir(v.vertex);

屏幕空间相关函数

函数名输入输出说明示例
ComputeScreenPos裁剪空间位置屏幕空间位置用于屏幕特效float4 screenPos = ComputeScreenPos(clipPos);
ComputeGrabScreenPos裁剪空间位置抓取屏幕位置用于折射等效果float4 grabPos = ComputeGrabScreenPos(clipPos);

深度相关函数

函数名输入输出说明示例
COMPUTE_EYEDEPTHSV_POSITION线性眼空间深度计算深度值COMPUTE_EYEDEPTH(o.depth);
DECODE_EYEDEPTH深度纹理值线性眼空间深度解码深度float depth = DECODE_EYEDEPTH(depthTex);
Linear01Depth深度缓冲值[0,1]线性深度深度值线性化float depth = Linear01Depth(depthValue);
LinearEyeDepth深度缓冲值眼空间线性深度实际距离float depth = LinearEyeDepth(depthValue);

二、Unity变换矩阵总表

基础变换矩阵

矩阵名类型变换说明使用示例
unity_ObjectToWorldfloat4x4模型→世界M矩阵float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
unity_WorldToObjectfloat4x4世界→模型M逆矩阵float3 objPos = mul(unity_WorldToObject, worldPos).xyz;
UNITY_MATRIX_Vfloat4x4世界→视图V矩阵(视图矩阵)float3 viewPos = mul(UNITY_MATRIX_V, worldPos).xyz;
UNITY_MATRIX_I_Vfloat4x4视图→世界V逆矩阵float3 worldPos = mul(UNITY_MATRIX_I_V, viewPos).xyz;
UNITY_MATRIX_Pfloat4x4视图→裁剪P矩阵(投影矩阵)float4 clipPos = mul(UNITY_MATRIX_P, viewPos);

组合变换矩阵

矩阵名类型变换等价于使用示例
UNITY_MATRIX_VPfloat4x4世界→裁剪P × Vfloat4 clipPos = mul(UNITY_MATRIX_VP, worldPos);
UNITY_MATRIX_MVPfloat4x4模型→裁剪P × V × Mfloat4 clipPos = mul(UNITY_MATRIX_MVP, v.vertex);
UNITY_MATRIX_MVfloat4x4模型→视图V × Mfloat3 viewPos = mul(UNITY_MATRIX_MV, v.vertex).xyz;
UNITY_MATRIX_IT_MVfloat4x4法线变换(模型→视图)(MV)^-T(转置逆)float3 viewNormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);

特殊矩阵

矩阵名类型说明使用场景
unity_MatrixInvPfloat4x4投影矩阵的逆深度重建世界坐标
unity_MatrixInvVPfloat4x4VP矩阵的逆屏幕坐标→世界坐标
unity_WorldToCamerafloat4x4世界→相机矩阵等同于UNITY_MATRIX_V
unity_CameraToWorldfloat4x4相机→世界矩阵等同于UNITY_MATRIX_I_V

三、空间变换流程对照表

完整变换链

空间坐标范围如何到达常用矩阵/函数用途
模型空间物体局部坐标从Mesh读取v.vertex顶点动画、物体局部效果
↓M矩阵unity_ObjectToWorld
世界空间场景全局坐标mul(unity_ObjectToWorld, v.vertex)UnityObjectToWorldNormal光照计算、物体交互
↓V矩阵UNITY_MATRIX_V
视图空间相机为原点mul(UNITY_MATRIX_V, worldPos)UnityWorldToViewPos雾效、深度计算
↓P矩阵UNITY_MATRIX_P
裁剪空间(x,y,z,w)UnityObjectToClipPos(v.vertex)UNITY_MATRIX_MVP输出到SV_POSITION
↓透视除法硬件自动
NDC空间[-1,1]或[0,1]/w(硬件)-归一化坐标
↓视口变换硬件自动
屏幕空间像素坐标ComputeScreenPos-屏幕特效、UI

四、常用变换组合速查表

位置变换快速查询

从 → 到方法1(函数)方法2(矩阵)推荐
模型 → 世界-mul(unity_ObjectToWorld, v.vertex).xyz矩阵
模型 → 视图UnityObjectToViewPos(v.vertex)mul(UNITY_MATRIX_MV, v.vertex).xyz函数
模型 → 裁剪UnityObjectToClipPos(v.vertex)mul(UNITY_MATRIX_MVP, v.vertex)函数⭐
世界 → 视图UnityWorldToViewPos(worldPos)mul(UNITY_MATRIX_V, float4(worldPos, 1)).xyz函数
世界 → 裁剪UnityWorldToClipPos(worldPos)mul(UNITY_MATRIX_VP, float4(worldPos, 1))函数
视图 → 裁剪-mul(UNITY_MATRIX_P, float4(viewPos, 1))矩阵

法线/方向变换快速查询

从 → 到方法1(函数)方法2(矩阵)推荐注意事项
模型法线 → 世界UnityObjectToWorldNormal(v.normal)mul((float3x3)unity_WorldToObject, v.normal)函数⭐自动转置逆
模型方向 → 世界UnityObjectToWorldDir(v.tangent.xyz)mul((float3x3)unity_ObjectToWorld, dir)函数不需要转置逆
世界方向 → 模型UnityWorldToObjectDir(worldDir)mul((float3x3)unity_WorldToObject, dir)函数-

五、光照计算常用函数表

光照方向获取

函数输入空间输出光源类型支持说明
UnityWorldSpaceLightDir(worldPos)世界空间位置世界空间光源方向方向光、点光源、聚光灯自动处理衰减
ObjSpaceLightDir(v.vertex)模型空间位置模型空间光源方向方向光、点光源、聚光灯模型空间光照
_WorldSpaceLightPos0-世界空间光源位置/方向主光源方向光时为方向向量

视线方向获取

函数输入空间输出说明
UnityWorldSpaceViewDir(worldPos)世界空间位置世界空间视线方向从顶点指向相机
ObjSpaceViewDir(v.vertex)模型空间位置模型空间视线方向模型空间视线
_WorldSpaceCameraPos-世界空间相机位置相机位置

光照颜色/属性

变量名类型说明使用场景
_LightColor0fixed4主光源颜色前向渲染
UNITY_LIGHTMODEL_AMBIENTfixed4环境光颜色所有管线
unity_SHAr, unity_SHAg, unity_SHAbfloat4球谐光照间接光照

六、纹理采样相关函数表

基础采样函数

函数说明Shader Model要求示例
tex2D(sampler, uv)2D纹理采样2.0+fixed4 col = tex2D(_MainTex, i.uv);
tex2Dlod(sampler, float4(uv, 0, mip))指定mipmap层级3.0+fixed4 col = tex2Dlod(_MainTex, float4(i.uv, 0, 0));
tex2Dproj(sampler, float4)投影纹理采样2.0+fixed4 col = tex2Dproj(_MainTex, screenPos);
tex2Dbias(sampler, float4(uv, 0, bias))带偏移的采样2.0+fixed4 col = tex2Dbias(_MainTex, float4(i.uv, 0, -1));

纹理采样(URP/HDRP)

函数说明示例
SAMPLE_TEXTURE2D(tex, sampler, uv)URP/HDRP标准采样SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
SAMPLE_TEXTURE2D_LOD(tex, sampler, uv, lod)指定LODSAMPLE_TEXTURE2D_LOD(_MainTex, sampler_MainTex, i.uv, 0);
SAMPLE_DEPTH_TEXTURE(tex, sampler, uv)深度纹理采样SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.uv);

衍生指令(需要3.0+)

函数说明用途示例
ddx(x)x对屏幕X的偏导计算变化率float dUdx = ddx(i.uv.x);
ddy(y)y对屏幕Y的偏导计算变化率float dUdy = ddy(i.uv.y);
fwidth(x)abs(ddx(x)) + abs(ddy(x))边缘检测float edge = fwidth(i.uv);

七、数学函数速查表

常用数学函数

函数说明范围示例
dot(a, b)点积[-1, 1](归一化向量)float ndotl = dot(normal, lightDir);
cross(a, b)叉积垂直向量float3 binormal = cross(normal, tangent);
normalize(v)归一化长度=1float3 normal = normalize(i.worldNormal);
length(v)向量长度>= 0float dist = length(worldPos - _WorldSpaceCameraPos);
distance(a, b)两点距离>= 0float dist = distance(worldPos, lightPos);
reflect(i, n)反射向量-float3 reflectDir = reflect(-viewDir, normal);
refract(i, n, eta)折射向量-float3 refractDir = refract(-viewDir, normal, 1.0/1.33);
lerp(a, b, t)线性插值-fixed3 color = lerp(shadowColor, litColor, ndotl);
smoothstep(min, max, x)平滑插值[0, 1]float smooth = smoothstep(0.4, 0.6, ndotl);
step(edge, x)阶梯函数0或1float toon = step(0.5, ndotl);
saturate(x)限制到[0,1][0, 1]float val = saturate(ndotl);
clamp(x, min, max)限制范围[min, max]float val = clamp(ndotl, 0.2, 0.8);
pow(x, y)x的y次方-float spec = pow(ndoth, _Gloss);
exp(x)e^x-float fog = exp(-depth * density);
log(x)ln(x)--
sqrt(x)平方根-float dist = sqrt(x*x + y*y);
abs(x)绝对值>= 0float val = abs(x);
sign(x)符号-1, 0, 1float s = sign(x);
floor(x)向下取整-float stepped = floor(x * 5) / 5;
ceil(x)向上取整-float stepped = ceil(x * 5) / 5;
frac(x)小数部分[0, 1)float f = frac(x);
fmod(x, y)x % y-float m = fmod(x, 2.0);

三角函数

函数说明输入单位范围
sin(x)正弦弧度[-1, 1]
cos(x)余弦弧度[-1, 1]
tan(x)正切弧度(-∞, +∞)
asin(x)反正弦-[-π/2, π/2]
acos(x)反余弦-[0, π]
atan(x)反正切-[-π/2, π/2]
atan2(y, x)两参数反正切-[-π, π]

八、语义(Semantics)速查表

顶点着色器输入语义

语义类型说明来源
POSITIONfloat4顶点位置(模型空间)Mesh
NORMALfloat3法线(模型空间)Mesh
TANGENTfloat4切线(模型空间,w=±1)Mesh
TEXCOORD0-7float2/4UV坐标Mesh
COLORfixed4顶点颜色Mesh
SV_VertexIDuint顶点索引系统自动
SV_InstanceIDuint实例索引(GPU Instancing)系统自动

顶点着色器输出/片元着色器输入语义

语义类型说明必须
SV_POSITIONfloat4裁剪空间位置✅必须
TEXCOORD0-9float1-4任意插值数据可选
COLOR0-1fixed4颜色数据可选
SV_IsFrontFacebool是否正面(片元输入)可选

完整的顶点输入语义列表:

语义含义数据类型
POSITION顶点位置(模型空间)float4
NORMAL法线(模型空间)float3
TANGENT切线(模型空间)float4
TEXCOORD0第一套UVfloat2/float4
TEXCOORD1第二套UV(光照贴图)float2/float4
TEXCOORD2第三套UVfloat2/float4
TEXCOORD3第四套UVfloat2/float4
COLOR顶点颜色float4
SV_VertexID顶点IDuint
SV_InstanceID实例ID(GPU Instancing)uint

片元着色器输出语义

语义类型说明用途
SV_Targetfixed4渲染目标0输出颜色(单目标)
SV_Target0-7fixed4渲染目标0-7MRT(多目标)
SV_Depthfloat自定义深度深度输出

常用系统值语义

语义使用位置含义
SV_POSITION顶点输出裁剪空间位置
SV_Target片元输出渲染目标
SV_Depth片元输出深度值
SV_VertexID顶点输入顶点索引
SV_InstanceID顶点输入实例索引
SV_PrimitiveID几何/片元输入图元ID
SV_IsFrontFace片元输入是否正面
SV_RenderTargetArrayIndex几何输出渲染目标数组索引

示例1:SV_VertexID(顶点ID)

struct appdata
{
    float4 vertex : POSITION;
    uint vertexID : SV_VertexID;  // 顶点索引
};

v2f vert(appdata v)
{
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    
    // 使用顶点ID生成渐变色
    float t = (float)v.vertexID / 100.0;
    o.color = float4(t, 1-t, 0, 1);
    
    return o;
}

示例2:SV_IsFrontFace(正反面检测)

fixed4 frag(v2f i, bool isFrontFace : SV_IsFrontFace) : SV_Target
{
    // 正面显示红色,背面显示蓝色
    if (isFrontFace)
        return fixed4(1, 0, 0, 1);  // 红色
    else
        return fixed4(0, 0, 1, 1);  // 蓝色
}

示例3:SV_PrimitiveID(三角形ID)

fixed4 frag(v2f i, uint primitiveID : SV_PrimitiveID) : SV_Target
{
    // 每个三角形不同颜色
    float hue = frac((float)primitiveID * 0.618);
    return fixed4(hue, 1-hue, 0.5, 1);
}

示例4:SV_Depth(自定义深度)

struct fragOutput
{
    fixed4 color : SV_Target;
    float depth : SV_Depth;
};

fragOutput frag(v2f i)
{
    fragOutput o;
    
    o.color = tex2D(_MainTex, i.uv);
    
    // 强制深度为0.5(总在中间)
    o.depth = 0.5;
    
    return o;
}

九、渲染状态关键字表

剔除模式

关键字说明
Cull Back剔除背面(默认)
Cull Front剔除正面
Cull Off双面渲染

深度测试

关键字说明
ZTest Less深度小于通过(默认)
ZTest LEqual深度小于等于通过
ZTest Greater深度大于通过
ZTest GEqual深度大于等于通过
ZTest Equal深度等于通过
ZTest NotEqual深度不等于通过
ZTest Always总是通过
ZTest Never总不通过

深度写入

关键字说明
ZWrite On写入深度(默认)
ZWrite Off不写入深度(透明物体)

混合模式

关键字效果用途
Blend Off无混合(默认)不透明物体
Blend SrcAlpha OneMinusSrcAlpha标准透明透明物体
Blend One One加法混合发光、粒子
Blend OneMinusDstColor One柔和叠加特效
Blend DstColor Zero乘法混合阴影、滤镜

Shader基本模板

Shader "Tutorial/CompleteReference"
{
    Properties
    {
        _MainTex ("Albedo", 2D) = "white" {}
        _Color ("Color", Color) = (1,1,1,1)
    }
    
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            
            Cull Back       // 剔除背面
            ZWrite On       // 写入深度
            ZTest LEqual    // 深度测试
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #pragma target 3.0
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Color;
            
            // ===========================================
            // 顶点着色器输入
            // ===========================================
            struct appdata
            {
                float4 vertex : POSITION;     // 模型空间位置
                float3 normal : NORMAL;       // 模型空间法线
                float4 tangent : TANGENT;     // 模型空间切线
                float2 uv : TEXCOORD0;        // UV0
                float2 uv2 : TEXCOORD1;       // UV1(光照贴图)
                fixed4 color : COLOR;         // 顶点颜色
            };
            
            // ===========================================
            // 顶点到片元
            // ===========================================
            struct v2f
            {
                float4 pos : SV_POSITION;     // 裁剪空间位置(必须)
                float2 uv : TEXCOORD0;        // UV
                float3 worldPos : TEXCOORD1;  // 世界空间位置
                float3 worldNormal : TEXCOORD2; // 世界空间法线
                float3 worldTangent : TEXCOORD3; // 世界空间切线
                float3 worldBinormal : TEXCOORD4; // 世界空间副法线
            };
            
            // ===========================================
            // 顶点着色器
            // ===========================================
            v2f vert(appdata v)
            {
                v2f o;
                
                // 位置变换
                o.pos = UnityObjectToClipPos(v.vertex);           // 模型→裁剪
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; // 模型→世界
                
                // 法线变换
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                o.worldBinormal = cross(o.worldNormal, o.worldTangent) * v.tangent.w;
                
                // UV变换
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                
                return o;
            }
            
            // ===========================================
            // 片元着色器
            // ===========================================
            fixed4 frag(v2f i) : SV_Target
            {
                // 归一化插值后的向量
                float3 worldNormal = normalize(i.worldNormal);
                
                // 光照方向(世界空间)
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                
                // 视线方向(世界空间)
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                
                // 漫反射
                float ndotl = max(0, dot(worldNormal, worldLightDir));
                
                // 采样纹理
                fixed4 albedo = tex2D(_MainTex, i.uv) * _Color;
                
                // 最终颜色
                fixed3 diffuse = _LightColor0.rgb * albedo.rgb * ndotl;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo.rgb;
                
                return fixed4(ambient + diffuse, 1.0);
            }
            ENDCG
        }
    }
    
    FallBack "Diffuse"
}