Unity Shader 简单美颜

本文详细介绍了基于Unity Shader的磨皮和美白算法实现,包括双边滤波原理和美颜Shader代码。通过Log函数调整亮度,实现图像两端变化弱,中间变化强的效果,同时应用双边滤波进行保边去噪,提高图像质量。最终实现的效果是图像暗部提亮,整体平滑,具有美白和磨皮效果。
摘要由CSDN通过智能技术生成

一、原理

参考博文
Unity Shader 实现磨皮效果
Bilateral Filters(双边滤波算法)原理及实现(二)
对皮肤美白算法的一些研究

美白公式
效果:图像两端(明-暗)变化弱,中间变化强。

11111.png

w(x,y)为输入的像素颜色,v(x,y)为输出的像素颜色,beta为调节参数。

双边滤波公式
效果:保边去噪

22222.png

2222.png

11111.png

(高斯滤波函数)

3333.png

g(i,j)为输出的像素颜色,f(k,l)为当前输入的像素颜色,S(i,j)是指以(i,j)为中心的(2N+1)*(2N+1)的卷积核覆盖的像素区域。

二、Shader

 
//一个简单美颜Shader
//功能:磨皮、美白
Shader "Custom/BeautyFaceShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
//模糊大小 (值越大越模糊)
_Radius ("Radius", Range(0, 10)) = 5
//调节距离空间权重,值越大权重越大
_SigmaS("SigmaS", float) = 3
//调节颜色空间权重,值越大权重越大
_SigmaR("SigmaR", float) = 1
//亮度值
_Brightness("Brightness", float) = 20
//对比度
_Contrast("Contrast", float) = 1.18
//饱和度
_Saturation("Saturation", 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;
half4 _MainTex_TexelSize;
float _Radius;
float _SigmaS;
float _SigmaR;
float _Brightness;
float _Contrast;
float _Saturation;

//计算像素亮度值
float Luminance(float3 color)
{
return dot(color, float3(0.2125, 0.7154, 0.0721));
}

//提亮暗部区域
float3 Brightness(float3 col)
{
//此公式: 使图像暗部变化强,亮部变化弱
//col.r = log(col.r * _Brightness);
//col.g = log(col.g * _Brightness);
//col.b = log(col.b * _Brightness);

//原理: https://blog.csdn.net/weixin_33716557/article/details/86197248?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control
//此公式: 使图像两端变化弱,中间变化强
col.r = log(col.r * (_Brightness - 1) + 1) / log(_Brightness);
col.g = log(col.g * (_Brightness - 1) + 1) / log(_Brightness);
col.b = log(col.b * (_Brightness - 1) + 1) / log(_Brightness);
return col;
}
//原理: https://blog.csdn.net/u013066730/article/details/87919412
//转载: https://www.jianshu.com/p/90feece27a04?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
//双边滤波算法-保边去噪
float3 BilateralFilter(float2 uv)
{
float i = uv.x;
float j = uv.y;
float sigmaSSquareMult2 = (2 * _SigmaS * _SigmaS);
float sigmaRSquareMult2 = (2 * _SigmaR * _SigmaR);

float3 centerCol = tex2D(_MainTex, uv).rgb; // 中心点像素的颜色 //
float centerLum = Luminance(centerCol); // 中心点像素的亮度 //

float3 sum_up; // 分子 //
float3 sum_down; // 分母 //
for (int k = -_Radius; k <= _Radius; k++)
{
for (int l = -_Radius; l <= _Radius; l++)
{
float2 uv_new = uv + _MainTex_TexelSize.xy * float2(k, l);
float3 curCol = tex2D(_MainTex, uv_new).rgb; // 当前像素的颜色 //
float curLum = Luminance(curCol); // 当前像素的亮度 //
float3 deltaColor = curCol - centerCol;
float len = dot(deltaColor, deltaColor);
// float exponent = -((i-k)*(i-k)+(j-l)*(j-l))/sigmaSSquareMult2 - (curLum-centerLum)*(curLum-centerLum)/sigmaRSquareMult2;
float exponent = -((i - k) * (i - k) + (j - l) * (j - l)) / sigmaSSquareMult2 - len / sigmaRSquareMult2;
float weight = exp(exponent);
sum_up += curCol * weight;
sum_down += weight;
}
}

float3 rgb = sum_up / sum_down;
return rgb;
}

v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

float4 frag(v2f i) : SV_Target
{
//保边去噪
float3 rgb = BilateralFilter(i.uv);
//该像素对应的亮度值
fixed luminance = Luminance(rgb);
//使用该亮度值创建一个饱和度为0的颜色
fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
//创建一个对比度度为0的颜色
fixed3 avgColor = fixed3(0.5, 0.5, 0.5);

//调整饱和度
rgb = lerp(luminanceColor, rgb, _Saturation);
//调整对比度
rgb = lerp(avgColor, rgb, _Contrast);
//调整亮度
rgb = Brightness(rgb);

return fixed4(rgb, 1);
}
ENDCG
}
}
}

效果

11111.png

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值