目录
Lecture 01
1) 工程搭建示范
a) 准备工作
TA一般推荐使用2by3的布局,具体如下
下面需要导入ShaderForge,资源指路 -> https://github.com/FreyaHolmer/ShaderForge ,只导入ShaderForge-master\ShaderForge-master\Shader Forge\Assets 中的ShaderForge即可
b) 创建Shader
完成导入后我们就可以在Unity的Tools栏中找到ShaderForge选项,打开新建一个unlit(无光照) Shader,就可以看到如下界面
选择Shader为它创建一个Material(或者新建一个Material并将它的Shader改为我们新建的Shader),到此,我们的工程搭建工作就完成了
2) 理论介绍
a) 结构(Struct)
一些相关数据的组织方式
b) 简单的渲染管线
对于3D的渲染来说,渲染流程一般与下图相符
c) 模型->输入结构
一个模型的信息主要由顶点和三角面构成,当然还包括uv、法线、顶点色等
下图中,v开头的代表顶点信息,后面接着它的位置在三个坐标轴上的分量,f开头的是三角面信息,其后是构成它的三个顶点在顶点序列中的索引,通过这些我们可以大概了解模型信息在计算机中的表示
将这些模型信息进行选取,采集后组成一个输入结构就可以传到后续的渲染单元以供使用
d) 输入结构->顶点Shader->输出结构
顶点Shader将输入结构中的每一个顶点信息进行处理(具体后续会介绍),然后将其输出为输出结构
e) 输出结构->像素Shader->渲染结果
在像素Shader中,它处理材质、光照等传来的全局参数,并计算得到最终的渲染结 果
3) 实际操作
a) 光照模型简述
通过计算光照方向的反方向向量与模型表面法向量的点乘结果,我们可以得到光线照射在模型上的效果,简单的计算方式如下图所示。需要注意的是因为负数表示亮度没有意义,我们会将小于零的点乘结果统一按照零计算,这样可以避免带来一些奇怪的效果,这一处理被称为兰伯特光照模型
但是我们发现上面的状态并不是很合适,于是我们对它的明度乘上1/2,再加上1/2,这被称为半兰伯特光照模型,它所产生的效果会比兰伯特模型更透气(视觉上疏密得当,层次分明一目了然)
b) 实现上述光照
我们进入ShaderForge界面,右键分别创建上述的法向量和光照方向的反方向向量
然后我们添加一个向量点乘的运算式并将结果输出到Emission(自发光,即按照所给的输入输出)中,编译着色器,我们就得到了光照效果
分别实现兰伯特光照模型(将点乘结果限制到0和1之间)和半兰伯特光照模型
c) 映射
我们可以在半兰伯特状态下进行一个映射,将明度在0到1之间的取值作为u坐标,然后取一个渐变色的调子作为v坐标,通过uv坐标之间的映射实现一个渐变的效果
我们调用Append节点将上面得到的明度值和一常量(一般渐变是横向渐变的,这时v坐标我们只需要随意取一常量值即可)组合为一个向量作为我们的uv坐标
我们将一个渐变色的2D材质拖进来,并将组合好的uv坐标输入,编译着色器就可以得到上述的渐变效果的Shader
d) 课后作业
个人想法,不代表正确
Lecture 02
1) 作业点评
a) 作业答案及解析
注意这里我们的RampTexture不用太大,也不需要生成Mipmap
还需要将纹理的环绕方式改为Clamp,以防止使用UV坐标采样像素点时,出现如下图般因有像素溢出而导致的最亮处有暗点的情况
老师给出的RampTexture配色(过渡卡硬和卡死是有一定区别的:卡硬是有一定过渡的,而卡死则是两种颜色非黑即白)
一些其他的问题因为目前内容较基础,还没有涉及到
b) 创作点评
- 左一为Halftone的shader,属于阴影线shader的一种
- 左二绿色的做出两个高光点,并通过偏移法线将两个高光点移开
- 左二猴子的比较生硬,这种分为三阶的一般叫3Cut的toneshadeing
- 左一也是3Cut的toneshadeing
- 猴子想要在暗处加入网格,和上面的阴影线shader类似
- 左一也是Halftone的效果,虽然和上面的都用到了屏幕空间UV,但是一个是纹理采样,一个是程序纹理
- 左一的第三个将光照模型中光线的方向改成了视线的方向,然后做了一个调子的映射
- 右边两个都是采样RampTexture的值再和贴图颜色相乘,能做出卡通渲染的效果,但实际项目中一般会做的更细腻
这一组中枪的高光并不太适合使用Lambert模型。其他的效果都非常nice
左边的效果很nice,右边的拉扯感比较严重,这种纹理一般需要在屏幕空间投射
2) 作业批改
下面老师对前面几个突出的作业进行了分析讲解
a) 作业1
这个作业使用的RampTexture如下,这种亮部画暗,暗部画亮的画法会表现出玉石的效果
首先是半Lambert光照模型的节点
这位同学在上面的基础上增加了使用Lambert模型模拟的高光(并非镜面反射的高光)
- 首先对法向量加一个偏移向量,来改变它的方向,并进行标准化
- 将标准化后的法向量与光照方向向量进行点乘,到这里依然是Lambert模型,但是我们可以通过改变偏移向量改变法线方向,进而改变Lambert的效果(逻辑上我们应该通过改变光照方向的偏移来实现,但这里最后效果相同)
- 接着使用if节点判断点积结果,大于某个值就算作是高光,输出1,否则输出0
- 然后使用max节点使两个高光可以同时存在(对于两个图层的同一点上的值取最大值,也就是“或”逻辑),并将取值限制在0和1之间
- 最后我们将上面输出的半Lambert光照作为底色,与指定颜色作为高光组合在一起并线性插值,就达到了下面的效果
上面描述的步骤用节点表示如下
现在我们只需再加上一个菲涅尔效果,这里我们有可以直接使用的Fresnel节点,将其与我们需要的颜色相乘并与上面得到的带有高光的光照模型混合(Blend)即可
该同学得到的最终效果
b) 作业2
这个作业的突出点是使用屏幕UV与深度图结合,下面我们来细致分析它
首先是Lambert光照部分
我对于屏幕UV和深度图的理解:使用模型UV是指先用模型的UV坐标采样,再将采样结果通过投影输出到屏幕上,而使用屏幕UV是指使用屏幕的UV坐标采样,再在屏幕上模型的可视范围内输出采样结果(此时输出的结果是不包含远近关系的,所以需要和深度图结合)
深度图则可以引用OpenGL中的深度缓冲来解释:就像我们在输出每一帧的图像前,都会先将图像的颜色信息先存到颜色缓冲中一样,深度图就是用于存储深度信息的深度缓冲,每次片段着色器输出颜色之前都会将每个片段的深度值与深度缓冲进行对比,若根据深度判断前者在后者之后,则前者将会被舍弃
通过屏幕UV与深度图的结合我们得到了这个可以在远近缩放时保持不变的排线效果
使用step节点将排线效果和Lambert结合,step节点的作用是当A<=B时输出1,否则输出0(与上一个作业的步骤3作用一样)
现在我们得到的效果如下:
下面我们将排线效果当作一个遮罩,分别添加一个亮部颜色和暗部颜色并对step节点的输出值进行插值,通过这一步,我们便将排线的黑色改为设置的暗部颜色,白色改为亮部颜色
最后将Lambert模型的结果乘上一个颜色并与之前的结果相加,给整体明暗一个过渡的效果就完成了
c) 作业3
这个作业使用了Halftone的效果
这个作业依然要分成两部分分析:
我们首先将屏幕UV坐标与点阵规模相乘换算成颜色(负数按照0处理),点阵规模越大,Multiply的结果中颜色渐变的范围就越小,因为UV坐标对应值超过1的话,值还是1
这里屏幕UV可以选两种模式:Normalized(归一化)模式和Tiled(平铺)模式都会将(0,0)放到屏幕中间,区别是Normalized会将(1,1)放到屏幕右上方,Tiled会根据纵横比在x轴缩放
下面我们使用Frac节点取小数,通过这一操作,我们可以将原本a->b的范围分成(b-a)个重复的0->1的小数范围,并且这个小数区域在y轴左侧和y轴右侧相同,因为我们有四个象限,所以小数范围会分成四个区域(点阵规模越大,分开的区域越多)
可以看到,现在的小数区域原点在左下角,我们通过将它由0->1映射到-0.5->0.5来把原点移动到区域中央
我们再通过Length节点获取区域内每个向量的长度(每一个像素点距离区域中央的距离,最大应为边缘顶点的 0.52 ),并将它们转换为颜色,就得到了下面的由中央向外扩散的圆点
第二部分我们将Lambert光照模型得到的点积乘上投影(让被遮挡的地方不会发亮),并将它由0->1反向后映射到-0.5->2
我们将圆点纹理作为底数,映射后的Lambert点积作为指数,通过这一步我们使某一圆点纹理固定时,当Lambert点积值大于某一个数时输出为白色,当Lambert点积值小于某一个数时输出为黑色,不同的圆点纹理只是黑色和白色的阈值不同