世界杯赔率_男乒世界杯决赛 - fjpftz.com

HOME> 世界杯冠军奖杯> 《Shader入门精要》基础篇笔记

《Shader入门精要》基础篇笔记

2025-10-09 14:21:24

Ch1.欢迎来到Shader的世界Ch2.渲染流水线2.1 应用阶段2.2 几何阶段2.3 光栅化阶段2.4 课后答疑DrawCall什么是ShaderCh3.UnityShader基础3.1 UnityShader概述3.2 Shader结构:名称3.3 Shader结构:PropertiesProperties属性!!!3.4 Shader结构:SubShader状态设置!!!SubShader专属标签!!!Pass语义块Pass名称Pass专属标签!!!特殊的Pass3.5 Shader结构:Fallback其他语义:有时间自行完善3.6 着色器分类3.7 课后答疑UnityShader != 真正的ShaderCh4.学习Unity所需的数学基础4.1 笛卡尔坐标系4.2 点和矢量4.3 矩阵定义矩阵运算矩阵乘法性质特殊矩阵4.4 变换4.5 坐标空间变换个人心得顶点的坐标变换过程难点:投影矩阵推导正交投影矩阵透视投影矩阵4.6 法线变换4.7 Shader内置变量!!!变换矩阵摄像机和屏幕参数4.8 答疑解惑(了解)Cg中的矢量和矩阵类型获取Unity中的屏幕坐标法1.frag函数直接声明语义法2.ComputeScreenPos函数一轮整理:2021年6月16日17:19:23

二轮整理:2021年10月28日20:24:37

作者:聪头

本书Unity版本:v5.2.1

Github:https://github.com/candycat1992/Unity_Shaders_Book

本文档为独自整理的笔记,故章节的主题和书本不一致!

Ch1.欢迎来到Shader的世界介绍各章节内容,本文档为独自整理的笔记,故章节的主题和书本不一致!

Ch2.渲染流水线

2.1 应用阶段

输入:无 执行者:CPU 输出结果:渲染图元(点、线三角面等)

过程:

把数据加载到显存中:硬盘 —> 内存 —> 显存

内存数据加载到显存后,可以移除。但对于一些数据,如用于碰撞检测的网格数据,则不希望移除场景数据:摄像机、视锥体、场景中包含模型、光源信息等。粗粒度剔除,把那些不可见的物体剔除出去。

设置渲染状态:定义场景中网格是怎样被渲染的

简单理解为Unity给Material绑定Shader,给模型绑定Material并设置参数 例如,指定顶点/片元着色器,光源属性,材质等

调用DrawCall

由CPU发给GPU的命令,指向一个需要被渲染的图元(primitives)列表。给定一个DrawCall,GPU会根据渲染状态(如材质、纹理、着色器等)和所有输入的顶点数据进行计算,最终输出成屏幕上显示的像素。该计算过程,就是GPU流水线

2.2 几何阶段

输入:CPU 执行者:GPU 输出结果:屏幕空间的顶点信息

过程:

顶点着色器:完全可编程控制,必须实现

用于实现顶点的空间变换、顶点着色等坐标变换:对顶点的坐标(即位置)进行某种变换。必须完成:把顶点从模型空间转换到齐次裁剪空间。

曲面细分着色器:完全可编程控制,可选

细分图元

几何着色器:完全可编程控制,可选

用于执行逐图元的着色操作或产生更多图元

裁剪:可配置,不可编程

裁剪不在相机范围内的顶点,并剔除三角图元的面片

屏幕映射:GPU固定实现

负责把每个图元的坐标转换到屏幕坐标系中

2.3 光栅化阶段

输入:屏幕坐标系下的顶点位置以及和它们相关的额外信息,如深度值(z坐标)、法线方向、视角方向等 执行者:GPU 输出结果:计算每个图元覆盖了哪些像素,以及为这些像素计算它们的颜色

过程:

三角形设置:GPU固定实现

计算光栅化一个三角形网格所需的信息上一阶段输出的都是三角网格的顶点,即每条边的两个端点。我们需要计算每条边上的像素坐标,得到整个三角网格对像素的覆盖情况。计算三角网格表示数据的过程就叫做三角形设置

三角形遍历:GPU固定实现

片元:像素被一个三角网格覆盖,就会生成一个片元(fragment)。一个片元并不是真正意义上的像素,而是包含了很多状态的集合,这些状态用于计算每个像素的最终颜色(利用上一阶段的三角网格的3个顶点信息对整个覆盖区域的像素进行插值)。这些状态包括(但不限于)它的屏幕坐标、深度信息,以及其他从几何阶段输出的顶点颜色,例如法线、纹理坐标等找到哪些像素被三角网格覆盖的过程就是三角形遍历,这个阶段也叫做扫描变换(Scan Conversion)

片元着色器:完全可编程控制,可选

输入的是上一个阶段对顶点信息插值得到的结果,输出的是一个或多个颜色值。这一阶段可以完成很多重要的渲染技术,如纹理采样

解释: 上一阶段不会影响屏幕上每个像素的颜色值,而是会产生一系列的数据,用来表述一个三角网格是怎样覆盖每个像素的。一句话说,每个片元只负责存储这样一系列数据,真正会对像素产生影响的是下一阶段,逐片元操作

逐片元操作:可配置,不可编程

很多重要操作,如修改颜色、深度缓冲、混合等 逐片元操作阶段所做的操作。只有通过了所有的测试后,新生成的片元才能和颜色缓冲区中已经存在的像素颜色进行混合,最后再写入颜色缓冲区中

区别:

1.模板测试和写入一起开和关;深度测试和写入可分别开启

2.模板测试未通过也可更新值;深度测试没通过不可更新值

源颜色:片元着色器的颜色值

目标颜色:已经存在于颜色缓冲区中颜色值

补充:

屏幕显示的是颜色缓冲区中的颜色值。GPU会使用双重缓冲的策略,对场景的渲染是在幕后发生的,即在后置缓冲区中。一旦场景已经被渲染到了后置缓冲区中,GPU就会交换前置缓冲区和后置缓冲区中的内容,前置缓冲区就是显示在屏幕上的图像。由此,保证我们看到的图像总是连续的

2.4 课后答疑

DrawCall性能瓶颈:CPU(而非GPU),每次调用DrawCall,CPU需要向GPU发送很多内容,包括数据、状态和命令等。在这一阶段,CPU需要完成很多工作,例如检查渲染状态等。而GPU的渲染能力很强,因此渲染速度往往快于CPU提交命令的速度。如果DrawCall数量太多,CPU就会把大量时间花费在提交DrawCall上,造成CPU过载

减少DrawCall的办法:

避免使用大量很小的网格,当不可避免地使用很小的网格时,考虑是否可以合并它们避免使用过多的材质。尽量在不同的网格之间共有同一个材质

什么是Shader

GPU流水线上一些可高度编程的阶段,而由着色器编译出来的最终代码是会在GPU上运行的(对于固定管线的渲染来说,着色器有时等同于一些特定的渲染设置)

Ch3.UnityShader基础

3.1 UnityShader概述

Unity Material和Shader

把材质(Material)想象成组件,把UnityShader想象成源文件。

组件的目的:个性化 源文件的目的:通用性

ShaderLab:为Unity开发者提供的高层级的渲染抽象层

3.2 Shader结构:名称

使用”/“控制位置

3.3 Shader结构:Properties

材质和UnityShader的桥梁,通过材质面板传递Shader属性

解释:

Name:Shader访问的名字display name:材质面板上的名字Propertype:类型DefaultValue:默认值

Properties属性!!!

说明:

2D、Cube、3D的内置纹理默认值包括:white、black、gray、bump

例子

为了在Shader中可以访问到这些属性,我们需要在Cg代码片中定义和这些属性类型相匹配的变量。 需要说明的是,即使我们不在Properties语义块中声明这些属性,也可以直接在Cg代码片中定义变量。此时,我们可以通过过脚本向Shader中传递这些属性

3.4 Shader结构:SubShader

每个UnityShader可以包含多个SubShader语义块(至少一个),加载时Unity选择第一个可在目标平台运行的SubShader。如果都不支持,使用Fallback

解释:不同显卡具有不同的能力,写SubShader就是为了在旧显卡使用计算复杂度较低的着色器,在高级显卡使用计算复杂度较高的着色器,以便提供更出色的画面

重要组成

SubShader:定义了一系列Pass以及可选的状态([RenderSetup])和标签([Tags])设置Pass:定义了一次完整的渲染流程

语法:

状态设置!!!

SubShader和Pass语法相同

SubShader专属标签!!!概念:SubShader标签是一个键值对,它的键和值都是字符串类型,用来告诉Unity渲染引擎:我希望怎样以及何时渲染这个对象

语法:

类型:

Pass语义块语法:

Pass名称

Name “MyPassName”通过Pass名称,我们可以使用ShaderLab的UsePass命令来直接使用其他Unity Shader中的Pass

例如:UsePass “MyShader/MYPASSNAME”

Unity内部会把所有Pass名称转换成大写字母

Pass专属标签!!!概念:Pass标签也是告诉渲染引擎我们希望怎样来渲染物体

语法:

类型:

特殊的Pass

UsePass:复用其他UnityShader中的PassGrabPass:抓取屏幕并将结果存储在一张纹理中,以用于后续的Pass处理

3.5 Shader结构:Fallback

所有SubShader都不能运行,使用该ShaderFallback还会影响阴影的投射,在渲染阴影纹理中,Unity会在每个UnityShader中寻找一个阴影投射的Pass。Fallback使用的内置Shader中包含了这样一个通用的Pass

语法:

例子:Fallback "VertexLit"

其他语义:有时间自行完善

扩展编辑界面:CustomEditor命令分组:Category

3.6 着色器分类表面着色器

Surface Shader

概念:Unity自己创造的一种着色器代码类型,是对顶点/片元着色器更高层的抽象,本质仍是顶点/片元着色器,定义在SubShader块(而非Pass块)中的CGPROGRAM和ENDCG之间。可以使用Cg/HLSL几乎所有语法。

顶点/片元着色器

Vertex/Fragment Shader

概念:本书使用。使用Cg/HLSL语言来编写,更复杂但更灵活。定义在Pass内

3.7 课后答疑

UnityShader != 真正的Shader

Ch4.学习Unity所需的数学基础

4.1 笛卡尔坐标系二维笛卡尔坐标系:

三维笛卡尔坐标系:

基矢量:3个坐标轴标准正交基:3个坐标轴之间互相垂直,且长度为1正交基:坐标轴之间互相垂直但长度不为1

判断坐标系:哪只手满足就是哪个坐标系

大拇指:+x食指:+y中指:+z

判断旋转正方向:伸出坐标系对应的手,大拇指对准旋转轴正方向,握拳方向就是旋转正方向(左手顺时针,右手逆时针)

4.2 点和矢量点:n维空间中的一个位置,没有大小、宽度的概念

矢量(向量):n维空间中一种包含了模和方向的有向线段

标量:只有模,没有方向

规定:

矢量运算:

矢量和标量乘法/除法: 矢量的加法和减法: 矢量的模: 单位矢量: 点积

公式1:公式2(平行四边形面积):

叉积

公式:模:方向:确定坐标系,根据左(右)手法则,从a到b握拳,拇指方向为叉积结果方向

4.3 矩阵

定义

mxn个标量组成的长方形数组

行向量和列向量:

矩阵运算

矩阵和标量相乘: 矩阵和矩阵相乘:

矩阵乘法性质

矩阵乘法不满足交换律:矩阵乘法满足结合律:

特殊矩阵1.方块矩阵:简称方阵,行和列数目相等

对角元素:行和列号相等的元素。如m11 对角矩阵:除对角元素外均为0的矩阵。非常适合次方计算。

2.单位矩阵:任何矩阵和它相乘的结果还是原来的矩阵

3.转置矩阵:实际是对原矩阵的一种运算。行列对调

性质一: 性质二:

4.逆矩阵:满足

逆矩阵判断:

必须是方阵行列式不为0

逆矩阵性质:

逆矩阵的逆矩阵是原矩阵本身(设M可逆) 单位矩阵的逆矩阵是它本身 转置矩阵的逆矩阵是逆矩阵的转置 矩阵串接相乘后的逆矩阵等于反向串接各个矩阵的逆矩阵。可推广到多维

5.正交矩阵

如果一个方阵M和它的转置矩阵的乘积是单位矩阵的话,我们就说这个矩阵是正交的

等价于

推论

- c1 -:表示一个三维向量c1的行展开式

4.4 变换变换:指的是我们把一些数据,如点、方向矢量甚至颜色等,经过某种方式进行转换的过程

线性变换:指可以保留矢量加和标量乘的变换

仿射变换:合并线性变换和平移变换。仿射变换可以使用一个4x4的矩阵表示,为此,我们需要把矢量扩展到四维空间下,就是齐次坐标空间

齐次坐标:四维向量

点:w=1向量:w=0

1.平移矩阵

2.缩放矩阵

3.旋转矩阵(正交矩阵)

无论坐标轴如何变换,两两之间总是互相垂直,且长度为1,满足上述推论。故旋转矩阵是正交矩阵

绕x轴旋转θ

绕y轴旋转θ

绕z轴旋转θ

约定:先缩放,再旋转,最后平移

4.5 坐标空间变换

变谁就按列展开乘谁,详见P69

第一个”谁”:目标坐标空间,即变换到的空间第二个”谁”:自己的坐标轴在目标空间下的表示

如果矩阵正交,那么只需转置即可得到逆变换

已知子坐标空间C的3个坐标轴在父坐标空间P下的表示Xc,Yc,Zc,以及原点位置Oc。给定一个子坐标空间一点Ac=(a,b,c),确定其在父空间下的位置Ap。

个人心得记录于:2021.10.27

根据看的角度不同,分为两种变换类型

坐标变换:我们坐标系下的点经过一个矩阵变换到我们坐标系下另一个点基变换:它们坐标系下的点,在我们坐标系下的表示

举例说明:以二维旋转变换为例

顶点的坐标变换过程

难点:投影矩阵推导并非真正从3D投影到2D,而是投影到NDC (Normalized Device Coordinates) 中,但是投影变换不会进行齐次除法,所以结果并非真正意义上的点,而是一个待处理的四维向量(w分量非0非1,而是和z有关)。所以四维向量需经过齐次除法,才算真正成为NDC中的点。

个人小结:

观察空间 - 投影变换 -> 裁剪空间(手动实现)裁剪空间 - 齐次除法 -> NDC空间(底层实现)NDC空间 - 屏幕映射 -> 屏幕空间(底层实现)

NDC和裁剪空间并非同一空间!

正交投影矩阵

透视投影矩阵

4.6 法线变换详见P86

4.7 Shader内置变量!!!

变换矩阵

摄像机和屏幕参数

4.8 答疑解惑(了解)

Cg中的矢量和矩阵类型矢量初始化:

float4 a = float4(1.0, 2.0, 3.0, 4.0);

矩阵初始化(行优先填充):

float3x3 M = float3x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0,7.0, 8.0, 9.0);

注意:脚本的Matrix4x4(列优先填充)

获取Unity中的屏幕坐标

法1.frag函数直接声明语义在片元着色器的输入中声明VPOS(HLSL)或WPOS(Cg)语义

设屏幕分辨率400x300,VPOS、WPOS各分量取值范围如下xy值代表在屏幕空间中的像素坐标

x∈[0.5,400.5]y∈[0.5,300.5]z∈[0,1],近平面z为0,远平面z为1透视:w∈[1/Near,1/Far](正交:w=1。这些值是通过投影矩阵变换后的w分量取倒数得到的)

原点在(0.5,0.5),即像素中心对应的是浮点值

视口坐标:屏幕空间除以屏幕分辨率得到的。左下角(0,0),右上角(1,1)

例子.求视口空间坐标

法2.ComputeScreenPos函数原理:

ComputeScreenPos内部实现

核心思想:手动模拟屏幕映射,得到未经齐次除法的视口坐标

例子.

不能在顶点着色器中先做齐次除法,具体详见P92,但是写得也不是很明白,只能隐约感觉到其中的奥妙

解释如下:

总之,不能在投影空间(齐次裁剪空间)中直接进行插值,因为这并不是一个线性的空间,而插值往往是线性的

最新发表
友情链接