Unity自定义后处理——用偏导数求图片颜色边缘

大家好,我是阿赵。

继续介绍屏幕后处理效果的做法。这次介绍一下用偏导数求图形边缘的技术。

一、原理介绍

先来看例子吧。

这个例子看起来好像是要给模型描边。之前其实也介绍过很多描边的方法,比如沿着法线方向放大模型,或者用NdotV来求边缘,之类。

不过这篇文章所说的内容,其实和模型描边是没有关系的。因为这是屏幕后处理,他针对的并不是模型,所以也不会有法线方向,有观察空间的计算。用偏导数,求的是一张图片的颜色变化。

简单来说,我们要求的是连续像素点之间的颜色变化。

听起来好像很复杂,不过由于已经提供了现成的方法,所以我们直接用就行了。方法就是ddx和ddy。

ddx是求横向像素之间的变化的,可以理解成是当前像素点和横向前一个像素点颜色的变化。

ddy就是纵向像素之间的变化了。

通过ddx和ddy,我们可以求出一张图片颜色变化比较强烈的一些边缘位置。

当求出了这些范围之后,我们可以给他填充不同的颜色,也可以指定背景色,发挥想象力之后,就可以做出一些有趣的效果了。

二、代码实现

1、C#代码

复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class OutlineCtrl : MonoBehaviour
{
    private Material outlineMat;
    public float lineStrength = 1;
    public Color baseColor = Color.white;
    public Color lineColor = Color.black;
    public float powVal = 1;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(outlineMat == null)
        {
            outlineMat = new Material(Shader.Find("Hidden/azhaoOutline"));
        }
        outlineMat.SetFloat("_lineStrength", lineStrength);
        outlineMat.SetColor("_baseColor", baseColor);
        outlineMat.SetColor("_lineColor", lineColor);
        outlineMat.SetFloat("_powVal", powVal);
        Graphics.Blit(source, destination,outlineMat);
    }
}

2、Shader

复制代码
Shader "Hidden/azhaoOutline"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_lineStrength("LineStrength",Float) = 1
		_lineColor("LineColor",Color) = (0,0,0,1)
		_baseColor("baseColor", Color) = (1,1,1,0)
		_powVal("powVal",Float) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			float _lineStrength;
			float4 _lineColor;
			float3 _baseColor;
			float _powVal;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
                // sample the texture
                half4 col = tex2D(_MainTex, i.uv);
				float grayscale = col.r * 0.2126729f + col.g * 0.7151522f + col.b * 0.0721750f;
				grayscale = pow(grayscale, _powVal);
				float ddVal = saturate(ddx(grayscale) + ddy(grayscale))*_lineStrength;
				half3 finalCol =  _baseColor.rgb * (1.0 - ddVal) + _lineColor.rgb * ddVal;
				return half4(finalCol, 1);

            }
            ENDCG
        }
    }
}

三、和原图的叠加

稍微做的一点点扩展,之前描绘出来的是纯背景色和线条色,其实我们也不一定要用纯背景色的,比如把偏导数得到的结果,和原图做叠加,就可以做出类似模型描边的效果。

代码很简单,修改一下shader的片段着色器程序就可以:

复制代码
half4 frag (v2f i) : SV_Target
{
    // sample the texture
    half4 col = tex2D(_MainTex, i.uv);
	float grayscale = col.r * 0.2126729f + col.g * 0.7151522f + col.b * 0.0721750f;
	grayscale = pow(grayscale, _powVal);
	float ddVal = saturate(ddx(grayscale) + ddy(grayscale))*_lineStrength;
	half3 finalCol = col.rgb*(1 - ddVal) + _lineColor.rgb * ddVal;
	return half4(finalCol, 1);

}

可以看出,描边的效果其实没有使用法线计算那么干净清晰。这是因为偏导数依赖于颜色的变化,越分明的变化,结果是越清晰,然后图片的分辨率如果不够大,得出的效果也会比较的模糊。

不过由于它并不依赖于其他数据,只要有颜色,就能计算,所以在屏幕后处理上,就刚好可以做出一些特殊的效果了。

相关推荐
mit6.82410 小时前
[shad-PS4] Vulkan渲染器 | 着色器_重新编译器 | SPIR-V 格式
c++·游戏引擎·ps4
向宇it18 小时前
【unity小技巧】在 Unity 中将 2D 精灵添加到 3D 游戏中,并实现阴影投射效果,实现类《八分旅人》《饥荒》等等的2.5D游戏效果
游戏·3d·unity·编辑器·游戏引擎·材质
向宇it21 小时前
Unity Universal Render Pipeline/Lit光照材质介绍
游戏·unity·c#·游戏引擎·材质
__water1 天前
RHA《Unity兼容AndroidStudio打Apk包》
android·unity·jdk·游戏引擎·sdk·打包·androidstudio
不爱说话的采儿1 天前
UE5详细保姆教程(第四章)
笔记·ue5·游戏引擎·课程设计
温玉琳琅2 天前
【UE5】虚幻引擎小百科
ue5·游戏引擎·虚幻
两水先木示2 天前
【Unity3D】微信小游戏适配安全区域或胶囊控件(圆圈按钮)水平高度一致方案
unity·微信小游戏·安全区域·ui适配·胶囊控件·safearea
枯萎穿心攻击2 天前
ECS由浅入深第三节:进阶?System 的行为与复杂交互模式
开发语言·unity·c#·游戏引擎
不绝1912 天前
怪物机制分析(有限状态机、编辑器可视化、巡逻机制)
网络·游戏·unity·游戏引擎
unicrom_深圳市由你创科技2 天前
Unity开发如何解决iOS闪退问题
unity·ios·蓝桥杯