Unity Shader 基础与图形学(一)

核心知识点:本地 / 世界坐标系、向量点乘叉乘、矩阵变换、DX 与 OpenGL 坐标系差异、MVP 矩阵、五大坐标空间、渲染流水线三大阶段、Shader 文件整体结构、Properties、SubShader、Pass、CGPROGRAM 语义、CG 数据类型、顶点着色器 & 片元着色器基础

一、图形数学前置知识

1 坐标系概念

1 概念

分为本地(模型)坐标系世界坐标系 。同一个空间点,在不同坐标系下坐标数值不同;做向量运算,必须保证运算双方处于同一坐标系

2 特性 & 规则
  1. 模型建模时自带本地坐标系;

  2. 世界坐标系是整个场景统一公共坐标系;

  3. 做计算需要把点 / 向量转换到同一坐标系再运算。

2 向量:点乘、叉乘

1 点乘 (Dot)
  1. 公式:a·b = |a||b|cosθ

  2. 几何意义:求 a 向量在 b 向量上的投影;返回结果是标量。

  3. 判断夹角: 结果 > 0:夹角小于 90°,方向接近; 结果 = 0:两向量垂直; 结果 < 0:夹角大于 90°。

  4. Unity API:Vector3.Dot(a,b)

2 叉乘 (Cross)
  1. 公式:a×b = |a||b|sinθ·n

  2. 几何意义:得到一个垂直于 a、b 所在平面的新向量;可以用来求平面法线、判断朝向。

  3. 点乘降维度,叉乘升维度;Unity API:Vector3.Cross(a,b)

3 单位向量

模长等于 1,只保留方向信息,常用于光照、朝向计算。

4 几何变换两种模式

  1. 视图变换(坐标模式):图形不变,坐标系发生旋转 / 平移;

  2. 几何变换(图形模式,项目常用):坐标系不变,物体本身做旋转、缩放、平移。

变换执行顺序:旋转 → 缩放 → 平移

平移:只改变位置,不改变大小形状; 旋转:改变物体朝向; 缩放:改变物体尺寸,会连带改变坐标。

5 OpenGL 与 DX 坐标系差异

  1. OpenGL:笛卡尔右手坐标系;

  2. DX (DirectX,微软):2D 下 Y 轴向下;三维空间两者差异更大;

  3. Unity 对底层图形库做高层封装,开发者一般不用手写底层图形 API。

6 矩阵基础

概念

矩阵是坐标变换的运算规则;模型大量顶点,使用同一个变换矩阵,批量完成所有顶点坐标转换。

  1. 方阵:行数等于列数,如 3×3、4×4;

  2. 单位矩阵:主对角线全部为 1,其余为 0,乘完坐标不变;

  3. DX 使用行向量 ;OpenGL 使用列向量,向量左乘 / 右乘矩阵规则不同。

7 MVP 矩阵与五大坐标空间

1 五大坐标空间
  1. 模型空间 (本地空间):建模时每个模型自带独立坐标系;

  2. 世界空间:整个场景统一坐标系;

  3. 观察空间 (摄像机空间):以摄像机为原点的坐标系;

  4. 剪裁空间:视锥体决定,超出视锥体的物体直接剪裁丢弃不渲染;

  5. 屏幕空间:最终 2D 屏幕像素坐标。

2 MVP 矩阵含义

M (Model 模型矩阵):模型空间 → 世界空间; V (View 视图矩阵):世界空间 → 观察空间; P (Projection 投影矩阵):观察空间 → 剪裁空间;

剪裁空间之后执行屏幕映射,得到屏幕像素坐标。

3 相关知识点对比

表格

空间 作用
模型空间 每个模型独立原点,建模输出
世界空间 场景全局统一坐标
观察空间 以摄像机为原点
剪裁空间 视锥体剔除不在视野内图元
屏幕空间 输出 2D 像素画面

4 模块拓展

底层 DX 裸 API 绘制一个立方体,手写上千行代码;Unity 封装了矩阵运算,开发者直接使用 MVP 内置变量。

二、渲染流水线宏观划分

1 概念

渲染流水线:把模型顶点数据一步步处理,最终输出屏幕像素画面;分为应用阶段、几何阶段、光栅化阶段

2 特性 & 规则

  1. 应用阶段(CPU 执行) 准备模型、贴图数据送入显存; 设置渲染状态; 输出 DrawCall(DC),向 GPU 下发渲染指令。

  2. 几何阶段(GPU 执行) 顶点着色器为主;完成顶点坐标矩阵变换,输出屏幕空间顶点。

  3. 光栅化阶段(GPU 执行) 把顶点构成三角形图元,生成片元;片元着色器计算每一个像素颜色;输出屏幕图像。

关系:CPU (负责运算)-应用程序-DC-Shader-DX/OpenGL-GPU(负责图形渲染)

3 流水线细分步骤

  1. CPU:顶点数据输入,发出 DrawCall;

  2. 顶点着色器:完成顶点坐标变换(必选);

  3. 曲面细分着色器:可选,细分图元;

  4. 几何着色器:可选,处理图元;

  5. 裁剪:丢弃视锥体外图元;

  6. 屏幕映射:顶点转为屏幕坐标;

  7. 三角形设置、三角形遍历:由顶点生成三角形、生成片元;

  8. 片元着色器:计算像素颜色;

  9. 逐片元操作:深度测试、模板测试、混合,输出屏幕最终图像。

4 相关知识点对比

顶点着色器:几何阶段,处理每一个顶点; 片元着色器:光栅化阶段,处理屏幕每一个像素片元。

5 模块拓展

D3D渲染管线:本地坐标-世界坐标-视图坐标-背面拣选-光照-裁剪-投影-视口变换-光栅化

DC (DrawCall) 就是 CPU 发给 GPU 的渲染指令,和之前性能优化知识点串联。

三、Unity Shader 整体文件语法结构

1 概念

Unity Shader 资源文件,搭配 Material 材质球使用;整体由Shader{}根块Properties属性块SubShader子着色器FallBack兜底组成。

2 特性 & 规则

  1. Shader "自定义名字"{}:根,名字会出现在材质球下拉列表;

  2. Properties{}:面板属性声明,暴露参数给 Inspector 材质面板调节;只做声明,CG 代码块内部需要重新定义对应变量。

    格式示例:_Color("颜色",Color) = (1,1,1,1) 常见类型:Color 颜色、Vector4 向量、Int整形、Float 浮点数、Range 范围、Texture 2D 纹理、3D Texture 3D纹理;

  3. SubShader{}子着色器:一个 shader 可以写多个 SubShader;Unity 运行自动挑选当前平台兼容的 SubShader 执行;

  4. Pass{}通道:写渲染逻辑的单元,一个 SubShader 至少要有 1 个 Pass;

  5. FallBack "xxx"兜底;所有 SubShader 都不兼容,回退使用指定内置 shader。

  6. Pass 内部写CGPROGRAM ... ENDCG,中间写 CG 着色器语言代码。

    Shader "Custom/01-shader"{
    Properties{
    //_变量名("在inspector面板上的名字",变量类型)
    _Color("Color",Color)=(1,1,1,1)
    }
    SubShader{
    Pass{
    CGPROGRAM
    float4 _Color;//所有变量使用前必须重新定义
    ENDCG
    }
    }
    FallBack "Diffuse"
    }

3 标签与渲染状态(Pass/SubShader 内设置)

Tags{ "RenderType"="Opaque" "Queue"="Geometry" "LightMode"="ForwardBase" "DisableBatching" "IgnoreProjector"="True"}:渲染类型、渲染队列、光照模式、禁用批处理、忽略投影; LOD 200:层级细节; Cull Back/Front/Off:面剔除;Cull Off 关闭剔除,双面都渲染; ZWrite On/Off:深度写入开关; ZTest Less / Greater:深度测试模式。

4 CG 语言基础数据类型(CGPROGRAM 块内)

  1. float:32 位高精度浮点数;

  2. half:16 位半精度,够用优先用 half,性能更好;

  3. fixed:12 位定点,颜色分量首选;

  4. int:32 位整型;

  5. bool布尔;

  6. float2/float3/float4 向量;float4x4矩阵;

  7. sampler2D / samplerCube / sampler3D:纹理采样器;

  8. float a[10]:数组;

  9. struct{};:结构体。

颜色 RGBA4 个分量,优先使用fixed4

5 顶点着色器、片元着色器基础

1 编译指令
复制代码
#pragma vertex vert   //指定vert为顶点着色器函数的名称,完成顶点坐标从模型空间到剪裁空间的变换
#pragma fragment frag //指定frag为片元着色器函数的名称,返回模型对应屏幕上的每一个像素的颜色值
2 语义绑定 (semantic)

输入语义:告诉 GPU 把模型数据传给函数参数,如POSITION顶点坐标; 输出语义:告诉 GPU 返回数据用途,SV_POSITION输出剪裁空间坐标;SV_Target输出像素颜色。

3 最简示例代码片段
复制代码
#pragma vertex vert
#pragma fragment frag
// 顶点输入语义 POSITION
//POSITION:告诉系统,需要把顶点坐标传递给变量v
//SV_POSITION:告诉系统,返回值是剪裁空间下的顶点坐标
float4 vert(float4 pos:POSITION) :SV_POSITION{
    // mul矩阵向量乘法,UnityObjectToClipPos等价乘MVP矩阵
    return mul(UNITY_MATRIX_MVP,pos);
}
//片元返回颜色给像素 SV_Target
//SV_Target:告诉系统。返回值需要模型对应屏幕上的每一个像素的颜色值
fixed4 frag():SV_Target{
    return fixed4(1,0,0,1); //输出红色
}

4 相关知识点对比

Properties 块:仅面板声明;CGPROGRAM 内部必须重新定义同名变量,才能在着色器代码读取。

5 模块拓展

当前示例缺陷:顶点着色器数据无法传递到片元着色器;下午课程讲解结构体传递插值数据。

综合拓展

1 完整知识链路 图形数学(坐标系、点乘叉乘、矩阵)→五大坐标空间→MVP 矩阵 →渲染流水线三大阶段(CPU 应用阶段、GPU 几何、光栅化) →Unity Shader 文件整体结构 Properties / SubShader / Pass / FallBack → CG 语言基础类型 →顶点着色器、片元着色器基础、语义绑定。

2 高频易错清单

  1. 向量运算不在同一坐标系,计算结果错误;需要先统一坐标空间;

  2. Properties 块声明变量,忘记在 CGPROGRAM 块内重新定义,代码拿不到参数;

  3. 混淆 DX 行向量、OpenGL 列向量,矩阵乘法顺序出错;

  4. 忘记语义绑定 POSITION/SV_POSITION/SV_Target,GPU 无法传递输入输出数据。

3 核心考点 点乘叉乘几何意义;五大坐标空间;MVP 矩阵作用;渲染流水线三阶段分工(CPU/GPU 分工);Shader 文件整体结构;Properties 作用;Pass 通道;CG 精度类型 fixed/half/float;顶点着色器与片元着色器职责;语义绑定。

4 进阶拓展方向 顶点片元之间结构体传递插值数据、纹理采样、光照模型。

相关推荐
百里香酚兰10 小时前
【Unity学习笔记】如何把粉色Prefab还原
笔记·学习·unity
xcLeigh11 小时前
Unity基础:使用Transform控制物体旋转——Rotate与LookAt详解
unity·教程·transform·rotate·lookat
平行云14 小时前
3D应用推流太贵太慢?ImmerShare Lite:利用本地算力实现极简一键分享
unity·ue5·实时云渲染·云桌面·像素流·云游戏·串流
淡海水15 小时前
11-04-Unity-Span-foreach-LINQ的分配与热路径边界
unity·c#·linq·foreach·span
灸木1 天前
Unity 多线程与并发:什么时候该用多线程?
unity
淡海水2 天前
11-02-Unity-Mono-vs-IL2CPP-两种脚本后端的数据结构行为差异
数据结构·unity·游戏引擎·il2cpp·mono
彧azz2 天前
初学Unity:编辑器
笔记·学习·unity·游戏引擎
小小数媒成员2 天前
GPU优化(1)
游戏·unity·游戏引擎