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);

}

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

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

相关推荐
真鬼12310 小时前
【Unity 6】Unity6快捷下载,快速下载
unity·游戏引擎
会潜水的小火龙11 小时前
unity打包apk报错Failure to initialize问题解决方法
unity·游戏引擎
平行云14 小时前
实时云渲染平台数据通道,支持3D应用文件上传下载分享无缝交互
linux·unity·云原生·ue5·gpu算力·实时云渲染·像素流送
Sator115 小时前
unity仅用粒子系统实现拖尾
unity·游戏引擎
游乐码15 小时前
Unity基础(五)四元数相关
unity·游戏引擎
想做后端的前端16 小时前
Unity热更新 - HybridCLR & YooAsset
unity·游戏引擎
鹿野素材屋16 小时前
Unity预加载:减少游戏中首次加载资源时的卡顿
windows·游戏·unity
RPGMZ17 小时前
RPGMZ游戏引擎事件技巧大全
javascript·游戏引擎·事件·rpgmz·rpgmakermz
天若有情67317 小时前
Superpowers 游戏引擎核心应用场景与落地指南
游戏引擎·superpowers
winlife_17 小时前
嵌入式 MCP server vs 外挂桥接进程:引擎编辑器自动化的架构取舍
架构·自动化·编辑器·游戏引擎·架构设计·mcp·编辑器自动化