在之前制作的Unity FPS游戏中,引入了具有全息瞄准器的ACR步枪。全息瞄准镜(Holographic Sight)是一种利用激光全息衍射技术生成瞄准分划的先进光学瞄具。它以其独特的瞄准方式、快速的目标锁定能力和出色的环境适应性,在军事、执法乃至竞技射击领域都备受青睐。全息瞄准器的最大特点是无视差,由于分划是作为平行光进入眼睛的,无论你的眼睛在目镜后的什么位置观察(只要还能看到分划),分划标记相对于目标的位置都是固定的。全息瞄准镜的工作原理如下图。

在很多FPS游戏中都有出现全息瞄准镜的身影,如下图。

现在就通过Unity的Shader Graph来实现全息瞄准器的功能。在Unity项目中,选择Create->Shader Graph->URP->Unlit Shader Graph,新建一个名为HoloSight的Shader Graph,然后进入编辑界面。
在Shader Graph的输入面板设置中,单击+号,新增一个类型为Texture2D的名为MainTex的输入变量,新增一个类型为Color的名为Color的变量,以及两个类型为Float的名为AlphaClip和Size的变量。单击Fragment节点,在Graph Settings设置面板中,单击Alpha Clipping选项,开启透明度裁剪功能,使得物体的某些部分透明。(即只叠加全息投影器的分划板,其他部分透明)。如下图。

把Color和AlphaClip变量拖动到编辑界面,连接Fragment节点的Base Color和Alpha Clip Threshold输入。Color用于定义全息投影的主色调(例如发光的红色),AlphaClip是设置一个全局阈值,低于阈值的像素被完全丢弃(镂空),高于或等于的像素被保留,从而创造出尖锐的数字化边缘。
把MainTex变量拖动到编辑界面,通过Sampler Texture 2D节点进行采样,Sampler Texture 2D节点的A端口输出连接到Fragment节点的Alpha端口,控制表面镂空效果,如下图。

全息瞄准器采用激光全息术,使分划板图案作为平行光进入人眼。人眼在接收到平行光时,会认为光源在无限远处。因此,只要眼睛能看到瞄准镜内的分划,无论从哪个角度,该分划都会"粘附"在目标上。要模拟这个效果,需要在编辑界面中增加一个View Direction节点(获取摄像机看向物体的方向向量,Space选择Tangent方向意味着该方向是基于每个片元自身的法线方向来计算的),连接到Normalize节点进行归一化处理,然后再连接到到Negate(反转向量方向)节点,从而获取从表面到摄像机的视角,如下图。

将Negate节点的输出和Size变量通过Multiply节点连接,以控制视角偏移的强度,再将其和Add节点连接,加上0.5,向向量各分量的取值范围从 [-1, 1]映射到 [-0.5, 1.5]区间,最后将其输入到Fragment节点的UV输入端口。增加一个Sampler State节点,设置Wrap为Clamp,将其连接到Fragment节点的Sampler端口(能防止当UV坐标超出常规的 [0, 1]范围时,纹理在边缘处出现不希望的重复),如下图。

通过以上设置,即可模拟分划板显示在无限远处的物体上,无论摄像机的角度如何变化,只要看到分划板,都可以看到分划板"粘"在物体上,不会因为观察位置的变化而相对于目标移动,实现无视差的效果。
新建一个名为Holo Sight的Material,Shader选择刚才创建的Holo Sight Shader Graph,拖动分划板图片到MainTex中,设置Color为红色,如下图。

现在可以查看效果了。在场景中新增一个Cube物体,设置其材质为刚才创建的Holo Sight,可以看到分化板显示在了远处的物体上,移动摄像机的视角,分划板在物体上的位置没有变化,实现了无视差的效果。如下图。


从以上效果可见,无论从哪个角度观察,分划板在物体上的位置没有发生变化。