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

}

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

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

相关推荐
变身缎带4 小时前
Unity中的NetworkManager基于protobuf, Socket-TCP
tcp/ip·unity·游戏引擎
AllBlue12 小时前
unity调用安卓方法
android·unity·游戏引擎
郝学胜-神的一滴12 小时前
Horse3D游戏引擎研发笔记(十):在QtOpenGL环境下,视图矩阵与投影矩阵(摄像机)带你正式进入三维世界
c++·3d·unity·游戏引擎·godot·图形渲染·unreal engine
AllBlue15 小时前
unity导出成安卓工程,集成到安卓显示
android·unity·游戏引擎
Sator117 小时前
Unity的FishNet相关知识
网络·unity·游戏引擎
AllBlue18 小时前
安卓调用unity中的方法
android·unity·游戏引擎
李岱诚19 小时前
epic商城下载,ue4报错处理
游戏引擎·ue4
jtymyxmz1 天前
《Unity Shader》10.1.4 折射
unity·游戏引擎
在路上看风景1 天前
12. Burst
unity
平行云PVT2 天前
实时云渲染解决UE5 像素流插件迁移及传输数据受限问题
unity·ue5·xr·实时云渲染·云桌面·像素流·云推流