欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity Shader - 遮罩效果

程序员文章站 2024-02-12 23:12:34
...

已经有二十天没有更新博客了,这段时间也一直在学习WebGL shader,后续可能也会更新一些WebGL相关的博客。

转入正题,我们来说说今天要实现的一个shader效果 - 遮罩
其实遮罩原理非常简单,把源像素遮罩图形像素相乘就行了。

大致效果如下:
Unity Shader - 遮罩效果

准备工作

1.创建一个场景和一些物体(cube,sphere等)。
2.创建一个新的C#脚本和一个Shader,命名为Mask。
3.把Mask.cs拖拽到Camera上。

具体实现

Mask.cs脚本代码如下:

PostEffectsBase 基类 可以到我之前的一篇文章里查看,主要是封装了一些功能,这里就不详细说了。

Mask.cs脚本主要是负责抓取unity渲染到的图像,然后经过后期处理(经过shader处理)后再渲染到屏幕上。

using UnityEngine;
public class Mask : PostEffectsBase {
    // shader
    public Shader myShader;
    //材质 
    private Material mat = null;
    public Material material {
        get {
            // 检查着色器并创建材质
            mat = CheckShaderAndCreateMaterial (myShader, mat);
            return mat;
        }
    }

    // 遮罩中心位置
    private Vector2 pos = new Vector4 (0.5f, 0.5f);

    void Start () {
        //找到对应的Shader文件  
        myShader = Shader.Find ("lcl/screenEffect/MaskEffect");
    }

    // 渲染屏幕
    //source:unity渲染得到的图像,destination:渲染纹理到屏幕上
    void OnRenderImage (RenderTexture source, RenderTexture destination) {
        if (material) {
            material.SetVector ("_Pos", pos);
            //经过material处理后 渲染到屏幕上
            Graphics.Blit (source, destination, material);
        } else {
            Graphics.Blit (source, destination);
        }
    }
	
    void Update () {
        if (Input.GetMouseButton (0)) {
            Vector2 mousePos = Input.mousePosition;
            //将mousePos转化为(0,1)区间
            pos = new Vector2 (mousePos.x / Screen.width, mousePos.y / Screen.height);
        }
    }
}

Shader:

首先我们需要绘制一个遮罩图形,这里就我绘制一个圆,当然也可以选择绘制其他图形。

这里绘制圆的主要思路:判断 当前像素点到圆心的距离是否小于等于半径,如果是则说明在圆内,否则在圆外。 可以通过setp或者smoothstep内置函数判断。

// 创建圆
// pos : 圆心
//radius: 半径
//uv: 当前像素坐标
fixed3 createCircle(float2 pos,float radius,float2 uv){
    //当前像素到中心点的距离
    float dis = distance(pos,uv);
    //  smoothstep 平滑过渡, 这里也可以用 step 代替。
    float col = smoothstep(radius + 0.008,radius,dis );
    return fixed3(col,col,col) ;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed3 mask = createCircle(float2(0.5,0.5),0.2,i.uv);
    return fixed4(mask,1.0);
}

如图:
Unity Shader - 遮罩效果

最后我们融合纹理颜色值,即 圆的颜色值 * 纹理颜色。
这里的 * 和 && 类似,表示并且的意思

fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed3 mask = createCircle(float2(0.5,0.5),0.2,i.uv);
    //这里的 * 和 && 类似,表示并且的意思。
    return col * fixed4(mask,1.0);
}

Unity Shader - 遮罩效果

可以看到遮罩的基本功能已经实现,最后我们把鼠标的位置传递给shader作为遮罩中心,并且把图形边缘模糊程度设置为变量,以便于我们调节。

c#:

// 渲染屏幕
    void OnRenderImage (RenderTexture source, RenderTexture destination) {
        if (material) {
            // 把鼠标坐标传递给shader
            material.SetVector ("_Pos", pos);
            // 模糊程度
            material.SetFloat ("_EdgeBlurLength", edgeBlurLength);
            // 渲染
            Graphics.Blit (source, destination, material);
        } else {
            Graphics.Blit (source, destination);
        }
    }

    void Update () {
        if (Input.GetMouseButton (0)) {
            Vector2 mousePos = Input.mousePosition;
            //将mousePos转化为(0,1)区间
            pos = new Vector2 (mousePos.x / Screen.width, mousePos.y / Screen.height);
        }
    }
// 创建圆
fixed3 createCircle(float2 pos,float radius,float2 uv){
    //当前像素到中心点的距离
    float dis = distance(pos,uv);
    //  smoothstep 平滑过渡
    float col = smoothstep(radius + _EdgeBlurLength,radius,dis );
    return fixed3(col,col,col) ;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed3 mask = createCircle(_Pos,0.2,i.uv);
    return col * fixed4(mask,1.0);
}

Unity Shader - 遮罩效果

当然!除了绘制圆外,我们还可以绘制其他图形,可以通过不同的造型函数绘制不同的遮罩图形,也可以用纹理图片。

完整代码可以到我的GitHub上查看,里面包含了多种图形造型函数。
shader路径
c#代码

图形如下:
Unity Shader - 遮罩效果

Unity Shader - 遮罩效果
Unity Shader - 遮罩效果