零、不同图形接口程序对Shader开发的影响:
1.渲染管线(流水线)和图形接口程序的关系:图形接口程序(OpenGL、 DX等)提供了对渲染管线(流水线)的控制和管理功能,它是开发者和硬件打交道的中间层
2. Shader和图形接口程序的关系:Shader属于图形接口程序的一部分
3.不同图形接口程序对Shader开发的影响:开发语言不同、坐标系原点不同
一.Unity中需要遵守的规则
1.在进行平移、旋转、缩放的复合运算时绝大多数情况下,我们约定的变换顺序为:先缩放、再旋转、后平移
2.在进行x轴、y轴、z轴旋转的复合运算时,绝大多数情况下,我们约定的变换顺序为: z->x>->y
二、坐标空间的变换
在Shader开发中为了方便我们制作模型,使用模型,渲染模型,也存在很多不同的坐标空间
如:模型空间、世界空间、观察空间、裁剪空间、屏幕空间
坐标空间的变换主要是指:在渲染管线中的,我们需要将坐标数据,在这几种空间当中进行变换计算(利用矩阵相关知识)在设计模型时,使用的是模型空间(所有的顶点、法线等等相关数据都是基于模型空间坐标系的)当我们将模型导入到Unity后,最终能够被我们在屏幕上看到,这里面的就经历了我们看不到的坐标空间变换
三、坐标空间之间的关系
在Unity中,世界坐标空间相当于我们的基础坐标空间,Unity中其他的大部分坐标空间,都是世界坐标空间的子坐标空间。这些子坐标空间的原点和轴向的相关表示数据,都是基于世界坐标空间的。
在Unity中坐标空间之间会形成-种层级结构, 大部分坐标空间都是另一个坐标空间的子空间。所以,Unity中的坐标空间的变换实际上就是父空间和子空间之间对点或向量进行变换。
四、模型空间的意义
模型空间(model space)也被成为对象空间(object space)或局部空间(local space),它一般指3D模型的局部坐标系,每个模型都有自己独立的坐标空间,.模型空间的主要意义是方便我们建模,模型的顶点等数据都是基于模型空间表达的。
注意:在Unity中当模型移动或旋转时,模型空间坐标系也会随着变换,因为此时的模型坐标空间是世界坐标空间的子空间。在模型空间中,我们一般会有上、下、左、右、前、后六种方向概念
Unity使用的是左手坐标系。因此模型空间的x、y、z轴,对应的是模型的右、上、前三个方向。还需要注意的是在不同的软件中,比如3DMax和Maya中,模型空间中的xyz不见得是上面这种关系。
相对世界坐标系的位置=平移矩阵*旋转矩阵*缩放矩阵*目标的列矩阵
当使用坐标空间规则进行计算时,如果存在缩放,只需要用x、y、z轴向的单位向量*对应轴的缩放因子即可
五、平移矩阵
1.三维空间中的点或向量,我们使用齐次坐标进行矩阵运算(x,y,z,w),其中w= 1时代表是-一个点,w= 0时代表一个向量
2.在Unity的Shader开发中我们采用列矩阵的形式进行向量计算,利用结合律,我们可以从右往左阅读CBAv = C(B(Av))
3.平移矩阵的计算:
(点的平移)
4.平移矩阵并不是正交矩阵
六、旋转矩阵
1.旋转操作需要指定一个旋转轴(不一定是空间中的坐标轴)
2.旋转矩阵是转置矩阵:因此x,y,z轴的旋转矩阵的逆矩阵是他们的转置矩阵,我们可以利用旋转矩阵的逆矩阵来进行还原旋转
七、缩放矩阵
1.缩放矩阵的构成:缩放矩阵主要就是对向量或点进行缩放操作,它可以用于改变向量或点再各个坐标轴上的尺度使其在每个方向上变大或变小,在三维空间中,它主要由x、y. z轴的缩放因子构成。
2.缩放矩阵对点缩放时,相当于在缩放模型的大小;对向量进行缩放时,同意缩放回只改变向量的模长,不会改变方向,非统一缩放时,还可能会改变方向。
八、观察空间变换
1.观察空间(view space)也被成为摄像机空间(camera space),观察空间可以认为是一个特殊的模型空间,这里的模型指的是场景中的摄像机,摄像机可以认为是-一个非常特殊的模型,它不可见,但是它可以决定我们在屏幕上看到的内容,因此我们它称为观察空间。
观察空间的主要意义是摄像机决定了渲染的视角和视野
2.观察空间变换指的主要是将模型空间中的点或向量从世界空间中变换到观察空间,它是顶点变换的第二步将数据从世界空间一> 观察空间进行变换,观察空间变换也可以称为观察变换
九、视锥体
在渲染管线中,顶点、法线等相关模型数据会经过以下的空间变换:模型空间->世界空间->观察空间->裁剪空间->屏幕空间
摄像机的视锥体是在三维空间中表示摄像机可见区域的虚拟体积,它类似一个六面体的形状,根据摄像机的属性和投影方式而定。视锥体定义了摄像机在场景中能够看到的物体区域,超出这个区域的物体将在渲染时被裁减掉从而提高渲染性能。
但是,如果直接使用视锥体定义的空间来进行裁剪,那不同的视锥体就需要不同的处理过程,而且对于透视投影的视锥体来说,判断顶点是否在范围内相对较麻烦。因此,我们用更通用、便捷的方式来进行裁剪工作,就需要将观察空间(摄像机空间)中的数据转换到齐次裁剪空间中从而提高渲染性能。
十、齐次裁剪空间
1.齐次裁剪空间是一个三维空间, 是在计算机图形学中用于在图形渲染过程中进行裁剪和投影的。它的坐标范围为(-1,-1,-1)到(1,1,1) ,超出这个范围的坐标在渲染时会被裁减掉,只会保留范围内的坐标。 齐次裁剪空间是通过将摄像机的视锥体投影到一个规范化的立方体而转换来的,这个立方体就是齐次裁剪空间。
2.摄像机视锥体的投影方式:
透视投影:视锥体内顶点和原点连接,在近裁剪面的交点为投影点
正交投影:视锥体内顶点向近裁剪面做左右裁剪面平行线,在近裁剪面交点为投影点
十一、正交投影
重要参数:
Projection:该掺数为Orthographic时,为正交摄像机
Size:视锥体竖直方向.上高度的一-半
Clipping Planes:裁剪平面
Near:近裁剪面离摄像机的距离
Far:远裁剪面离摄像机的距离
正交矩阵投影推导:
1.将视锥体中心位移到观察空间原点中心
2.将长方体视锥体的xyz坐标范围映射到(-1,1)长宽高为2的正方体中正交投影:视锥体内顶点向近裁剪面做左右裁剪面平行线,在近裁剪面交点为投影点
(目标缩放矩阵)
十二、ShaderLab
1.材质和shader:
如果要在Unity中体现出一个Shader的渲染效果,必须配合使用材质和Shader 才能达到目标
一般的使用流程是: 1.创建一个材质 2.创建一个Unity Sahder, 把该Shader赋给上一步中创建的材质 3.将材质赋予给想要渲染的对象 4.在材质面板中调整Unity Shader的相关属性,以达到最终效果
也就是说,Unity中的Shader必须配合材质才能正常使用
(五种不同的着色器,学习的重点是顶点/片元着色器)
1.1.Default Maps:默认纹理:设置着色器使用的默认纹理图片,第一次使用该Shader时,这些纹理会自动的赋予到对应的属性上
1.2.Imported Object:导入的对象
这里可以查看和编机与着色器对象本身相关的设置,以及着色器编译器如何处理
Surface Shader (表面着色器) Show generated code (显示生成的代码)
1.3.Fixed function:是否使用固定管线进行渲染(非常老的版本使用的方式)
1.4.Preprocess only:是否开启预处理阶段执行特定代码标记
1.5.Compiled code (Compile and show code) : 编译并显示代码:可以查看在不同平台时使用不同的图形接口程序时编译出来的代码,可以优化若色器性能
1.6.Cast shadows:是否投射期影
1.7.Render queue:该Shader的演染队列,决定渲染顺序
1.8.LOD: LOD圾别
1.9.lgnore projector:是否忽略投影器
shaderLab实际上是一种unity自定义的一种语法规则,使用在unity中编写和管理着色器的一种语言,提供了一种结构化的方式来描述unity着色器的各个部分,从而能更轻松和管理着色器
相关语法知识点可参考:Unity Shader(基本概念)-CSDN博客
2.shader的名字:
2.1如何修改名字:直接修改shader文件中shader后的名字即可,shader的名字决定了在材质面板上的选择路径
2.2不能使用中文进行命名,统一使用英文进行命名
2.3shader文件名和文件中的命名尽量相同
3.shader的属性:
3.1两个特点:可以在材质面板被编辑;可以在后续当作输入变量提供给所有子着色器使用
3.2基本语法:shader树丛属于语句块中的Properties属性语句块,只需要在其中按照语法规则声明属性即可;属性主要分为三大类:数值、颜色和向量、纹理贴图
_Name("DName",type) = defaultValue[{options}]
_Name:属性名字
DName:材质面板上显示的名字
type:属性的类型
defaultValue:将shader指定给材质的时候初始化的默认值
3.3数值类型属性:整形/浮点型/范围浮点型
虽然提供了整数Int,但在编译时最终都会转化为浮点型
3.4颜色和向量类型属性:
颜色:由RGBA四个分量代表,取值时0-1(映射0-255)
_Name( "DName", Color) = (number1 ,number2,number3,number4)
向量:有XYZW四个分量代表,取值无限制
_Name( "DName", Vector) = (number1 ,number2,number3,number4)
4.shader的子着色器(SubShader)
4.1相关作用:每一个Shader中都会包含至少一个SubShader,当Unity想要显示一个物体的时候就会在Shader文件中去检测这些SubShader语句块,然后选择第一个能够在当前显卡运行的SubShader进行执行,因此在一个Shader当中实现一些高级效果时,为了避免在在某些设备上无法执行可能会存在多个SubShader语句块,用于适配这些低端设备,SubShader当中包含最终的渲染相关代码,决定了最终的渲染效果
4.2基本构成:Subshader语句块中主要由3部分构成
1.渲染标签:通过标签来确定什么时候以及如何对物体进行渲染
2.渲染状态:通过状态来确定渲染时的剔除方式、深度测试方式、混合方式等等内容
3.渲染通道:具体实现着色器代码的地方(每个SubShader语句块中至少有一个渲染通道,可以有多个)
4.3Tags渲染标签:通过渲染标签来确定什么时候对物体进行渲染
Tags{"标签名"="标签值" "标签名"="标签值" ..。...}
//通过键值对的形式进行声明,无数量限制,空格作为间隔
4.4渲染队列Quene
Tags{"Quene"="标签值"}
//unity中有许多定义好的渲染队列标签值
可以基于unity预先定义好的渲染队列标签(决定渲染先后顺序)来进行加减计算从而定义自己的渲染队列(注意加减过程中不要加空格),注意不能直接写数字
4.5RenderType(渲染类型):对着色器进行分类,之后可以用于着色器替换功能;摄像机上有对应的API,可以指定这个渲染类型采替换成别的着色器
4.6禁用批处理:当使用批处理时,模型会被变换到世界空间中,模型空间会被丢弃。这可能会导致某些使用模型空间顶点数据的Shader最终无法实现想要的结果。可以通过开启禁用批处理来解决该问题
4.7禁止阴影投影:控制该SubShader的物体是否会投射阴影
4.8states渲染状态:通过状态来确定渲染时的剔除方式、深度测试方式、混合方式等内容。渲染状态是通过渲染状态关键词+空格+状态类型决定的,如果存在多个渲染状态可以通过空行隔开。
4.9片元:在渲染管线中,片元是指在光栅化阶段生成的像素或像素片段,片元是渲染管线中进行像素级别操作和计算的基本单位,每个片元代表了屏幕上的一个像素,并且具有位置信息和与之相关的属性,比如:颜色、深度值、法线等。