【shaderforge学习笔记】 Vector Operations(向量运算)

2019-04-14 18:34发布

shaderforge 向量运算

以一张向量运算的全家福开始
这里写图片描述

Append(数据维度的附加) & Component Mask(数据维度的分解)

1. 节点说明
  • Append
用于数据维度的附加
低维数据连接到输入端,高维数据在输出端输出
这里写图片描述
Append的节点会将计算好的数据以一种颜 {MOD}RGBA的形式显示出来
Append节点最多可以附加四个一维数据(因为shader中最高维度的数据类型是float4,且我们的计算最高涉及到四维)
  • Component Mask
用于数据维度的分解
高维数据连接到输入端,节点中有四个通道的选项,可以让我们控制通道的开启与关闭,并可以将任意一个通道设置成任意一个输入通道的数据。输出的是将节点在四个选项中开启的所有通道附加起来的高维数据和所有开启的单个通道。
这里写图片描述
这里写图片描述 2. UnityShader中进行数据维度附加和分解
GPU是以四维向量为基本单位来计算的。4个浮点数所组成的float4向量是GPU内置的最基本类型。使用GPU对两个float4向量进行计算,与CPU对两个整数或两个浮点数进行计算一样简单,都是只需要一个指令就可以完成。
HLSH的基本数据类型定义了float、int和bool等非向量类型,但是它们实际上都会被Complier转换成float4的向量,只要把float4向量的其中3个数值忽略,就可以把float4类型作为标量使用。 在使用float4向量中的个别数值时,可以用xyzw或rgba,都可以用来表示四维向量中的数值。但不能把它们混用,例如不能用xyba,把它视为颜 {MOD}时就用rgba,否则就是用xyzw,不能把这二者混合使用。 float4 appendData = float4(float3(x,y,z),float(w)) //数据维度附加 float w = appendData.w; //或appendData.a; //数据维度的分解

Channel Blend(通道混合)

1. 节点说明
这里写图片描述
贴图的RGBA的每个通道作为遮罩控制对应的贴图
mask有几个通道那么节点显示几个输入通道
节点下拉框可以选择混合模式为summed(总和)模式还是layered(插值)模式,summed就是通道乘以对应的分量遮罩结果的总和。layered插值启用底图Btm,各个通道有次序的按照分类遮罩进行插值,可实现图层覆盖和透明度混合。
2. UnityShader实现通道混合节点的功能
  • summed
float3 summed = (_mask_var.rgb.r*_Rcol_var.rgb + _mask_var.rgb.g*_Gcol_var.rgb + _mask_var.rgb.b*_Bcol_var.rgb);
  • layered
float3 layered = (lerp( lerp( lerp( _Btm_var.rgb, _Rcol_var.rgb, _Mask_var.rgb.r ), _Gcol_var.rgb, _Mask_var.rgb.g ), _Bcol_var.rgb, _Mask_var.rgb.b ));

Cross Product(叉积)

1. 节点说明
用于给定x轴y轴求z轴
这里写图片描述
叉积的结果是一个矢量,是有方向的。
这里写图片描述
2. UnityShader的cross函数 cross(向量a,向量b)

Desaturate(去 {MOD})

1. 节点说明
这里写图片描述
2. 去 {MOD}原理
为图片的RGB分别乘以权重然后加起来得到一个灰 {MOD}值,并且将这个灰 {MOD}值作为新的RGB值。
为什么在使彩 {MOD}图变灰RGB的权重会固定为(R:0.299 G:0.587,B:0.114)?
人眼对绿 {MOD}的敏感度最高,对红 {MOD}的敏感度次之,对蓝 {MOD}的敏感度最低,因此使用不同的权重将得到比较合理的灰度图像。实验和理论推导出来的结果是0.299、0.587、0.114。
参考:为什么在使彩 {MOD}图变灰RGB的权重会固定为(R:0.299 G:0.587 B:0.114)?
3. UnityShader是实现去 {MOD} lerp(col ,dot(i.normalDir,float3(0.3,0.59,0.11)), des))

DDX DDY DDXY(偏导数)

1. 节点说明
这里写图片描述
DDX是X方向上的偏导数,DDY是Y方向上的偏导数,DDXY返回的是X和Y方向上偏导数绝对值的和。
注意:这里的偏导数不是数学意义上的偏导数而是某方向上后一像素块与前一像素块的差值。
这里写图片描述
2. 如何理解shader中的偏导数
An introduction to shader derivative functions
An introduction to shader derivative functions(译)
这里写图片描述
我们知道在光栅化的时刻,GPUs会在同一时刻并行运行很多Fragment Shader,但是并不是一个pixel一个pixel去执行的,而是将其组织在2x2的一组pixels分块中,去并行执行。而偏导数就正好是计算的这一块像素中的变化率。从上图可以看出来ddx 就是右边的像素块的值减去左边像素块的值,而ddy就是下面像素块的值减去上面像素块的值。其中的x,y代表的是屏幕坐标。
注意:偏导数ddx/y可以计算我们FragmentShader中任意的变量。向量,矩阵等等。
3. UnityShader求偏导数 ddx(n) ddy(n) fwidth(n)

distance(距离)

1. 节点说明
这里写图片描述
2. UnityShader的distance函数 distance(a,b)

Dot Product(点积)

1. 节点说明
用于计算两个向量的朝向关系,是相对,侧对还是背对
这里写图片描述
2. 标准点积数学意义 以两个三维标量为例子x=(a,b,c),y=(a2,b2,c2)
乘法的结果是三维数据: x*y = (a*a2,b*b2,c*c2) 点积的结果是乘法得到三维数据相加得到的一维数据 x dot y=a*a2+b*b2+c*c2 这里写图片描述
3. Unityshader实现点积操作
  • dot standart
dot(a,b)
  • dot positive
max(0,dot(a,b))
  • dot negative
min(0,dot(a,b))
  • dot abs
abs(dot(a,b))
  • dot normalize
normalize(dot(a,b))

Length(计算向量长度)

1. 节点说明
这里写图片描述 这里写图片描述
2. UnityShader的Normalize函数 length(向量)

Normalize(归一化)

1. 节点说明
这里写图片描述
单位化向量
2. UnityShader的Normalize函数 normalize(float4)

Normal Blend(法线混合)

这里写图片描述
如果detail_x,detail_y值都为0的话,不做扰动,否则随着detail_x、detail_y的值的更改改变扰动的程度。
这里写图片描述

Reflection(反射)

1. 节点说明 这里写图片描述 这里写图片描述
2. UnityShader反射函数 reflect(I,N)

Transform(坐标系变换)

1. 节点说明
这里写图片描述
用于实现向量的坐标系空间转换,比如从世界空间到模型空间等等
这里写图片描述
2. UnityShader实现Transform结点的功能
  • 用到的unity shader内置矩阵变量
Name Value unity_ObjectToWorld 当前的模型矩阵 unity_WorldToObject 当前的世界坐标矩阵的逆矩阵 UNITY_MATRIX_V 当前的视点矩阵 UNITY_MATRIX_MV 当前的模型*视点矩阵 - 用到的unity shader内置函数 Name Value float3 UnityObjectToViewPos(float3 pos) 将一个位置从模型空间转换到视点空间,等价于(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz 常用的坐标系有世界坐标系、模型坐标系、切线坐标系、视点坐标系,位置点可以通过矩阵乘法切换坐标系 1.world->local float3 posW2L = mul( unity_WorldToObject, float4(pos, 0)).xyz; 2.world->tangnet float3x3 tangentTransform = float3x3( i.tangentDir, i.bitangentDir, i.normalDir); float3 posW2T = mul( tangentTransform, float4(pos, 0)).xyz;
简单介绍TBN切线空间以及Bitangent向量
切线空间,同局部空间、世界空间等一样,是3D图形学中众多的坐标系之一。切线空间基于网面的顶点由法线、切线、副切线构成一个互相垂直的三维坐标系。当模型网面变形时,切线坐标系必定跟着面一起运动,那么在这个坐标系里的某个点或向量,不需要变动。当整个面发生变化时,我们只需要计算面上的坐标系到世界坐标系的转换矩阵,那么定义在这个面上的点或坐标(固定的),乘以这个矩阵即可得到在世界中的坐标。这个坐标系术语里称为tangent space(或称TBN切线空间)。
一个右手坐标系的TBN切线坐标系如下图所示: 这里写图片描述
TBN切线空间的TBN这三个字母分别代表tangent、bitangent和normal向量。
tangent是顶点的切线,normal是顶点的法线,bitangent由tangent和normal叉乘(注意进行叉乘的N和T的先后顺序!在右手坐标系中是N × T,在左手坐标系中是T x N! 注意:Unity是左手坐标系)得到,是一个垂直于tangent和normal的向量bitangent。
切线坐标系转换到世界坐标系
切线空间到世界空间的转换矩阵T2W: egin{bmatrix} > T_{x} & T_{y} & T_{z} \ > B_{x} & B_{y} & B_{z} \ > N_{x} & N_{y} & N_{z} > end{bmatrix} 切线空间下的法线向量乘以转换矩阵,得到世界坐标系下的切线向量 normalWorld= normalize(mul(normalTangent,T2W));
3.world->view float3 posW2V = mul( UNITY_MATRIX_V, float4(pos, 0)).xyz; 4.local -> world float3 posL2W = mul( unity_ObjectToWorld, float4(pos, 0)).xyz; 5.local -> tangent float2 posL2T = mul( tangentTransform, mul( unity_ObjectToWorld, float4(pos,0) ).xyz 6.local -> view float3 posL2W = UnityObjectToViewPos( float4(pos,0) ).xyz 7.tangent -> world float3 posT2W = mul( float4(pos,0), tangentTransform ).xyz; 8.tangent -> local float3 posT2L = mul( unity_WorldToObject, float4(mul( pos, tangentTransform ),0) ).xyz 9.tangent -> view float3 posT2V = mul( UNITY_MATRIX_V, float4(mul( pos, tangentTransform ),0) ).xyz 10.view -> world float3 posV2W = mul( float4(pos,0), UNITY_MATRIX_V ).xyz; 11.view -> local float3 posV2L = mul( float4(pos,0), UNITY_MATRIX_MV ).xyz 12.view -> tangent float3 posv2T = mul( tangentTransform, mul( float4(pos,0), UNITY_MATRIX_V ).xyz ).xyz

Transpose(矩阵转置)

1. 节点说明
这里写图片描述
输出矩阵的转置矩阵
2. Transpose的数学意义
wiki关于transpose matrix(转置矩阵)的说明
这里写图片描述
在线性代数中,转置矩阵是一个按照对角线翻转一个矩阵的操作,交换矩阵行和列的索引号生成一个新的矩阵,称之为AT(也写作A’,Atr,tA,At),
转换矩阵的行和列生成这是开关矩阵的行和列索引通过产生另一个矩阵表示为(还写了′,Atr,tA或)。它是由下列任何一项等价的动作实现的:
- 从它的主对角线(从左上方到右下角)反射A以获得。
- 把A的行写作AT的列。
- 把A的列写作AT的行。 形式上,AT的第i行,第j列元素是A的第j行,第i列元素: {displaystyle left[mathbf {A} ^{mathrm {T} } ight]_{ij}=left[mathbf {A} ight]_{ji}} 如果A是一个m×n矩阵,那么AT是一个n×m矩阵。
1858年,英国数学家Arthur Cayley引入了矩阵的转置。
3. UnityShader进行transpose(矩阵转置)操作 transpose(float4x4)

Vector Projection & Vector Rejection(向量投影)

1. 节点说明
  • Vector Projection
这里写图片描述
这里写图片描述
  • Vector Rejection
这里写图片描述
这里写图片描述 2. Vector Rejection的数学意义
wiki关于Vector Projection和Vector Rejection的说明 这里写图片描述
一个向量a对一个非零向量b的向量投影是a到b所在直线的正交投影。它是一个b方向上的向量,定义为 这里写图片描述
a1是一个标量,称为a到b的标量投影。b是b方向上的单位向量,因此标量投影定义为 这里写图片描述
操作符 · 代表点积操作, |a| 代表向量a的长度,θ代表a和b之间的夹角。标量投影等价于投影向量的带正负的长度值,如果投影向量的方向与b的方向相反的话标量投影为负数。 有时我们称从a出发垂直于b的向量为a到b的rejection向量(不知道怎么翻译rejection vector合适),它是a向垂直于b的平面的正交投影。一个向量的projection a1和rejection a2还是向量,a1和a2的和是a,那么就得到了rejection的公式: 这里写图片描述
3. UnityShader获取projection和rejection
projection float3 a = float3(0,4,3); float3 b = float3(0,4,0); float3 projectionOfab = b * dot(a,b) / dot(b,b); rejection float3 a = float3(0,4,3); float3 b = float3(0,4,0); float3 rejectionOfab = (a - (b * dot(a,b)/dot(b,b)));