unityShader基本介绍
第二章:Shader和渲染管线
【图形学】学长沉浸式啃《实时渲染4th》- 第一章图形渲染流水线 - 深入浅出实时渲染的整体流程_哔哩哔哩_bilibili
2.1 什么是Shader
- GPU流水线上高度可编程阶段。
- 有特定类型的着色器,如顶点着色器,片元着色器。
- 依靠着色器可以控制流水线中的渲染细节。
2.2 什么是顶点、片元
- 顶点就是点,包含了空间坐标信息。
- 图元是由顶点组成的。一个顶点,一条线段,一个三角形或者多边形都可以成为图元。
- 片元是在图元经过光栅化阶段后,被分割成一个个像素大小的基本单位。
- 像素是最终呈现在屏幕上的包含RGBA值的图像最小单元。
2.3 渲染流水线
- 计算机从一系列的顶点数据,纹理等信息出发,将这些信息转换为图像,这个工作通常由GPU和CPU共同完成。
- 渲染流水线是概念流水线。
渲染流水线:应用阶段->几何阶段->光栅化阶段->像素化阶段
2.3.1 应用阶段
这一阶段由三个主要任务:
- 准备场景数据
- 粗粒度剔除(可以剔除不可见物体,提升渲染性能)
- 输出渲染图元。
渲染图元:可以是点,线,三角面等。渲染图元会传递到几何阶段。
步骤 | 详细 | |
---|---|---|
把数据加载到显存中 | 渲染数据从硬盘加载到系统内存(RAM),网格和纹理等数据被加载到显存(VRAM)。因为显卡对于显存的访问速度更快,且对于RAM无直接访问权限。 加载到显存后就可以移除RAM内部数据,但是一些数据需要保留给CPU访问。从硬盘加载到RAM非常耗时。 |
|
设置渲染状态 | 通过CPU设置渲染状态,指导GPU如何进行渲染工作。 渲染状态定义了场景中的网格是怎么被渲染的,如片元着色器,顶点着色器,光源属性,材质等。 当没有更改渲染状态的时候,所有网格都使用一种渲染状态,看起来像是同一种材质。 |
|
调用Draw Call | Draw Call是一个命令,发起方为CPU,接收方GPU。一次DC命令指向一个需要被渲染的图元列表。 |
GPU流水线
GPU渲染过程就是GPU流水线。
对几何阶段和光栅化阶段开发者无法拥有绝对控制权,实现载体为GPU。
几何阶段和光栅化阶段可以分为若干的流水线阶段,由GPU实现,
每个阶段都提供了不同的可配置性或可编程性。
2.几何阶段:
通常在GPU上进行,决定绘制的图元,怎么绘制,在哪里绘制。
3.光栅化阶段:
通常在GPU上进行,使用上个阶段传递的数据来产生像素,渲染最终图像。
第三章:Unity Shader
3.1 shader lab
3.1.1 什么是shaderlab
Unity Shader是Unity提供的高层级渲染抽象层。在Unity中,所有的Unity Shader都通过ShaderLab来编写。ShaderLab是Unity提供编写Unity Shader的一种说明性语言。
3.1.2 Unity Shader结构
1 | Shader "MyShader" |
标签(Tages)
标签的作用是告诉Unity渲染引擎要怎样以及何时渲染这个对象。
标签仅可在Subshader中声明,不可在Pass中声明。
结构如下:
1 | Tags {"TagName1" = "Value1" "TagName2" = "Value2"} |
状态设置
ShaderLab常见的渲染状态设置选项:
如果在SubShader块中设置了状态,就会应用到全部的Pass。可以在Pass中单独设置状态。
Pass
结构如下
1 | Pass |
可以在定义该Pass的名称
1 | Name "MyPassName" |
通过这个名称,可以使用ShaderLab的UsePass命令来使用其他Unity Shader中的Pass
1 | UsePass "MyShader/MYPASSNAME" |
需要注意,Pass的名称会被Unity转换成大写的表示,因此在使用UsePass命令的时候需要将Pass名称全部大写。
Pass也可以使用标签,不过不同于SubShader。
一些特殊Pass
- UsePass
- GrabPass
Fallback
在SubShader语义块后,可以添加Fallback指令。如果所有的SubShader在这块显卡上都无法运行,就会使用这个Fallback指定的最低级shader。
1 | Fallback "name" |
在渲染阴影纹理时,Unity会寻找一个阴影投射Pass。通常Fallback使用的内置Shader包含了一个这样的通用Pass。
3.1.3 着色器
表面着色器
Surface Shader是Unity创造的着色器代码类型,定义在Pass中。需要的代码量很少,效果比较差。
本质上是将开发者提供的表面着色器转换为顶点/片元着色器。是对顶点/片元着色器的高层抽象。可以交由Unity处理光照细节。
顶点/片元着色器
顶点/片元着色器需要定义在CGPROGRAM和ENDCG之间,同时要写在Pass语义块,同样使用GL/HLSL编写。
我们需要自定义每个Pass的Shader代码,可以控制渲染实现的细节。
1 | Pass |
固定函数着色器
一些老旧设备不支持可编程管线着色器,需要使用固定函数着色器,这种方法已经逐渐被淘汰。
3.1.4 怎么选择Unity Shader
- 使用可编程管线着色器,即表面着色器或者顶点/片元着色器。
- 表面着色器与光源相关,但是影响性能。
- 如果光照数目少,使用顶点/片元着色器。
- 有很多自定义渲染效果,顶点/片元着色器。
第五章:Unity Shader的基本语法结构
5.1顶点片元着色器的基本结构:
1 | // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' |
5.1.1 语义
1 | Shader "Unity Shaders Book/Chapter 5/Simple Shader" { |
语义(semantics)就是一个赋给Shader输入输出的字符串,这个字符串表达了这个参数的含义。语义可以让Shader知道从哪里读取数据,并把数据输出到哪里。
- 语义分为有意义语义和无意义语义。
- 接受系统数据的语义有特殊含义,而用户输入无特殊含义。
SV系统数值(ststem-value)语义。
- SV_POSITION表示光栅化的变换后的顶点坐标(即齐次裁剪空间中的坐标)。
- SV_TARGET表示告诉渲染器把结果存储到渲染目标。
5.1.2 模型数据从哪里来 a2v
- 每帧调用Draw Call时,Mesh Render组件会把它负责渲染的模型数据发送给Unity Shader。
- 定义结构体逐顶点获取模型数据。
1 | //application to vertex shader 应用到顶点着色器 |
5.1.3 顶点着色器和片元着色器之间如何通信 v2f
- 定义结构体接受返回信息
- 顶点着色器计算后返回结构体
- 片元着色器接收顶点着色器的输出做插值后得到的结果。
1 | //vertex shader to fragment shader 顶点到片 |
5.1.4 顶点着色器和片元着色器的差别
- 顶点着色器逐顶点,片元着色器逐片元
- 顶点着色器获取顶点信息
- 片元着色器获取顶点插值结果信息。
5.1.5 使用属性
通过参数,可以随时调整材质的效果。这些参数需要写在Properties中。
为Shader添加Properties:
1 | Properties |
会在材质面板显示一个颜色拾取器,从而直接控制模型在屏幕上显示的颜色。
为了在CG代码中可以访问它,还需要在代码片段中定义一个变量。这个变量的名称和类型必须与Properties语义块中的属性定义相匹配。
1 | CGPROGRAM |
5.1.6 内置包含文件
包含文件(include file),类似c++的头文件。在Unity中,它们的文件后缀是.cginc。
在编写的时候可以使用#include指令把这些文件包含进来。
1 | CGPROGRAM |
1 | Shader "Unity Shaders Book/Chapter 5/False Color" { |
https://zhuanlan.zhihu.com/p/569862136?wd=&eqid=916838b80000e08b00000006647df4f4