一、亮度、饱和度、对比度
脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
//在编辑器下也可执行
[ExecuteInEditMode]
public class BrightnessShader : MonoBehaviour
{
public Shader Brightshader;
private Material mat;
//亮度
public float Brightness;
//饱和度
public float Saturation;
//对比度
public float Contrast;
public Material Mat
{
get
{
if(mat==null)
{
Material _newmat = new Material(Brightshader);
_newmat.hideFlags= HideFlags.HideAndDontSave;
mat = _newmat;
return mat;
}
else
{
return mat;
}
}
}
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
Mat.SetFloat("_Brightness", Brightness);
Mat.SetFloat("_Saturation", Saturation);
Mat.SetFloat("_Contrast", Contrast);
Graphics.Blit(src, dest, Mat);
}
}
Shader:
Shader"unity/BrightShader"
{
Properties
{
_MainTex("MainTex",2D)="white"{}
//亮度调节
_Brightness("Brightness",float)=1.0
//饱和度调节
_Saturation("Saturation",float)=1.0
//对比度调节
_Contrast("Contrast",float)=1.0
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float _Saturation;
float _Brightness;
float _Contrast;
struct appdate
{
float4 vertex : POSITION;
float4 uv : TEXCOORD;
};
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD;
};
v2f vert(appdate v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=v.uv;
return o;
}
float4 frag(v2f i):SV_Target
{
float4 mainTex = tex2D(_MainTex,i.uv);
//亮度颜色
float3 finalColor = mainTex.rgb*_Brightness;
//饱和度
//计算该像素的亮度值
float luminance = 0.2125*mainTex.r+0.7154*mainTex.g+0.0721*mainTex.b;
//饱和度为0的颜色值
float3 luminanceColor=float3(luminance,luminance,luminance);
//插值
finalColor=lerp(luminanceColor,finalColor,_Saturation);
//对比度
//对比度为0的颜色值
float3 avgColor=float3(0.5,0.5,0.5);
finalColor=lerp(avgColor,finalColor,_Contrast);
return float4(finalColor,mainTex.a);
}
ENDCG
}
}
}
二、边缘检测
脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class EdgeDetection : MonoBehaviour
{
public Shader EdgeShader;
[Range(0,1)]public float WO;
private Material mat;
public Material Mat
{
get
{
if(mat==null)
{
Material _newmat = new Material(EdgeShader);
_newmat.hideFlags = HideFlags.HideAndDontSave;
mat = _newmat;
return mat;
}
else
{
return mat;
}
}
}
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
Mat.SetColor("_EdgeColor", Color.black);
Mat.SetColor("_BackgroundColor", Color.white);
Mat.SetFloat("_EdgeWithOnly", WO);
Graphics.Blit(src,dest,Mat);
}
}
Shader:
Shader"unity/EdgeShader"
{
Properties
{
_MainTex("MainTex",2D)="white"{}
//滑杆
_EdgeWithOnly("EdgeWithOnly",float)=0
//描边颜色
_EdgeColor("EdgeColor",Color)=(0,0,0,0)
//背景颜色
_BackgroundColor("BackgroundColor",Color)=(0,0,0,0)
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
//纹理中对应每个像素的大小;例如512*512的纹理,其值为1/512
float4 _MainTex_TexelSize;
//描边颜色
float4 _EdgeColor;
//背景颜色
float4 _BackgroundColor;
//背景颜色调节滑杆
float _EdgeWithOnly;
struct appdate
{
float4 vertex : POSITION;
float4 uv : TEXCOORD;
};
struct v2f
{
float4 pos : SV_POSITION;
//定义了某像素的纹理坐标以及其邻域的8个纹理坐标
float2 uv[9] : TEXCOORD;
};
v2f vert(appdate v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv[0]=v.uv+_MainTex_TexelSize*float2(-1,-1);
o.uv[1]=v.uv+_MainTex_TexelSize*float2(0,-1);
o.uv[2]=v.uv+_MainTex_TexelSize*float2(1,-1);
o.uv[3]=v.uv+_MainTex_TexelSize*float2(-1,0);
o.uv[4]=v.uv+_MainTex_TexelSize*float2(0,0);
o.uv[5]=v.uv+_MainTex_TexelSize*float2(1,0);
o.uv[6]=v.uv+_MainTex_TexelSize*float2(-1,1);
o.uv[7]=v.uv+_MainTex_TexelSize*float2(0,1);
o.uv[8]=v.uv+_MainTex_TexelSize*float2(1,1);
return o;
}
// 在线性颜色空间下的RGB 转为灰度值的心理学公式
fixed luminance(fixed4 color)
{
return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
// 应用Sobel卷积
half Sobel(v2f i)
{
const half Gx[9] = {-1, 0, 1,
-2, 0, 2,
-1, 0, 1};
const half Gy[9] = {-1, -2, -1,
0, 0, 0,
1, 2, 1};
half texColor;
half GradientX = 0;
half GradientY = 0;
for (int index = 0;index<9;index++)
{
texColor = luminance(tex2D(_MainTex,i.uv[index]));
GradientX += texColor * Gx[index];
GradientY += texColor * Gy[index];
}
half edge = 1-abs(GradientX)-abs(GradientY);
return edge; //edge越小 表明该像素越可能是边缘
}
float4 frag(v2f i):SV_Target
{
//Sobel函数利用Sobel算子对原图进行边缘检测
float edge = Sobel(i);
//既有原图也有边缘的颜色
float4 withEdgeColor=lerp(_EdgeColor,tex2D(_MainTex,i.uv[4]),edge);
//只有边缘和纯色的颜色
float4 OnlyEdgeColor=lerp(_EdgeColor,_BackgroundColor,edge);
//前两者的混合
return lerp(withEdgeColor,OnlyEdgeColor,_EdgeWithOnly);
}
ENDCG
}
}
}
三、效果展示
【太妃糖耶】更新啦,赶紧来围观吧!
详细知识解析见书 P246