本文由@唐三十胖子出品,转载请注明出处。
文章链接:https://blog.csdn.net/iceSony/article/details/84309224
这篇文章将总结和提炼《Unity Shader入门精要》的第五章“Unity Shader学习之旅”的内容。
通过这篇文章,你可以知道
1)Shader开发所需的数学基础
2)顶点/片元着色器的书写&语法介绍
一.学习ShaderLab的数学基础
矢量/标量:矢量是状态量,有方向大小;标量只有大小
小明向东10km/h开车
这里的向东10km/h就是矢量,10km/h就是标量
向量又称作矢量,一个三维向量(1,1,1)代表从原点到点(1,1,1)的射线
除了简单的加减,向量与标量的乘除
我们还要知道大学数学讲到的向量的内积与外积
向量内积:A·B (x1,y1)·(x2,y2)= x1x2+y1y2
实际意义:大于0 两者夹角<90 等于0 两者垂直 小于0 两者夹角>90
向量外积:AxB (x1,y1,z1)·(x2,y2,z2)= (y1z2-z1y2,z1x2-x1z2,x1y2-x2y1)
实际意义:AxB代表垂直于AB构成平面的法向量
最后还涉及了矩阵的乘法
你要知道的是为了区分点和向量在世界坐标中的区别,我们需要将xyz的坐标加上多一栏
(x,y,z,0/1) 0代表是向量 1代表点
比如一个矩阵乘法代表移动操作
其次在U3D中分为左右手坐标系
书中提到摄像头是右手坐标系,事实上windows下和mac是不同的
Mac下z越小离摄像头越远,而Mac下是z越大越远。这里特别说明这是由于OPENGL与DirectX的不同导致的。Windows下统一为左手坐标系。
(不清楚的可以看书,注意书中都是矩阵右乘,也就是从倒数第二个乘以倒数第一个开始)
二.接下来编写顶点/片元着色器
Shader "sony/Shader122" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct a2v { float4 position:POSITION; float3 normal:NORMAL; float4 texcoord:TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; fixed3 color : COLOR0; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.position); o.color = v.normal*0.5 + fixed3(0.5,0.5,0.5); return o; } fixed4 frag(v2f o):SV_TARGET { return fixed4(o.color,1.0); } ENDCG } } }
实现效果
介绍一下基本的语法
这就是第一个着色器,上一章说过顶点/片元着色器写在Pass中的CGPROGRAM-ENDCG中
这里不难看出两个申明
#pragma vertex vert
#pragma fragment frag
这里的vertex与fragment代表vert与frag函数分别作用在顶点、片元上
之后的函数编写和常见的c语法类似
但是有个符号 :
注意这里的 : 不是c++中的继承
这是告诉函数的最后的修改对象
比如float4 vert(float4 v : POSITION) :SV_POSITION
这里的v其实就是float4v = POSITION
SV_POSITION代表:最后return数据会作用在SV_POSITION裁剪坐标中(摄像机外不需要进行修改)
UnityObjectToClipPos:从世界坐标到裁剪坐标
结构体:用于顶点——>片元函数数据传递,如下在顶点函数中处理顶点颜色,传递给片元函数插值产生五彩的球体
Shader "sony/Shader122" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct a2v { float4 position:POSITION; float3 normal:NORMAL; float4 texcoord:TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; fixed3 color : COLOR0; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.position); o.color = v.normal + fixed3(0.5, 0.5, 0.5); return o; } fixed4 frag(v2f o):SV_TARGET { return fixed4(o.color,1.0); } ENDCG } } }
当我们需要参数的时候直接通过定义的结构体来获取就可以:)
和普通的定义不同的是我们修改结构体的内容不需要写输出内容,因为需要修改的内容写在开头了
比如:v2f vert(a2v v)
下一篇我们将介绍CG语法&变量与常见函数的使用