这是unityJapan办的官方演讲会中讲解的一个用shaderGraph制作能量护盾的例子。由于用到SG,所以是基于URP的。(HDRP应该也可以用)
官方油管地址:https://www.youtube.com/watch?v=7ToExWKVZW0&t=2407s
最终效果如图:
主要分解为步骤步骤:
1.检测物体之间的接触边缘
2.画出透明物体的边缘
3.给边缘加上花纹
4.扭曲透过物体的像
检测物体之间的接触边缘
STEP1. 设置管线创建一个新的Shader
由于要通过深度来检测接触边缘,所以在管线的配置文件[1]将其中的Depth Texture勾选上。由于不需要进行光照计算,建立一个Unlit shader,将master节点设定改为transparent渲染队列和双面渲染。
STEP2. 利用sceenDepth节点进行接触检测
建立一个screenDepth[2]节点,采样改为eye,这个节点是获得屏幕上每个像素点对应的深度信息(只能对应显示的非透明物体上的点)。再建立一个screenPosition[3]节点,模式改为raw来获取该material所在物体的深度信息。把screenPosition节点里的w分量分出来,用sceenDepth节点输出的值去减,最后输出到master节点上的color看一下。发现同球体接触的边缘变黑。其实减去的值就是模型上点延视线方向达到的最近的非透明物体的距离,这个值0~∞的。于是设置一个变量a减去这个值的话,范围就变成-∞~0~a。因此可以通过a来控制边缘的厚度。由于透明度0-1,所以用smoothStep[4]来限制输出值的范围,同时由于其插值的特性,用来做边缘光带的过渡。最终节点如图:
画出透明物体的边缘
一般的物体可以通过FresnelEffect节点简单的做出边缘发光的效果。但是对于双面绘制的物体行不通,因为由于菲涅尔的原理,导致背面的节点无法实现边缘发光的效果。于是根据菲涅尔的原理,要重新连一个适用于双面的菲涅尔。其实也很简单,就是将表面法线与视线方向单位向量点乘后取绝对值再用1减去这个值即可。
连接的节点图如下:
边缘加上花纹
花纹图案的实现就比较简单,就是在原本基础上导入一张黑白花纹的图案(因为颜色控制是用baseColor)。之后再叠加一层噪声纹理,通过UV动画让花纹动起来就行。有趣的是可以通过UV和和sin节点,形成移动的黑白条纹。因为有sin会有负值,再用remap重映射至0~1。
扭曲透过物体的像
接下来要做给透过护盾时光线扭曲的效果。 由于之前的shader是用了alpha通道,而扭曲像其实是通过将渲染不透明物体后的结果按屏幕坐标贴到物体上来实现的。由于透过的地方本来alpha为零,也就无法显示贴上去的颜色,所以要另开一个shader和材质做目标物体的第二材质,同时要保证这个材质的的渲染队列在力场材质之前。
STEP1. 设置管线创建一个新的Shader
由于要要获得不透明物体的渲染结果,在渲染管线的配置文件[1]的设定中开启Opaque Texture。由于同样不需要进行光照计算,建立一个Unlit shader,将master节点设定改为transparent渲染队列。
STEP2. 接受不透明物体的渲染结果
建一个texture2D的变量,reference填入_CameraOpaqueTexture,将expored勾去掉,即可用来接收渲染场景的贴图。
将这个texture和ScreenPosition[3](这回用default模式)连到sampler节点上,发现物体消失,证明成功接收到了不透明物体的渲染结果。
那之后的事情就简单了,只要给屏幕坐标一点干扰就行。
同加花纹噪声纹理一致,用时间和噪声来做一个动态的扰动,加到ScreenPosition的输出即可。要注意的是因为是直接处理坐标,即使是1都比较大,要将扰动remap到一个合理的范围。
混合各个部分
扰动是在另一个材质上,所以在Meshrenderer组件里加上相应材质就行,要注意设置Render Queue。
力场材质里的各部分混合如下:
{(双面菲涅尔)add (边缘检测)} Blend:Overlay[5] {花纹处理}
写在最后
这个效果我放在了我的开源仓库里Art&EffectCollection_Unity。
[1]: 默认的文件名为:UniversalRenderPipelineAsset
[2]: ScreebDepth节点:通过ZBuffer获得屏幕空间下的每个像素点的深度信息有三种采样模式:
1.Linear01:返回0~1之前的深度信息
2.raw:返回未处理的深度信息
3.eye:返回转换成摄像机坐标的深度信息(前两个都跟近接平面有关)
[3]:screenPosition节点:获取shader所应用的mesh的屏幕空间坐标,有4种模式:
1.Default:返回屏幕坐标。这个模式屏幕坐标除了clip space position W。
2.Raw 返回屏幕坐标。这个模式屏幕坐标没除clip space position W。其a通道为顶点的深度信息。
3.Center 在default上添加了偏移,让 float2(0,0) 在屏幕的中心。 Tiled 在default添加了偏移,让float2(0,0) 在屏幕的中心并且使用frac进行tiled。
[4]:SmoothStep节点:如果输入In在Edge1和Edge2之间,则返回Hermite插值。 如果In小于 Edge1,则返回0,如果In大于Edge2,则返回1。 这个节点类似于Lerp节点,但有两个显着差异。第一,此节点返回值介于0和1之间而Lerp返回值介于输入的A和B之间。第二,该节点使用平滑的Hermite插值而不是线性插值。Hermite插值在开始加速 并在最后减速。这对创建自然的动画,淡入淡出和其他转换非常有用。
[5]:Blend节点:
Overlay模式:这个模式下值小于0.5的按变暗处理,值大于0.5的按变亮处理。也就是说暗的地方会变得更暗,亮的地方会变得更亮。