// author : Saber
|
|
// date : 2020/12/8
|
|
// desc : 将当前项目中的后处理集中处理
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using System;
|
|
using LuaInterface;
|
|
using UnityStandardAssets.ImageEffects;
|
|
public enum Resolution
|
|
{
|
|
Low = 0,
|
|
High = 1,
|
|
}
|
|
|
|
public enum BlurType
|
|
{
|
|
Standard = 0,
|
|
Sgx = 1,
|
|
}
|
|
|
|
// [ExecuteInEditMode, ImageEffectAllowedInSceneView]
|
|
[RequireComponent (typeof(Camera))]
|
|
public class PostEffect : PostEffectsBase
|
|
{
|
|
|
|
#region FXAA参数
|
|
public bool EnableFXAA = false; // FXAA总开关
|
|
const int fxaaPass = 1;
|
|
[Range(0.0312f, 0.0833f)]
|
|
public float contrastThreshold = 0.0312f;
|
|
[Range(0.063f, 0.333f)]
|
|
public float relativeThreshold = 0.063f;
|
|
[Range(0f, 1f)]
|
|
public float subpixelBlending = 1f;
|
|
public Shader FXAAShader;
|
|
public bool lowQuality;
|
|
Material fxaaMaterial;
|
|
#endregion
|
|
|
|
#region bloom效果参数
|
|
public bool EnableBloom = false;
|
|
[Range(0.0f, 1.5f)]
|
|
public float threshold = 0.47f;
|
|
[Range(0.0f, 3f)]
|
|
public float intensity = 0.75f;
|
|
[Range(0.25f, 5.5f)]
|
|
public float blurSize = 0.46f;
|
|
int bloomDowmSample = 1;
|
|
float bloomBlurAmount = 0.5f;
|
|
int passOffset = 0;
|
|
Resolution resolution = Resolution.Low;
|
|
[Range(1, 4)]
|
|
public int blurIterations = 1;
|
|
public BlurType blurType= BlurType.Standard;
|
|
public Shader fastBloomShader = null;
|
|
public Shader dualBloomShader = null;
|
|
private Material fastBloomMaterial = null;
|
|
private Material dualBloomMaterial = null;
|
|
public bool use_dual_bloom = false;
|
|
|
|
const int DUAL_BLOOM_RENDER_PASS = 0;
|
|
const int DUAL_BLOOM_DOWNSAMPLE_PASS = 1;
|
|
const int DUAL_BLOOM_UPSAMPLE_PASS = 2;
|
|
const int DUAL_BLOOM_LUMINACE_PASS = 3;
|
|
#endregion
|
|
|
|
#region 高斯模糊/双重模糊后处理效果参数
|
|
public bool EnableBlur = false;
|
|
public bool use_dual_blur = false; // 使用双面模糊
|
|
|
|
#region 高斯模糊相关参数
|
|
const int BLUR_PASS_HOR = 0; // 水平模糊pass
|
|
const int BLUR_PASS_VER = 1; // 垂直模糊pass
|
|
public Shader blurShader; // 高斯模糊shader
|
|
Material blurMaterial; // 高速模糊材质
|
|
[HideInInspector]
|
|
public bool render_blur_effect = false; // 高斯模糊关键参数,设置为true时会开始渲染高斯模糊纹理
|
|
public bool get_screen_shot = false; // 与上面的功能区分,只截图,并不会改变原先的渲染
|
|
// 高斯模糊缓存纹理(不要在渲染时动态创建,会消耗很多内存,这里先生成引用)
|
|
public float blurSpread = 0.4f; // 模糊散值
|
|
public float blur_amount = 1f; // 模糊插值,0:初始效果,1:完全模糊效果
|
|
private int recurveNum = 1; // 当前迭代的渲染次数
|
|
public int recurveMaxNum = 1; // 最大迭代渲染次数
|
|
public int downSample = 4; // 降低采样率比率(降低采样率可以提高性能,但肯定会让效果变差)
|
|
LuaFunction screenshot_callback; // 模糊截图回调
|
|
#endregion
|
|
|
|
#region 双面模糊相关参数
|
|
const int DOWN_SAMPLE_PASS = 0; // 降采样pass
|
|
const int UP_SAMPLE_PASS = 1; // 升采样pass
|
|
public Shader dualBlurShader; // 双面模糊shader
|
|
Material dual_blur_mat; // 双面模糊材质球
|
|
RenderTextureFormat format;
|
|
#endregion
|
|
#endregion
|
|
private RenderTexture final_renderTexture; // 最终渲染出来的画面RT缓存
|
|
private RenderTexture temp_rt1;
|
|
private RenderTexture temp_rt2;
|
|
private bool final_rt_rendered = false; // 最终画面是否被渲染到了
|
|
|
|
// 检查资源
|
|
public bool GetSupported()
|
|
{
|
|
return CheckSupport(false);
|
|
}
|
|
public override bool CheckResources()
|
|
{
|
|
CheckSupport (false);
|
|
|
|
if (!isSupported){
|
|
ReportAutoDisable ();
|
|
return isSupported;
|
|
}
|
|
|
|
// 创建对应shader的材质球
|
|
fxaaMaterial = CheckShaderAndCreateMaterial (FXAAShader, fxaaMaterial); // FXAA效果
|
|
fastBloomMaterial = CheckShaderAndCreateMaterial (fastBloomShader, fastBloomMaterial); // Bloom效果(高斯模糊)
|
|
dualBloomMaterial = CheckShaderAndCreateMaterial (dualBloomShader, dualBloomMaterial); // Bloom效果(双重模糊)
|
|
blurMaterial = CheckShaderAndCreateMaterial (blurShader, blurMaterial); // 高斯模糊效果
|
|
dual_blur_mat = CheckShaderAndCreateMaterial (dualBlurShader, dual_blur_mat); // 双面模糊效果
|
|
|
|
return isSupported;
|
|
}
|
|
|
|
// 非迭代的material参数修改,统一做成接口调用以一次性修改,而不要在渲染逻辑内重复执行
|
|
// FXAA属性值应用
|
|
public void ApplyFXAAMaterialProperties()
|
|
{
|
|
if (fxaaMaterial != null)
|
|
{
|
|
fxaaMaterial.SetFloat("_ContrastThreshold", contrastThreshold);
|
|
fxaaMaterial.SetFloat("_RelativeThreshold", relativeThreshold);
|
|
fxaaMaterial.SetFloat("_SubpixelBlending", subpixelBlending);
|
|
|
|
if (lowQuality) {
|
|
fxaaMaterial.EnableKeyword("LOW_QUALITY");
|
|
}
|
|
else {
|
|
fxaaMaterial.DisableKeyword("LOW_QUALITY");
|
|
}
|
|
}
|
|
}
|
|
// Bloom泛光属性值应用
|
|
public void ApplyBloomMaterialProperties()
|
|
{
|
|
bloomDowmSample = resolution == Resolution.Low ? 4 : 2;
|
|
bloomBlurAmount = resolution == Resolution.Low ? 0.5f : 1.0f;
|
|
passOffset = blurType == BlurType.Standard ? 0 : 2;
|
|
|
|
// 双面模糊的参数直接设置
|
|
if (dualBloomMaterial)
|
|
{
|
|
dualBloomMaterial.SetFloat("_Threshold", threshold);
|
|
dualBloomMaterial.SetFloat("_Intensity", intensity);
|
|
}
|
|
}
|
|
|
|
// 高斯/双面模糊属性值应用
|
|
public void ApplyBlurMaterialProperties()
|
|
{
|
|
|
|
}
|
|
|
|
// 根据当前的项目渲染顺序,预设的渲染顺序分别是 Bloom泛光效果 -> FXAA抗锯齿效果 -> 模糊效果(采集模糊背景用,很少用于即时渲染)
|
|
// 将所有的效果整合成OnRenderImage中处理,不拆分,尽可能减少Graphics.Blit次数
|
|
void OnRenderImage(RenderTexture src, RenderTexture dest)
|
|
{
|
|
if (isSupported) // 支持后处理
|
|
{
|
|
final_rt_rendered = false;
|
|
final_renderTexture = RenderTexture.GetTemporary(src.width, src.height, 0, src.format);
|
|
format = src.format;
|
|
// 1.处理Bloom泛光效果
|
|
if (EnableBloom && fastBloomMaterial != null && dualBloomMaterial != null)
|
|
{
|
|
// 使用双面模糊算法来处理模糊部分
|
|
if(use_dual_bloom)
|
|
{
|
|
int width = src.width;
|
|
int height = src.height;
|
|
// 根据亮度阈值获取亮度图
|
|
temp_rt1 = RenderTexture.GetTemporary(width / bloomDowmSample, height / bloomDowmSample, 0, format);
|
|
temp_rt2 = RenderTexture.GetTemporary(width / bloomDowmSample, height / bloomDowmSample, 0, format);
|
|
Graphics.Blit(src, temp_rt1, dualBloomMaterial, DUAL_BLOOM_LUMINACE_PASS);
|
|
for(int i = 0; i < blurIterations; i++)
|
|
{
|
|
dualBloomMaterial.SetFloat("_Offset", (1.0f + i * blurSize) * bloomBlurAmount); // 设置模糊扩散uv偏移
|
|
// 降采样渲染
|
|
Graphics.Blit(temp_rt1, temp_rt2, dualBloomMaterial, DUAL_BLOOM_DOWNSAMPLE_PASS);
|
|
// 升采样渲染
|
|
Graphics.Blit(temp_rt2, temp_rt1, dualBloomMaterial, DUAL_BLOOM_UPSAMPLE_PASS);
|
|
}
|
|
dualBloomMaterial.SetTexture("_Bloom", temp_rt1);
|
|
}
|
|
// 使用高斯模糊算法处理模糊部分
|
|
else
|
|
{
|
|
fastBloomMaterial.SetVector("_Parameter", new Vector4 (blurSize * bloomBlurAmount, 0.0f, threshold, intensity));
|
|
// src.filterMode = FilterMode.Bilinear;
|
|
int rtW = src.width / bloomDowmSample;
|
|
int rtH = src.height / bloomDowmSample;
|
|
// downsample
|
|
temp_rt1 = RenderTexture.GetTemporary(rtW, rtH, 0, format);
|
|
temp_rt2 = RenderTexture.GetTemporary(rtW, rtH, 0, format);
|
|
// temp_rt1.filterMode = FilterMode.Bilinear;
|
|
// temp_rt2.filterMode = FilterMode.Bilinear;
|
|
Graphics.Blit(src, temp_rt1, fastBloomMaterial, 1);
|
|
|
|
for(int i = 0; i < blurIterations; i++)
|
|
{
|
|
fastBloomMaterial.SetVector("_Parameter", new Vector4 (blurSize * bloomBlurAmount + (i*1.0f), 0.0f, threshold, intensity));
|
|
// vertical blur
|
|
Graphics.Blit(temp_rt1, temp_rt2, fastBloomMaterial, 2 + passOffset);
|
|
Graphics.Blit(temp_rt2, temp_rt1, fastBloomMaterial, 3 + passOffset);
|
|
}
|
|
fastBloomMaterial.SetTexture("_Bloom", temp_rt1);
|
|
}
|
|
ReleaseTemporary(temp_rt2);
|
|
|
|
// 这边就判断是否使用FXAA
|
|
if (EnableFXAA && fxaaMaterial != null)
|
|
{
|
|
temp_rt2 = RenderTexture.GetTemporary(src.width, src.height, 0, format);
|
|
if(use_dual_bloom) // 使用双面模糊算法来处理合并部分
|
|
{
|
|
Graphics.Blit(src, temp_rt2, dualBloomMaterial, DUAL_BLOOM_RENDER_PASS);
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(src, temp_rt2, fastBloomMaterial, 0);
|
|
}
|
|
|
|
Graphics.Blit(temp_rt2, final_renderTexture, fxaaMaterial, fxaaPass);
|
|
ReleaseTemporary(temp_rt2);
|
|
}
|
|
else
|
|
{
|
|
if(use_dual_bloom) // 使用双面模糊算法来处理合并部分
|
|
{
|
|
Graphics.Blit(src, final_renderTexture, dualBloomMaterial, DUAL_BLOOM_RENDER_PASS);
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(src, final_renderTexture, fastBloomMaterial, 0);
|
|
}
|
|
}
|
|
final_rt_rendered = true;
|
|
//source.filterMode = FilterMode.Point;
|
|
ReleaseTemporary(temp_rt1);
|
|
}
|
|
else
|
|
{
|
|
// 当不适用Bloom的情况,处理FXAA抗锯齿效果
|
|
if (EnableFXAA && fxaaMaterial != null)
|
|
{
|
|
Graphics.Blit(src, final_renderTexture, fxaaMaterial, fxaaPass);
|
|
final_rt_rendered = true;
|
|
}
|
|
}
|
|
// 3.处理模糊需求
|
|
if (EnableBlur && blurMaterial != null && dual_blur_mat != null && (render_blur_effect || get_screen_shot))
|
|
{
|
|
// 使用双面模糊算法
|
|
if(use_dual_blur){
|
|
int width = src.width;
|
|
int height = src.height;
|
|
recurveNum = 1; // 初始化迭代
|
|
// RT初始化
|
|
temp_rt1 = RenderTexture.GetTemporary(width / downSample, height / downSample, 0, format);
|
|
|
|
if(get_screen_shot && !render_blur_effect) // 当只是渲染截图,就使用临时rt2
|
|
temp_rt2 = RenderTexture.GetTemporary(width / downSample, height / downSample, 0, format);
|
|
|
|
while(recurveNum <= recurveMaxNum)
|
|
{
|
|
dual_blur_mat.SetFloat("_Offset", (1.0f + recurveNum * blurSpread) * blur_amount); // 设置模糊扩散uv偏移
|
|
if (get_screen_shot && !render_blur_effect) // 只渲染截屏
|
|
{
|
|
// 降采样渲染
|
|
if(recurveNum == 1 && !final_rt_rendered) // 当首次降采样且最终RT没有处理过,就使用源RT
|
|
Graphics.Blit(src, temp_rt1, dual_blur_mat, DOWN_SAMPLE_PASS);
|
|
else
|
|
Graphics.Blit(temp_rt2, temp_rt1, dual_blur_mat, DOWN_SAMPLE_PASS);
|
|
|
|
// 升采样渲染
|
|
// 使用temp_rt2,不要影响最终画面
|
|
Graphics.Blit(temp_rt1, temp_rt2, dual_blur_mat, UP_SAMPLE_PASS);
|
|
}
|
|
else // 需要实时模糊
|
|
{
|
|
// 降采样渲染
|
|
if(recurveNum == 1 && !final_rt_rendered) // 当首次降采样且最终RT没有处理过,就使用源RT
|
|
Graphics.Blit(src, temp_rt1, dual_blur_mat, DOWN_SAMPLE_PASS);
|
|
else
|
|
Graphics.Blit(final_renderTexture, temp_rt1, dual_blur_mat, DOWN_SAMPLE_PASS);
|
|
|
|
// 升采样渲染,输出模糊的final_renderTexture
|
|
Graphics.Blit(temp_rt1, final_renderTexture, dual_blur_mat, UP_SAMPLE_PASS);
|
|
}
|
|
|
|
recurveNum ++;
|
|
}
|
|
RenderTexture.ReleaseTemporary(temp_rt1); // 释放临时RT
|
|
// 仅当使用持续模糊渲染才会置为true,否则由之前的效果来决定
|
|
final_rt_rendered = final_rt_rendered || render_blur_effect;
|
|
}
|
|
else
|
|
{
|
|
recurveNum = 1;
|
|
//缩小要模糊的图片,减少处理压力
|
|
int width = src.width / downSample;
|
|
int height = src.height / downSample;
|
|
// 由于高斯模糊需要将最终纹理降采样,所以这边做一个标志量
|
|
// 如果经过了上面的处理后还需要高斯模糊处理,则需要在迭代渲染过程中进行一次降采样缓存
|
|
bool need_redownSample = true;
|
|
|
|
if(get_screen_shot && !render_blur_effect) // 当只是渲染截图,就使用临时rt2
|
|
{
|
|
temp_rt2 = RenderTexture.GetTemporary(width, height, 0, format);
|
|
Graphics.Blit(src, temp_rt2);
|
|
need_redownSample = false;
|
|
}
|
|
else
|
|
{
|
|
if(!final_rt_rendered)
|
|
{
|
|
// 这边如果原RT未采样也要释放缓存,不然直接获取缓存会存在泄露问题
|
|
ReleaseTemporary(final_renderTexture);
|
|
final_renderTexture = RenderTexture.GetTemporary(width, height, 0);
|
|
// final_renderTexture.filterMode = FilterMode.Bilinear;
|
|
Graphics.Blit(src, final_renderTexture);
|
|
|
|
need_redownSample = false;
|
|
}
|
|
}
|
|
|
|
temp_rt1 = RenderTexture.GetTemporary(width, height, 0);
|
|
while(recurveNum <= recurveMaxNum){
|
|
recurveNum ++;
|
|
blurMaterial.SetFloat("_BlurSize", (1.0f + recurveNum * blurSpread) * blur_amount);
|
|
|
|
if(get_screen_shot && !render_blur_effect)
|
|
{
|
|
Graphics.Blit(temp_rt2, temp_rt1, blurMaterial, BLUR_PASS_HOR);
|
|
if(need_redownSample)
|
|
{
|
|
temp_rt2 = RenderTexture.GetTemporary(width, height, 0, format);
|
|
need_redownSample = false;
|
|
}
|
|
Graphics.Blit(temp_rt1, temp_rt2, blurMaterial, BLUR_PASS_VER);
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(final_renderTexture, temp_rt1, blurMaterial, BLUR_PASS_HOR);
|
|
if(need_redownSample)
|
|
{
|
|
ReleaseTemporary(final_renderTexture);
|
|
final_renderTexture = RenderTexture.GetTemporary(width, height, 0);
|
|
need_redownSample = false;
|
|
}
|
|
Graphics.Blit(temp_rt1, final_renderTexture, blurMaterial, BLUR_PASS_VER);
|
|
}
|
|
}
|
|
RenderTexture.ReleaseTemporary(temp_rt1);
|
|
// 仅当使用持续模糊渲染才会置为true,否则由之前的效果来决定
|
|
final_rt_rendered = final_rt_rendered || render_blur_effect;
|
|
}
|
|
}
|
|
if(get_screen_shot && !render_blur_effect){
|
|
GetBlurScreenShot();
|
|
get_screen_shot = false; // 截图生成之后就停止运作
|
|
}
|
|
if(final_rt_rendered)
|
|
{
|
|
Graphics.Blit(final_renderTexture, dest);
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(src, dest);
|
|
}
|
|
RenderTexture.ReleaseTemporary(final_renderTexture);
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(src, dest); // 不支持后处理,则直接输出最终画面
|
|
}
|
|
}
|
|
|
|
// 设置开始处理模糊效果的截图
|
|
public void RenderBlurScreenShot(float blur_amount, int downSample, LuaFunction func)
|
|
{
|
|
get_screen_shot = true;
|
|
this.blur_amount = blur_amount;
|
|
this.downSample = downSample;
|
|
screenshot_callback = func;
|
|
}
|
|
void GetBlurScreenShot()
|
|
{
|
|
// RenderTexture temp_screen_shot = RenderTexture.GetTemporary(final_renderTexture.width, final_renderTexture.height, 0);
|
|
// Graphics.Blit(final_renderTexture, temp_screen_shot);
|
|
RenderTexture temp_screen_shot = RenderTexture.GetTemporary(temp_rt2.width, temp_rt2.height, 0);
|
|
Graphics.Blit(temp_rt2, temp_screen_shot);
|
|
if (screenshot_callback != null)
|
|
{
|
|
List<UnityEngine.Object> list = new List<UnityEngine.Object>();
|
|
list.Add(temp_screen_shot);
|
|
object[] args = new object[] { list.ToArray() };
|
|
screenshot_callback.Call(args);
|
|
screenshot_callback.Dispose();
|
|
screenshot_callback = null;
|
|
}
|
|
// 释放掉临时RT2
|
|
ReleaseTemporary(temp_rt2);
|
|
}
|
|
// 销毁渲染纹理缓存
|
|
public void ReleaseRenderTexCache()
|
|
{
|
|
if (!render_blur_effect) {
|
|
ReleaseTemporary(final_renderTexture);
|
|
}
|
|
}
|
|
void ReleaseTemporary(RenderTexture rt)
|
|
{
|
|
if (rt != null)
|
|
{
|
|
RenderTexture.ReleaseTemporary(rt);
|
|
}
|
|
}
|
|
void OnDisable()
|
|
{
|
|
// // 销毁已有的材质球
|
|
// if (fastBloomMaterial)
|
|
// DestroyImmediate (fastBloomMaterial);
|
|
// if (dualBloomMaterial)
|
|
// DestroyImmediate (dualBloomMaterial);
|
|
// if (fxaaMaterial)
|
|
// DestroyImmediate (fxaaMaterial);
|
|
// if (blurMaterial)
|
|
// DestroyImmediate (blurMaterial);
|
|
// if (dual_blur_mat)
|
|
// DestroyImmediate (dual_blur_mat);
|
|
|
|
// ReleaseTemporary(final_renderTexture);
|
|
// ReleaseTemporary(temp_rt1);
|
|
// ReleaseTemporary(temp_rt2);
|
|
}
|
|
}
|