Files
Main/Assets/Launcher/ExternalLibs/CmdBuffer/OpaqueBloom/OpaqueBloom.cs
2025-01-25 04:38:09 +08:00

256 lines
8.8 KiB
C#

using Thousandto.Launcher.ExternalLibs;
using UnityEngine;
using UnityEngine.Rendering;
namespace Thousandto.Launcher.ExternalLibs
{
/// <summary>
/// 不透明对象的曝光处理.
/// 描述: 利用渲染图片的alpha通道,来判断哪些需要曝光哪些不需要,这个只针对不透明的对象(Opaque).
/// </summary>
public class OpaqueBloom
{
//命令缓存
private CommandBuffer _processCmds;
//当前挂载的摄像机
private Camera _camera;
//材质球
private Material _mat;
//触发事件2
private CameraEvent _triggerEvent = CameraEvent.BeforeImageEffects;
//参数:x,y表示偏移处理,z:表示曝光强度
private Vector4 _Params = Vector4.zero;
//阈值相关:x:threshold,y:threshold-knee,z:knee*2,w:1/(knee*4)
private Vector4 _Threshold = Vector4.zero;
private bool _isInited = false;
//是否可用
private bool _enabled = true;
public bool Enabled
{
get
{
return _enabled;
}
set
{
if (_enabled != value)
{
_enabled = value && SystemInfo.supportsImageEffects;
}
}
}
public bool IsInited
{
get
{
return _isInited;
}
}
//初始化
public void Initialize()
{
if (!_isInited)
{
//判断是否支持
_enabled = _enabled && SystemInfo.supportsImageEffects;
InitMat();
Debug.Log("Initialize:" + _enabled + ";;;SystemInfo.supportsImageEffects:" + SystemInfo.supportsImageEffects + ";;(_mat != null):" + (_mat != null).ToString());
if (_mat != null)
{
InitCmd();
_isInited = true;
}
}
}
//反初始化
public void UnInitialize()
{
if (_processCmds != null)
{
if (_camera != null)
{
_camera.RemoveCommandBuffer(_triggerEvent, _processCmds);
}
_processCmds.Release();
_processCmds = null;
}
if (_mat != null)
{
GameObject.Destroy(_mat);
_mat = null;
}
}
//绑定摄像机
public void BindCamera(Camera cam)
{
if (_processCmds != null)
{
if (_camera != null)
{
_camera.forceIntoRenderTexture = false;
_camera.RemoveCommandBuffer(_triggerEvent, _processCmds);
}
if (cam != null && Enabled)
{
cam.forceIntoRenderTexture = true;
cam.AddCommandBuffer(_triggerEvent, _processCmds);
}
}
_camera = cam;
}
//设置偏移和强度
public void SetOffsetAndStrength(Vector2 offset, float strength)
{
_Params = new Vector4(offset.x, offset.y, strength);
RefreshMat();
}
//设置阈值
public void SeThreshold(float threshold, float knee)
{
_Threshold = new Vector4(threshold, threshold - knee, knee * 2, 1 / ((knee + 0.0001f) * 4));
RefreshMat();
}
//刷新材质球
public void RefreshMat()
{
if (_mat != null)
{
_mat.SetVector("_Params", _Params);
_mat.SetVector("_Threshold", _Threshold);
}
}
//初始化渲染命令
private void InitCmd()
{
var mainTexID = CmdBufferUtils.MainTexID;
var bloomTexID = Shader.PropertyToID("_BloomTex");
if (_processCmds == null)
{
_processCmds = new CommandBuffer();
_processCmds.name = "OpaqueBloomCmd";
//准备
_processCmds.GetTemporaryRT(CmdBufferUtils.FullScreenTexID, -1,-1, 0, FilterMode.Bilinear);
int tw = Screen.width / 2;
int th = Screen.height / 2;
int iterations = Mathf.Clamp(Mathf.FloorToInt(Mathf.Log(Mathf.Max(tw, th), 2)), 1, 3);
int[] dids = new int[iterations];
int[] uids = new int[iterations];
for (int i = 0; i < iterations; i++)
{
dids[i] = (Shader.PropertyToID("_CameraBloomEffectTexD" + i));
uids[i] = (Shader.PropertyToID("_CameraBloomEffectTexU" + i));
_processCmds.GetTemporaryRT(dids[i], tw, th, 0, FilterMode.Bilinear);
_processCmds.GetTemporaryRT(uids[i], tw, th, 0, FilterMode.Bilinear);
tw = tw / 2;
th = th / 2;
}
//0.摄像机的数据读取出来
_processCmds.SetRenderTarget(CmdBufferUtils.FullScreenTexID);
_processCmds.SetGlobalTexture(mainTexID, BuiltinRenderTextureType.CameraTarget);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 3);
//1.过滤一下
_processCmds.SetRenderTarget(dids[0]);
_processCmds.SetGlobalTexture(mainTexID, CmdBufferUtils.FullScreenTexID);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 0);
//2.进行采样处理
for (int i = 0; i < iterations; i++)
{
//2.1 处理行
_processCmds.SetRenderTarget(uids[i]);
_processCmds.SetGlobalTexture(mainTexID, dids[0]);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 1);
//2.2 处理列
_processCmds.SetRenderTarget(dids[i]);
_processCmds.SetGlobalTexture(mainTexID, uids[i]);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 2);
}
//4.先把最后一个复制了
_processCmds.SetRenderTarget(uids[iterations - 1]);
_processCmds.SetGlobalTexture(mainTexID, dids[iterations - 1]);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 3);
//5.把bloom纹理给组合起来
for (int i = iterations - 2; i >= 0; i--)
{
_processCmds.SetRenderTarget(uids[i]);
_processCmds.SetGlobalTexture(mainTexID, uids[i + 1]);
_processCmds.SetGlobalTexture(bloomTexID, dids[i]);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 4);
}
//6.把bloom纹理与显示帧的数据给组合起来
_processCmds.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
_processCmds.SetGlobalTexture(mainTexID, CmdBufferUtils.FullScreenTexID);
_processCmds.SetGlobalTexture(bloomTexID, uids[0]);
_processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 4);
_processCmds.SetRenderTarget(uids[0]);
//7.释放RT资源
for (int i = 0; i < iterations; i++)
{
_processCmds.ReleaseTemporaryRT(dids[i]);
_processCmds.ReleaseTemporaryRT(uids[i]);
}
_processCmds.ReleaseTemporaryRT(CmdBufferUtils.FullScreenTexID);
if (_camera != null && Enabled)
{
_camera.forceIntoRenderTexture = true;
_camera.AddCommandBuffer(_triggerEvent, _processCmds);
}
}
}
//初始化材质球
private void InitMat()
{
if (_mat == null)
{
var sh = RuntimeUtilities.FindShader("Hidden/Ares/PostEffect/BloomCmd");
if (sh != null)
{
_mat = new Material(sh);
_mat.hideFlags = HideFlags.DontSave;
//初始化材质球
SetOffsetAndStrength(new Vector2(4, 4), 1.5f);
SeThreshold(0.9f, 0.5f);
RefreshMat();
}
else
{
Debug.LogError("没有找到Shader:Hidden/Ares/PostEffect/BloomCmd,OpaqueBloom无效!");
}
}
}
}
}