首先想到的是最简单的方法就是每帧设置被覆盖的UI纹理的alpha值。 这种方法的缺点是对CUP造成很大的压力,因为移动端的项目主要负载还是在CPU上(iOS的CPU负载比Android机型大很多)unity ui界面切换特效,这个解决办法没有考虑太多。 当然,需要注意的是,如果逐步更新纹理中某些像素的alpha值,计算量也不会太大。 不过我还是觉得这个方法不够美观,Pass。
如果不想使用CUP,自然就得使用GPU来设置Alpha值,于是就想到了使用RenderTexture来实现这个UI控制。 简单来说,就是在绘制GUI的脚本中创建一个RenderTexture,并将其作为新相机的RenderTarget。 通过脚本在这个相机上画一个全屏的冷却遮罩,这样这个RT就可以作为技能冷却的UI组件了。 来用了。
现在的问题是如何绘制全屏的冷却蒙版。 您可以创建一个与相机视锥体大小完全相同的补丁,然后制作一个材质球并编写着色器代码以将遮罩贴图部分渲染到该补丁上。 。 其实创建补丁这一步完全可以省略,因为基本上所有后期特效PostEffects都需要创建这样的补丁。 这些PostEffects大多数都会做一些图像处理,比如改变色调、模糊、干扰等。因此,Unity3D提供了一个非常方便的方法,比如Graphic.Blit(RenderTexture source, RenderTexturedestination, Material mat),它省去了创建补丁的步骤。 源图像用作垫子的 -_MainTex 来渲染到目标图像。 。
因此,首先让我们看看如何使用 Image Effect 包中提供的 ImageEffectBase 基类来编写附加到相机的渲染控制脚本。 这个脚本其实非常简单。 我使用 C#:
public class CDMask: ImageEffect
{
public Texture2D cdMaskTex;
public float cdTime;
public float CdTime
{
set {material.SetFloat(“_CDPercentage”, value/cdTime); }
}
void Awake()
{
material.SetTexture(“_MaskTex”,cdMaskTex);
}
void OnRenderImage(RenderTexture source, RenderTexturedestination)
{
Graphics.Blit(source,destination, material);
}
}
基类 ImageEffect 有一个 Shader 公共变量和一个在调用时创建的材质保护变量。 它还负责检查渲染设备是否支持Shader。
OnRenderImage 是一个消息方法。 在相机将场景渲染到屏幕图像缓存后,附加到与相机组件相同的对象的任何脚本都会调用此方法。 两个传入参数source是缓存中的图片,destination是最终输出。 对于RenderTarget图像来说,在这个方法中调用Graphics.Blit显然是合适的。
剩下的就是编写一个着色器了。 没有什么特别的困难。 您只需将图像 alpha 值设置放入片段着色器中,并稍微修改 ImageEffect 包中的 Overlay Shader 即可。
编写这个shader有几点需要注意:
1. 不要使用表面着色器。 Unity3D创建的Shader文件默认使用表面着色器进行绘制。 它的表面着色器确实方便,但是如果用在Blit方法中就会死得很惨。 在电脑上的编辑器中效果可能还好unity ui界面切换特效,但在真机上完全没用。 官方论坛有人解释了具体原因,主要与GL2.0支持的平台兼容性问题以及表面着色器使用的UnityCG.cginc中的一个函数有关。 简而言之,只需使用CG编写顶点和片段着色器即可。 顶点着色器可以直接从ImageEffect包中的Overlay Shader复制。
2.在SubShader中设置固定管线参数时记得写ColorMask RGBA。 如果我只写RGB,我会死得很惨。
最后我想说的是,其实有一种更快更聪明的方法来绘制这个旋转蒙版。 这是官方论坛上有人提供的。 它使用AlphaTest功能游戏素材下载 免费,配合mask图像的Alpha通道,节省大量计算。 只是实际使用中渲染效果并不理想3D场景,边缘非常不平整。 这可能是手机平台对图片进行压缩造成的。 然而,似乎所有着色器(例如AlphaCutout)都有这个问题。 很多人在后续的回复中也提到了这一点。 不过最终没有被采用,但这仍然是一个非常好的解决方案。 一旦给出链接,我就不会详细介绍。