《UnityShader入门精要》总结(1)理论篇

紫色:大类概念或简短有力的总结

蓝色:细分概念或重要部分

红色:重要的补充注释

第二章:渲染流程与流程分工

渲染的流程分三个阶段:

应用阶段(开发者控制阶段)

由开发者全权进行管理,控制场景内摄像机位置,需要用到的模型以及他们的位置.在布置结束后DrawCall进入下一阶段(由CPU发布渲染指令被称为DrawCall)

几何阶段(3D转2D阶段)

由GPU进行管理,将所有3D物体坐标进行变换,输出2D坐标并传输到下一阶段

光栅化阶段(将图像渲染到屏幕上)

由GPU进行管理,根据坐标决定要如何渲染,并将处理好的图像绘制在屏幕上

 几何阶段过程详解

顶点着色器:将顶点进行空间变换并着色

曲面细分着色器:用于细分图元

几何着色器:产生更多图元或对图元依次着色

裁剪:将不在摄像机范围内的顶点去除掉,并去除一些三角图元的面片

屏幕映射:把每个图元的x和y坐标转换到屏幕坐标系下

光栅化阶段过程详解

三角形设置:计算由几何阶段传过端点而构成的三角形的边的坐标

三角形遍历:检查每个像素是否被三角网格所覆盖

片元着色器:将片元逐一着色

逐片元操作:将片元依次渲染,不可编程但可配置.对片元进行测试通过后可对片元进行各种重要操作.如修改颜色,颜色混合等(若未通过测试则舍弃片元)

 模板测试:

读取模板缓冲区该片元的位置,然后和读取到的参考值进行比较

开发者可对比较函数进行配置。如小于参考值时舍弃,或大于等于时舍弃

不管片元有没有通过测试,开发者都可以根据测试结果修改模板缓冲区

常用于实现阴影效果

深度测试:

GPU将该片元的深度和深度缓冲区的数值进行比较,常用于实现透明效果

当一个片元完成了以上测试,就进入了混合(合并)环节

在渲染时,因为物体是逐一被绘制到屏幕上的,而每个像素的颜色都被保存在颜色缓冲区

那么当我们执行下次渲染时,是要直接替换掉之前的颜色,还是和之前的颜色进行一些混合操作?

对于不透明物体,开发者可以关闭混合。这样,由于绘制时会覆盖掉之前的像素,绘制到屏幕上的结果就是不透明的。反之,通过混合操作可以让物体看起来像是透明

章节总结:

阶段与各环节流程

渲染流程的三个阶段.在应用阶段由开发者自由配置

在几何阶段由GPU进行空间转换.将端点坐标计算好来为光栅化阶段做准备

光栅化阶段负责进行最后的渲染,我们在这里通过配置模板测试/深度测试的脚本来修饰片元

最后在混合环节完成最后的整合输出到我们的屏幕上

顶点,片元,图元,像素的关联

顶点是从应用阶段被解析,经过几何阶段的变换与计算来获取图元.图元被光栅化之后变为片元.片元在经过模型/深度测试后变为像素(即呈现在计算机屏幕上的像素点)

什么是DrawCall

当CPU需要GPU进行渲染工作时,向命令缓冲区发送DrawCall指令

由于GPU渲染速度很快,而CPU发布命令速度较慢。因此,发送大批量DrawCall指令比GPU进行一次大规模渲染要慢得多(因为发送命令的间隔GPU就把任务完成了)所以,可以通过批处理来减少DrawCall造成的开销

批处理

 

 批处理有个缺点,因为批处理是合并了很多模型,而合并他们是需要时间的.所以,批处理不适用于动态物体(因为每一帧都要进行合并)

而在unity开发中,网格不建议细分小而多,这样也会增加drawcall的开销

第三章:UnityShader入门

UnityShader的结构

 Title ShaderName:这个Shader的命名空间,可以展示在编辑器

properties:存放变量的区域。这里的变量可以在编辑器中修改

 

 Subshader:定义状态(RenderSetup)标签(Tags)和完整渲染流程(Pass)

常用RenderSetup

 常用Tags

 注意:虽然Pass中也允许你设置Tags,但是使用的代码不同.以上是仅适用SubShader的Tags

Pass:完整的渲染流程

 用Name定义该Pass的名称 如 Name "Aba"

这样,我们可以在其他UnityShader中的SubShader中直接引用这个Pass.如 UsePass "MyShader/ABA"

其中,MyShader是Title中声明的Name.而Pass的Name将在Unity中自动转大写.所以要引用Aba应输入ABA

Pass的标签类型

 UsePass:复用其他Unity Shader中的Pass

GrabPass:该Pass负责抓取屏幕并将结果存储在一张纹理中,以用于后续的Pass处理

最简单的实现:在Unity中截图!

UnityShader的形式

表面着色器: Unity中对基本渲染进行了封装的高级形式.封装了片元着色器和顶点着色器.在编译通过后,unity会将表面着色器拆分为片元/顶点着色器.而不需我们再做多余底层工作

顶点/片元着色器:  使用CG/HLSL着色器语言编写的常规着色器.更加复杂,但灵活性更高.而且学会了可以跨平台(因为表面着色器是Unity专用)

章节总结:

 UnityShader不是真正意义上的Shader.只是能实现Shader的功能

UnityShader分为三部分:Title(开头),properties(属性) ,subshader(状态).subshader中的Pass块定义渲染流程

Subshader可以有多个Pass.用于从前到后依次检索.会挑选显卡能够呈现的第一个效果

表面着色器是顶点/片元着色器的组合,为unity的高级封装

第四章:Unity中的数学

应用数学

笛卡尔坐标系

 要描述一个物体的相对位置。使用笛卡尔坐标系(原点起发的三维向量。距离x,y,z轴的距离

左手坐标系与右手坐标系:

反转一个轴,就得到了一个相反的坐标系对于坐标系来说,这相当于镜像翻转)

这种操作也能转换左右手坐标系

(理解上图吗?可以看作将左手坐标系向右旋转了90°,然而本来应该是-x的方向变为了+x。x轴被反转了,所以转变为右手坐标系) 

 同时,左右手法则的旋正方向也不同

  在Unity的世界空间中,使用的是左手坐标系.而观察空间使用的是右手坐标系

点和矢量(向量)

点,矢量的概念

点:平平无奇的坐落在坐标系上的一个点

向量:表达一个方向,以及终点距离原点的距离.向量是空间中的一个箭头

向量运算

 向量的本质是将x帽和y帽的路径整合

根据此观点,我们知道了。[1,2]+[3,4]向量相加的本质

其实就是[1+3,2+4]=[4,6]

 同样的,向量相乘。[2,3]*[3,4]=[2*3,3*4]

在图形学中向量通常用于描述位置偏移(简称位移)。因此,我们可以利用向量的加法和减法来计算一点相对于另一点的位移。

 单一矢量

不关心矢量的模(距离),将矢量的距离视为1。单位矢量也被称为被归一化的矢量。对任何给定的非零矢量,把它转换成单位矢量的过程就被称为归一化

 这样的向量在上面加一个倒v表示,读帽。如x帽就是距离为1的向量

在正常法线方向,光源方向运算时,矢量不一定是归一化矢量。我们要先进行归一化再进行运算

点积和X积

点积:两个相同维度的矩阵每个向量相乘后相加

 

 可以理解为一个向量投影到其他向量,然后将向量相乘

所以,当方向基本相同时,结果为正

方向相反时,结果为负

 垂直时结果为正

点积满足交换律

X积:本质上是两个向量之间构成的平行四边形的面积

 叉积不满足交换律

当顺时针计算时,叉积结果为正。逆时针计算时,叉积结果为负

 求结果计算行列式即可

 

矩阵运算

首先。要明白矩阵的本质是矢量组成的坐标系

例:有这样一个矩阵:

 实际上,他是三个向量(1,2,3)(4,5,6)(7,8,9)描绘的坐标系

矩阵运算的过程,其实是空间变换的过程。这个过程叫线性变换

矩阵和矩阵的乘法

当一个a*b大小的矩阵和一个b*c大小的矩阵相乘时.最后矩阵大小为a*c

(如果行数相等,可以把其中一个行矩阵转为列矩阵)

当行列不相等时.如2*4矩阵和3*6大小矩阵无法进行运算

 结果矩阵为依次遍历.如c11为[a11,a12]与[b11,b12]进行运算

运算公式为c11=a11*b11+a12*b12

一般shader中的矩阵为4x4

变换

在shader中最常用的变换就是线性变换

矩阵可以抽象为坐标轴,而线性变换是以矩阵运算。所以,线性变换的运算就是空间变换的过程

什么是线性变换?

将一个空间通过一定的运算,得到另一个空间

如f(x)=2x,这是一个缩放线性变换

此外,比较常用的还有平移变换

仿射变换(将三维矢量转到四维来进行线性变换和平移变换)

如何将三维矢量转为齐次坐标(四维矢量)?

对于点:将w轴设为1

对于向量:将w轴设为0

仿射变换下的变换矩阵

移动矩阵:

注:向量没有位置属性,所以不受平移矩阵影响

缩放矩阵

 旋转矩阵(绕轴旋转)

最后:复合变换的顺序是缩放,旋转,平移

Unity的内置矩阵

章节总结

shader最重要的数学知识是矩阵和线性变换

矩阵实际上是向量/点的抽象

矩阵变换的计算方法

不同的坐标系空间不可以相互进行运算,需要转换到相同坐标系

(如父物体的子物体中的坐标系是相对父物体而言的)

猜你喜欢

转载自blog.csdn.net/qq_58804985/article/details/125545658