Unity Shader笔记(一)

渲染流水线

概念流水线的三个阶段

应用阶段

输出渲染图元(点、线、三角面等)
此阶段对于开发者来说的任务有:

  • 要准备好场景数据(包括设计相机的位置、视锥体、模型、光源)
  • 做一个粗粒度的剔除工作,把不可见的物体剔除
  • 设置好每个模型的渲染状态(材质、纹理、Shader)

几何阶段

输出屏幕的顶点信息

光栅化阶段

使用上一阶段的数据来阐述屏幕上的像素,并渲染出最终的图像

CPU与GPU的通信

把数据加载到显存中

数据从硬盘加载到内存,然后网格和纹理等数据又被加载到显卡的存储空间,即显存里

设置渲染状态

定义场景中的网格是怎样被渲染的

调用Draw Call

Draw Call:每次CPU准备数据并调用图形绘制API通知GPU的过程就称之为一个DrawCall

所谓Draw Call,就是一个命令,发起方是CPU,接收方是GPU,仅仅指向一个需要被渲染的图元(点线面)列表,不包含任何材质信息(材质信息已经加载到了显存中)

GPU流水线

几何阶段和光栅化阶段可以分成若干个更小的流水线阶段。这些流水线阶段由GPU来实现,每个姐u但GPU提供不同的可配置性和可编程性
流水线
顶点着色器:实现顶点空间变换、顶点着色功能。把顶点坐标从模型空间转换到齐次裁剪空间(类似于归一化)
曲面细分着色器:用于细分图元
几何着色器:用于执行逐图元的着色操作,或者用于产生更多图元
裁剪:将不在摄像机视野内的顶点裁剪掉,剔除某些三角图元的面片
裁剪时物体的三种状态
屏幕映射:负责把每个图元的坐标转换到屏幕坐标系中
// 在Unity中,屏幕坐标系是以屏幕左下角为原点,向右为 x 正方向,向上为 y 的正方向,相机世界坐标中 z 坐标的负方向为正方向的坐标系
三角形设置:固定函数阶段,计算光栅化一个三角形网格所需的信息
三角形遍历:固定函数阶段,检查每个像素是否被一个三角网格所覆盖,是的话就生成一个片元
// 一个片元并不是真正意义上的像素,只是包含要渲染的像素所需要的信息的集合,用于计算每个像素的最终颜色
片元着色器(像素着色器):实现逐片元的着色操作
逐片元操作(合并阶段):修改颜色、深度缓冲、进行混合等
输出:屏幕图像

着色器语言

HLSL

DX的着色器语言

GLSL

OpenGL的着色语言

CG

英伟达C for Graphic

小总结

Shader 所在的阶段就是渲染流水线的一部分,更具体来说 Shader 就是GPU流水线上一些可编程的部分。而着色器编译出来的代码最终是在GPU上运行的


Unity Shader基础

Unity 中提供了方便管理着色器、代码以及渲染设置的 Unity Shader

  • 标准表面着色器(Standdard Surface Shader):包含标准光照的表面着色器模板
  • 无光照着色器(Unlit Shader):不包含光照的基本顶点/片元着色器
  • 图像效果着色器(Image Effect Shader):实现各种屏幕后处理效果
  • 计算着色器(Compute Shader):产生一个特殊的Shader文件,旨在利用GPU并行性进行一些与常规渲染流水线无关的计算
  • 光线追踪着色器(Ray Tracing Shader): 执行与光线追踪相关的计算
    Unity中的着色器类型

流程

创建一个材质(Material),创建一个着色器(Shader),将Shader赋予到材质上,再把材质赋予给游戏对象,在材质面板中调整属于以达到满意的效果。

ShaderLab

ShaderLab 是 Unity 中用于编写着色器的特定语言

Shader"_ShaderName"
{
    Properties{ //属性}
    SubShader{ //子着色器}
    SubShader{ //子着色器}
	Fallback "VertexLit"	//SubShader都无法使用时调用Fallback
}

属性 Properties

属性是连接材质和Shader的桥梁,这些属性将出现在材质的面板中

  • Int
  • Float
  • Range(min, max)
  • Color
  • Vertor
  • 2D
  • Cube
  • 3D

子着色器 SubShader

SubShader可以有多个且至少有一个;
当需要加载Shader时,Unity会扫描所有SubShader并选择一个能够在目标平台运行的SubShader;
若所有SubShader都不支持则调用Fallback

SubShader{
	// 可选的[Tags]
    // 可选的[RenderSetup]
    Pass{}	// 每个Pass定义了一次完成的渲染流程,但Pass数目过多性能会下降
    // Other Passes
}

常见的渲染状态设置选项:

  • Cull(剔除)
    • Back 背面
    • Front 正面
    • Off 关闭
  • ZTest(深度测试)
    • Less Greater
    • LEqual
    • GEqual
    • Equal
    • NotEqual
    • Always
  • Zwrite(深度写入)
    • On
    • Off
  • Blend(混合模式)
    • SrcFactor
    • DstFactor

SubShader 的标签类型

  • Queue:控制渲染顺序
  • RenderType:对着色器进行分类
  • DisableBatching:指定是否使用批处理
  • ForceNoShadowCasting:控制投射阴影
  • IgnoreProjector:控制是否受 Projector 的影响。常用于半透明物体
  • CanUseSpriteAtlas: 使用此子着色器的精灵是否与 Legacy Sprite Packer 兼容
  • PreviewType:指明材质面板如何预览该材质,默认球形

Pass 的标签类型:

  • LightMode:定义该 Pass 在渲染流水线中的角色
  • RequireOptions:指定当满足某些条件时才渲染该 Pass

降级着色器 FallBack

FallBack "name"	// 使用的最低级着色器
FallBack Off	// 关闭 Fallback 功能

Unity中其它与Shader相关的术语

  • 着色器/着色器程序:在 GPU 上运行的程序。默认着色器程序是图形管线的一部分
  • Shader 对象:Shader类的一个实例。Shader对象是着色器程序和其他信息的封装器
  • ShaderLab:Unity中用于编写着色器的特定语言
  • Shader Graph:一种不用代码创建着色器的工具
  • 着色器资源:Unity 项目中扩展名为 .shader 的文件。它定义一个 Shader 对象
  • Shader Graph 资源:Unity 项目中的文件。它定义一个 Shader 对象

传统的 Shader 仅可以编写特定的Shader,例如顶点着色器或片元着色器,而 Unity Shader 中可以在一个文件中同时包含顶点着色器和片元着色器的代码。
传统的 Shader 中无法设置一些渲染设置,例如是否开启混合、深度测试等,而 Unity Shader 中可以通过特定指令来完成。


数学相关知识

坐标系与矢量

Unity:左手坐标系,但是观察空间为右手
UE:左手坐标系
// 判断小技巧:对应手的四指从 x 指向 y,大拇指方向为 z 轴
矢量点积 => 数
几何意义:投影长度
矢量叉积 => 矢量
几何意义:垂直于两个矢量的新矢量(模长为原矢量为边的平行四边形面积)
// UE中的mutiply节点既不是点积也不是叉积,而是各个分量的简单相乘而已

变换

矩阵在三维渲染中的主要作用就是变换,包括对物体的平移、旋转、缩放,对坐标空间的变换等
线性变换:保留矢量加和标量乘
仿射变换:合并线性变换和平移变换的变换类型

齐次坐标

线性变换可以做到缩放、旋转和正交投影,但是不能满足平移的需求。因此需要将三维矢量转换成四维矢量
[ M t 0 1 ] \left[ \begin{array}{c|c} M&t\\ \hline 0&1 \end{array} \right] [M0t1]

左上角M为表示旋转和缩放的3×3矩阵
M = [ 1 0 0 0 1 0 0 0 1 ] M=\begin{bmatrix} 1&0&0\\ 0&1&0\\ 0&0&1\\ \end{bmatrix} M=100010001

右上角为平移矩阵
t = [ t x t y t z ] t=\begin{bmatrix} t_x \\ t_y\\ t_z \\ \end{bmatrix} t=txtytz

左下角为0矩阵,右下角为标量1

平移矩阵

点 P(x, y, z) 平移 (tx, ty, tz)

[ 1 0 0 t x 0 1 0 t y 0 0 1 t z 0 0 0 1 ] ⋅ [ x y z 1 ] = [ x + t x y + t y z + t z 1 ] \begin{bmatrix} 1&0&0&t_x\\ 0&1&0&t_y\\ 0&0&1&t_z\\ 0&0&0&1 \end{bmatrix} \cdot \begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} = \begin{bmatrix} x+t_x\\ y+t_y\\ z+t_z\\ 1\\ \end{bmatrix} 100001000010txtytz1xyz1=x+txy+tyz+tz1

缩放矩阵

[ k 1 0 0 0 0 k 2 0 0 0 0 k 3 0 0 0 0 1 ] ⋅ [ x y z 1 ] = [ k 1 ⋅ x k 2 ⋅ y k 3 ⋅ z 1 ] \begin{bmatrix} k_1&0&0&0\\ 0&k_2&0&0\\ 0&0&k_3&0\\ 0&0&0&1 \end{bmatrix} \cdot \begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} = \begin{bmatrix} k_1\cdot x\\ k_2\cdot y\\ k_3\cdot z\\ 1\\ \end{bmatrix} k10000k20000k300001xyz1=k1xk2yk3z1

旋转矩阵

[ 1 0 0 0 0 c o s θ − s i n θ 0 0 s i n θ c o s θ 0 0 0 0 1 ] cot ⁡ [ x y z 1 ] = [ x y ⋅ c o s θ − z ⋅ s i n θ y ⋅ s i n θ + z ⋅ c o s θ 1 ] \begin{bmatrix} 1&0&0&0\\ 0&cosθ&-sinθ&0\\ 0&sinθ&cosθ&0\\ 0&0&0&1 \end{bmatrix} \cot \begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} = \begin{bmatrix} x\\ y\cdot cosθ-z\cdot sinθ\\ y\cdot sinθ+z\cdot cosθ\\ 1\\ \end{bmatrix} 10000cosθsinθ00sinθcosθ00001cotxyz1=xycosθzsinθysinθ+zcosθ1

绕 y 轴旋转 θ 度

[ c o s θ 0 s i n θ 0 0 1 0 0 − s i n θ 0 c o s θ 0 0 0 0 1 ] cot ⁡ [ x y z 1 ] = [ x ⋅ c o s θ + z ⋅ s i n θ y − x ⋅ s i n θ + z ⋅ c o s θ 1 ] \begin{bmatrix} cosθ&0&sinθ&0\\ 0&1&0&0\\ -sinθ&0&cosθ&0\\ 0&0&0&1 \end{bmatrix} \cot \begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} = \begin{bmatrix} x\cdot cosθ+z\cdot sinθ\\ y\\ -x\cdot sinθ+z\cdot cosθ\\ 1\\ \end{bmatrix} cosθ0sinθ00100sinθ0cosθ00001cotxyz1=xcosθ+zsinθyxsinθ+zcosθ1

绕 z 轴旋转 θ 度
[ c o s θ − s i n θ 0 0 s i n θ c o s θ 0 0 0 0 1 0 0 0 0 1 ] cot ⁡ [ x y z 1 ] = [ x ⋅ c o s θ − y ⋅ s i n θ x ⋅ s i n θ + y ⋅ c o s θ z 1 ] \begin{bmatrix} cosθ&-sinθ&0&0\\ sinθ&cosθ&0&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix} \cot \begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} = \begin{bmatrix} x\cdot cosθ-y\cdot sinθ\\ x\cdot sinθ+y\cdot cosθ\\ z\\ 1\\ \end{bmatrix} cosθsinθ00sinθcosθ0000100001cotxyz1=xcosθysinθxsinθ+ycosθz1

一般的顺序是:缩放 -> 旋转 -> 平移

坐标空间

模型空间(Model Space)

// 又称对象空间(Object Space)或局部空间(Local Space)

世界空间(World Space)

观察空间(View Space)

裁剪空间(Clip Space)

把顶点从观察空间转换到裁剪空间中的矩阵叫做裁剪矩阵,也被称作投影矩阵。最终渲染的部分是由视锥体决定的。
Unity 中的相机参数如下:
Unity相机透视投影参数

视锥体投影类型有两种:正交投影、透视投影

透视投影

近裁剪平面和远裁剪平面决定可以看到的最近和最远距离

n e a r C l i p P l a n e H e i g h t = 2 ⋅ N e a r ⋅ tan ⁡ F O V 2 nearClipPlaneHeight=2\cdot Near\cdot \tan\frac{FOV}{2} nearClipPlaneHeight=2Neartan2FOV
F a r C l i p P l a n e H e i g h t = 2 ⋅ F a r ⋅ tan ⁡ F O V 2 FarClipPlaneHeight=2\cdot Far\cdot \tan\frac{FOV}{2} FarClipPlaneHeight=2Fartan2FOV

宽度由计算出的高度和设置的宽高比 Aspect 可以计算出。
透视投影矩阵:
[ cot ⁡ F O V 2 A s p e c t 0 0 0 0 cot ⁡ F O V 2 0 0 0 0 − F a r + N e a r F a r − N e a r − 2 ⋅ N e a r ⋅ F a r F a r − N e a r 0 0 − 1 0 ] \begin{bmatrix} \frac{\cot\frac{FOV}{2}}{Aspect}&0&0&0\\ 0&\cot\frac{FOV}{2}&0&0\\ 0&0&-\frac{Far+Near}{Far-Near}&-\frac{2\cdot Near\cdot Far}{Far-Near}\\ 0&0&-1&0 \end{bmatrix} Aspectcot2FOV0000cot2FOV0000FarNearFar+Near100FarNear2NearFar0

把顶点从观察空间转换到裁剪空间,将透视投影矩阵点乘顶点坐标:
[ cot ⁡ F O V 2 A s p e c t 0 0 0 0 cot ⁡ F O V 2 0 0 0 0 − F a r + N e a r F a r − N e a r − 2 ⋅ N e a r ⋅ F a r F a r − N e a r 0 0 − 1 0 ] ⋅ [ x v y v z v 1 ] = [ x c y c z c − z v ] \begin{bmatrix} \frac{\cot\frac{FOV}{2}}{Aspect}&0&0&0\\ 0&\cot\frac{FOV}{2}&0&0\\ 0&0&-\frac{Far+Near}{Far-Near}&-\frac{2\cdot Near\cdot Far}{Far-Near}\\ 0&0&-1&0 \end{bmatrix}\cdot \begin{bmatrix} x_v\\ y_v\\ z_v\\ 1\\ \end{bmatrix} = \begin{bmatrix} x_c\\ y_c\\ z_c\\ -z_v\\ \end{bmatrix} Aspectcot2FOV0000cot2FOV0000FarNearFar+Near100FarNear2NearFar0xvyvzv1=xcyczczv

转换后顶点的 w 分量不再为1而是观察空间 z 坐标的相反数,使用该 w 分量判断顶点是否在视锥体内
− w ≤ x ≤ w − w ≤ y ≤ w − w ≤ z ≤ w -w\leq x \leq w \\ -w\leq y \leq w \\ -w\leq z \leq w wxwwywwzw

正交投影

正交投影的视锥体是一个长方体

Unity相机正交投影参数

n e a r C l i p P l a n e H e i g h t = F a r C l i p P l a n e H e i g h t = 2 ⋅ S i z e nearClipPlaneHeight=FarClipPlaneHeight=2\cdot Size nearClipPlaneHeight=FarClipPlaneHeight=2Size同理宽度也是由计算出的高度和设置的宽高比 Aspect 可以计算出。正交投影矩阵:
[ 1 A s p e c t ⋅ S i z e 0 0 0 0 1 S i z e 0 0 0 0 − 2 F a r − N e a r − F a r + N e a r F a r − N e a r 0 0 0 1 ] \begin{bmatrix} \frac{1}{Aspect\cdot Size}&0&0&0\\ 0&\frac{1}{Size}&0&0\\ 0&0&-\frac{2}{Far-Near}&-\frac{Far+Near}{Far-Near}\\ 0&0&0&1\\ \end{bmatrix} AspectSize10000Size10000FarNear2000FarNearFar+Near1把顶点从观察空间转换到裁剪空间,将正交投影矩阵点乘顶点坐标:
[ 1 A s p e c t ⋅ S i z e 0 0 0 0 1 S i z e 0 0 0 0 − 2 F a r − N e a r − F a r + N e a r F a r − N e a r 0 0 0 1 ] ⋅ [ x v y v z v 1 ] = [ x c y c z c 1 ] \begin{bmatrix} \frac{1}{Aspect\cdot Size}&0&0&0\\ 0&\frac{1}{Size}&0&0\\ 0&0&-\frac{2}{Far-Near}&-\frac{Far+Near}{Far-Near}\\ 0&0&0&1\\ \end{bmatrix}\cdot \begin{bmatrix} x_v\\ y_v\\ z_v\\ 1\\ \end{bmatrix} = \begin{bmatrix} x_c\\ y_c\\ z_c\\ 1\\ \end{bmatrix} AspectSize10000Size10000FarNear2000FarNearFar+Near1xvyvzv1=xcyczc1变换后 w 分量仍然是1,判断是否在视锥体内的公式仍然不变

− w ≤ x ≤ w − w ≤ y ≤ w − w ≤ z ≤ w -w\leq x \leq w \\ -w\leq y \leq w \\ -w\leq z \leq w wxwwywwzw

屏幕空间(Screen Space)

顶点变换的最后一步,变换到屏幕空间,也就是把视锥体投影到屏幕空间。
用齐次除法(或者叫透视除法),将齐次坐标系 w 分量除以 x、y、z 分量,变换到一个立方体内。再进行屏幕映射求屏幕上的像素坐标(Screenx,Screeny):
S c r e e n x = c l i p x ⋅ p i x e l W i d t h 2 ⋅ c l i p w + p i x e l W i d t h 2 Screen_x=\frac{clip_x\cdot pixelWidth}{2\cdot clip_w}+\frac{pixelWidth}{2} Screenx=2clipwclipxpixelWidth+2pixelWidth
S c r e e n y = c l i p y ⋅ p i x e l H e i g h t 2 ⋅ c l i p w + p i x e l H e i g h t 2 Screen_y=\frac{clip_y\cdot pixelHeight}{2\cdot clip_w}+\frac{pixelHeight}{2} Screeny=2clipwclipypixelHeight+2pixelHeight

  • clip_x:裁剪空间中顶点的 x 分量
  • clip_y:裁剪空间中顶点的 y 分量
  • clip_w:裁剪空间中顶点的 w 分量
  • pixelWidth:屏幕宽度像素分辨率
  • pixelHeight:屏幕高度像素分辨率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值