本篇参考B站视频
“技术美术百人计划”·霜狼_may ;
《Shader入门精要》·冯乐乐女神著;
几何着色器·风宇冲
草地渲染·流朔
草渲染2
shader中随机数的生成法
碎片效果
本篇主要用于自我复习,其中会掺入一些个人观点,如有疑问或发现有什么错误,请多指教~
本篇内容主要包括:曲面细分着色器与几何着色器(缩写分别为TESS和GS);
写在前面
在正式开始之前,我觉得应该先回顾下渲染管线,尤其是这两个着色器的位置,因为在面试中也有被问到,如下图;
本篇要说的这两位都是在顶点着色器之后,裁剪之前,其中曲面细分着色器在几何着色器之前,两个都是可选的着色器,并不是必须要写的,且曲面细分着色器目前在手机上基本上没应用,而几何着色器最常用的则是用来渲染草地;
一.曲面细分着色器
1.它能干些啥
-
海浪,雪地,下图中的右边通过曲面细分从平面变的有凹凸感
-
与置换贴图结合,置换贴图是移动了顶点位置来实现的,那么通过使用曲面细分着色器,我们可以增多模型顶点数量,从而使得效果看起来更好;
2.进一步细分曲面细分着色器
如下图,可以看到按顺序分为细分控制着色器(Hull Shader),Tessellation Primitive Generation,细分计算着色器(Domain Shader);
曲面细分着色器,细分后的点,其空间位于重心空间,在细分计算着色器中,将其转换为我们要用的空间;
- HULL Shader
- 决定细分的数量(设定曲面细分因素【Tessellation factor】以及内曲面细分因素【Inside Tessellation factor】)
- 对输入的Patch参数进行改变(根据需求要进行变换时)
- Tessellation Primitive Generation
- 进行细分操作
- Domain Shader
- 对细分后的顶点进行处理,将其从重心空间转换到屏幕空间
3.输入与输出
- 输入
Patch,可以看成是多个顶点的集合,包含每个顶点的属性(所有顶点共享),可以指定一个Patch包含的顶点数以及自己的属性; - 功能
将图元细分(可以为三角形,矩形等) - 输出
细分后的顶点
4.HULL Shader各参数解析
- Tessellation Factor
决定将一条边分成几个部分,它又三种分法,见下图:
三者区别:
- equa_Spacing:将一条边等分,Subdivide参数是几就是几等分;
- fractional_even_Spacing:最小值为2,Subdivide参数向上取最近的偶数,将周长分为n-2的等长的部分,以及两端不等长的部分,目的是让细分更平滑;
- fractional_odd_Spacing :最小值为1,Subdivide参数向上取最近的奇数,将周长分为n-2的等长的部分,以及两端不等长的部分,目的是让细分更平滑;
- Inner Tessellation Factor
内部细分因素,当该参数为3时,无论上面的Tessellation Factor怎样去进行切分的,我们把三角形切分为三等分,然后分别找最近的两个切分的点,做其延长线,其焦点便是在新内部三角形的一个点;
(概括下就是取边上点的垂线的延长线做交点,直至最后无交点或者交于中心一点)
5.代码解析
-
使用曲面细分着色器涉及到两个hull和domain两个shader,并且要引用其库文件;
-
不同于以往的shader代码,这里的vert函数并非顶点着色器,而是用来做空间转换用的,它应用于domain函数中;
-
定义宏,由于并非所有平台均支持曲面细分着色器,因而通过定义宏,以防出现bug红;
-
顶点着色器结构体定义,以及hullshader中用到的Patch属性,根据是三角形还是矩形的图元,edge[]里填3或4;
关于unity中导入四边面模型,查了下要求是模型在导出时是四边面,且勾选如下图的选项,即可(但是我自己测试并无卵用,不知道哪里出错了)
-
接下来是顶点着色器,没啥好说的,由于在此之前已进行过空间转换,所以这里只是简单的传参;
-
接下来结合看两段,大致各段代码意思其实都如下图所示,其中中括号段落的第三条,用来表示图元的组装是按照顺时针还是逆时针,会影响最后显示有无正面剔除或者背面剔除;第四个中括号则是关联上面的一大段函数,规定曲面细分的属性;hullProgram则是hull函数,根据图元不同,InputPatch中的数字不同;
- domain shader先定义图元,再进行空间转换,括号中的bary是重心空间(以重心为原点的坐标系)下的系数,用该系数与重心坐标还原到模型空间;
- 最后像素着色器
参考着,写了一遍完整的,根据自己理解将其各部分说明了下,代码如下:
Shader "Unlit/sh_Tressla"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {
}
_TessellationUniform("细分参数",float)= 1.0
}
SubShader
{
Tags {
"RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma hull myhull
#pragma domain myds
//接下来定义的顶点着色器并非如往常一样的
#pragma vertex tessvert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;