**Unity Bloom的效果实现网上也有蛮多例子,但它们多数都是传承与高斯模糊,用一个限定的阀值,提取出屏幕上超过阀值亮度的像素,用卷积核运算对周围像素按照一定的比例差值颜色值叠加,这种实现方式性能可以,但在配合HDR实现发光效果其实并不理想,因为太粗鲁的将高亮度像素和它们的邻居卷起来叠加,会误伤了不少应该在较暗区域的像素,较暗区域被高亮度区域过度污染了。表现为如场景上几个招牌大字霓虹灯等,灯的轮廓和周围较暗的区域混在一起,过于浑浊,丢失了霓虹灯管本应清晰的轮廓。虽然大体上看上去还可以,但并不够真实可信。
因此,这里专用箱型模糊,此模糊算法在对获取高亮度像素时获取周围像素表现得更聚集,更适合在效果中体现出曝光物体轮廓,控制泛光范围。

原场景效果:

添加Bloom,依旧能看到清晰的霓虹灯轮廓,亮光区域控制的十分自然,亮光区域并没有过度入侵较暗区域造成一片糊:


用法:
1、将Bloom.cs挂到场景上Main Camera节点。
2、打开相机HDR和项目HDR设置。
Bloom.cs

using UnityEngine;
using System.Collections;[ExecuteInEditMode]
public class Bloom : MonoBehaviour
{private Material _bloomMaterial = null;public Material bloomMaterial{get{if (_bloomMaterial == null){_bloomMaterial = new Material(Shader.Find("Custom/MBloom"));}return _bloomMaterial;}}[Tooltip("要有发光效果必须开启")]public bool HDR = true;[Tooltip("颜色")]public Color BloomColor = Color.white;[Tooltip("发光强度")][Range(0, 100)]public float intensity = 1;[Tooltip("屏幕上的高光亮度阀值")][Range(0, 10)]public float threshold = 1;[Tooltip("光线过度柔和程度")][Range(0, 1)]public float softKnee = 0.5f;[Tooltip("散射程度")][Range(0, 20)]public float diffusion = 7;[Tooltip("方框模糊采样屏幕比值")][Range(1, 8)]public int downSample = 2;RenderTexture[] rtDowns;RenderTexture[] rtUps;private void Awake(){}public static float Exp2(float x){return Mathf.Exp(x * 0.69314718055994530941723212145818f);}void OnRenderImage(RenderTexture src, RenderTexture dest){if (bloomMaterial != null){bloomMaterial.SetColor("_Bloom_Color", BloomColor);//prefilteringfloat lt = Mathf.GammaToLinearSpace(threshold);float knee = lt * softKnee + 1e-5f;Vector4 threshold4 = new Vector4(lt, lt-knee, knee*2f, 0.25f/knee);bloomMaterial.SetVector("_Threshold", threshold4);float _intensity = Exp2(intensity/10f)-1f;bloomMaterial.SetFloat("_Intensity", _intensity);int rtW = src.width / downSample;int rtH = src.height / downSample;int s = Mathf.Max(rtH, rtW);float logs = Mathf.Log(s, 2f) + Mathf.Min(diffusion, 10f) - 10f;int logs_i = Mathf.FloorToInt(logs);int k_MaxPyramidSize = 16;int iterations = Mathf.Clamp(logs_i, 1, k_MaxPyramidSize);float sampleScale = 0.5f + logs - logs_i;bloomMaterial.SetFloat("_SampleScale", sampleScale);//sheet.properties.SetFloat(ShaderIDs.SampleScale, sampleScale);rtDowns = new RenderTexture[iterations];rtUps = new RenderTexture[iterations];RenderTextureFormat textureFormat = HDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default;for (int i = 0; i < iterations; i++){RenderTexture down = RenderTexture.GetTemporary(rtW, rtH, 0, textureFormat);down.filterMode = FilterMode.Bilinear;rtDowns[i] = down;RenderTexture up = RenderTexture.GetTemporary(rtW, rtH, 0, textureFormat);up.filterMode = FilterMode.Bilinear;rtUps[i] = up;if (i == 0){Graphics.Blit(src, rtDowns[i], bloomMaterial, 0);}else {Graphics.Blit(rtDowns[i-1], rtDowns[i],bloomMaterial, 1);}rtW = Mathf.Max(rtW/2, 1);rtH = Mathf.Max(rtH/2, 1);}RenderTexture lastup = rtDowns[iterations - 1];for (int i = iterations - 2; i >= 0; i--) {bloomMaterial.SetTexture("_BloomTex", rtDowns[i]);Graphics.Blit(lastup, rtUps[i], bloomMaterial, 2);lastup = rtUps[i];}bloomMaterial.SetTexture("_BloomTex", rtUps[0]);Graphics.Blit(src, dest, bloomMaterial, 3);foreach (RenderTexture rt in rtUps) {if(rt != null)RenderTexture.ReleaseTemporary(rt);}foreach (RenderTexture rt in rtDowns) {if(rt != null)RenderTexture.ReleaseTemporary(rt);}}else{Graphics.Blit(src, dest);}}
}

Bloom.shader

Shader "Custom/MBloom"
{Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{CGINCLUDE#define HALF_MAX        65504.0#define EPSILON         1.0e-4#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float4 uv : TEXCOORD0;};struct v2f{float4 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;sampler2D _BloomTex;float4 _BloomTex_ST;float4 _BloomTex_TexelSize;half3 _Bloom_Color;float4 _MainTex_ST;float4 _MainTex_TexelSize;float4 _Threshold;float _SampleScale;float _Intensity;float Max3(float a, float b, float c){return max(max(a, b), c);}// Standard box filteringhalf4 DownsampleBox4Tap(sampler2D tex, float2 uv, float2 texelSize){float4 d = texelSize.xyxy * float4(-1.0, -1.0, 1.0, 1.0);half4 s;s =  tex2D(tex,  uv + d.xy);s += tex2D(tex,  uv + d.zy);s += tex2D(tex,  uv + d.xw);s += tex2D(tex,  uv + d.zw);return s * (1.0 / 4.0);}// Standard box filteringhalf4 UpsampleBox(sampler2D tex, float2 uv, float2 texelSize, float4 sampleScale){float4 d = texelSize.xyxy * float4(-1.0, -1.0, 1.0, 1.0) * (sampleScale * 0.5);half4 s;s =  tex2D(tex,  uv + d.xy);s += tex2D(tex,  uv + d.zy);s += tex2D(tex,  uv + d.xw);s += tex2D(tex,  uv + d.zw);return s * (1.0 / 4.0);}//// Quadratic color thresholding// curve = (threshold - knee, knee * 2, 0.25 / knee)//half4 QuadraticThreshold(half4 color, half threshold, half3 curve){// Pixel brightnesshalf br = Max3(color.r, color.g, color.b);// Under-threshold part: quadratic curvehalf rq = clamp(br - curve.x, 0.0, curve.y);rq = curve.z * rq * rq;// Combine and apply the brightness response curve.color *= max(rq, br - threshold) / max(br, 1.0e-4);return color;}half4 Prefilter(half4 color){color = QuadraticThreshold(color, _Threshold.x, _Threshold.yzw);return color;}half4 farg_Prefilter(v2f i):SV_Target{half4 color = DownsampleBox4Tap(_MainTex, i.uv.xy, _MainTex_TexelSize.xy);return Prefilter(color);}v2f vert(appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);o.uv.zw = TRANSFORM_TEX(v.uv, _BloomTex);return o;}fixed4 frag_downsample(v2f i) : SV_Target{// sample the texturefixed4 col = DownsampleBox4Tap(_MainTex, i.uv.xy, _MainTex_TexelSize.xy);return col;}half4 frag_upsample(v2f i) : SV_Target{half4 color = UpsampleBox(_MainTex, i.uv.xy, _MainTex_TexelSize.xy, _SampleScale);half4 bloom = tex2D(_BloomTex, i.uv.zw);return color + bloom;}fixed4 frag(v2f i) : SV_Target {return tex2D(_MainTex, i.uv.xy) + tex2D(_BloomTex, i.uv.zw);} fixed4 frag_uber(v2f i) : SV_Target{half4 color = tex2D(_MainTex, i.uv.xy);half4 bloom = UpsampleBox(_BloomTex, i.uv.xy, _BloomTex_TexelSize.xy, _SampleScale);bloom *= _Intensity;color += bloom * half4(_Bloom_Color, 1.0);return color;}ENDCGZTest Always Cull Off ZWrite OffPass {CGPROGRAM  #pragma vertex vert  #pragma fragment farg_Prefilter ENDCG  }Pass {CGPROGRAM  #pragma vertex vert  #pragma fragment frag_downsampleENDCG  }Pass {CGPROGRAM  #pragma vertex vert  #pragma fragment frag_upsampleENDCG  }Pass {CGPROGRAM  #pragma vertex vert#pragma fragment frag_uberENDCG  }Pass {CGPROGRAM  #pragma vertex vert  #pragma fragment fragENDCG  }}
}

Unity Bloom更可信的实现相关推荐

  1. 为何有些云比其他云更可信

    (本文原文为英文"Why and how some cloud can be more trustworthy than the other",作者于2010年10月29日发表于E ...

  2. 深度学习面临天花板,亟需更可信、可靠、安全的第三代AI技术|AI ProCon 2019

    整理 | 夕颜 出品 | AI科技大本营(ID:rgznai100) 在人工智能领域中,深度学习掀起了最近一次浪潮,但在实践和应用中也面临着诸多挑战,特别是关系到人的生命,如医疗.自动驾驶等领域场景时 ...

  3. Java和U3D比较,Unity热更方案 ILRuntime 和 toLua的比较

    前言 目前市面上流行的热更方案就是lua系列和ILRuntime,选取哪一种需要根据自己的项目进行比对. 无论是ILRuntime还是toLua都是市面上有在用到的热更方案.直观上来讲,都可以通过把代 ...

  4. 开源公告|更可信的人脸识别,腾讯优图TFace正式开源!

    继神经网络推理框架 ncnn.TNN,动作检测算法 DBG,通用目标检测算法 OSD,人脸检测算法 DSFD.人脸属性算法 FAN等众多优秀的框架.算法开源后,腾讯优图实验室又有一项人脸识别算法研究项 ...

  5. 腾讯优图TFace正式开源,更可信的人脸识别!

    本文转载自腾讯开源 继神经网络推理框架 ncnn.TNN,动作检测算法 DBG,通用目标检测算法 OSD,人脸检测算法 DSFD.人脸属性算法 FAN等众多优秀的框架.算法开源后,腾讯优图实验室又有一 ...

  6. 在unity中更改天空盒的几种方式

    我们先来讲一下,怎么样自制一个天空盒吧,其实很简单,先创建一个material,取好名字,然后更改属性为Skybox/6 Sided,并且把六个面的图片都选好,如下图: 注意图片在太空盒的位置啊~~天 ...

  7. luajit集成篇/平台相关篇 | 合理用好lua+unity,更省性能的方案整理

    luajit集成篇 大家都知道luajit比原生lua快,快在jit这三个字上. 但实际情况是,luajit的行为十分复杂.尤其jit并不是一个简单的把代码翻译成机器码的机制,背后有很多会影响性能的因 ...

  8. lua与c#交互篇 | 合理用好lua+unity,更省性能的方案整理

    前言 在看了uwa之前发布的<Unity项目常见Lua解决方案性能比较>,决定动手写一篇关于lua+unity方案的性能优化文. 整合lua是目前最强大的unity热更新方案,毕竟这是唯一 ...

  9. [Unity 架构] 更好的 Unity 游戏架构

    英文原文:https://thegamedev.guru/unity-architecture/a-better-architecture-for-unity-projects/   在使用 Unit ...

最新文章

  1. jpg怎么合成一份_哪些超实用的有机化学知识点---之有机合成工具包
  2. PHP获取今天开始和结束的时间戳
  3. 查看显卡显存_显卡显存越大性能就越好吗【详细介绍】
  4. 【文文殿下】快速傅里叶变换(FFT)学习笔记
  5. 读ACM程序设计竞赛基础教程之-------技巧小结
  6. 神策 2021 数据驱动大会丨北京主会场首日直播,拼团早鸟票特惠来袭
  7. pycharm matplotlib 图片显示
  8. [Silverlight入门系列]使用MVVM模式(7):ViewModel的INotifyPropertyChanged接口实现
  9. win8f8修复计算机,Win8怎么在启动时按F8出现修复计算机选项
  10. python与机器视觉(X)打包为exe可执行文件
  11. 解题:ZJOI 2006 书架
  12. 一招教你在linux服务器配置Jenkins持续集成神器
  13. Invest模型中HAbitat quality(生境质量)的计算过程
  14. SQL 2008 r2(MSSQLSERVER)服务启动错误代码3414
  15. 个人计算机组装主板,电脑主板安装详细图解 可以自己组装电脑了
  16. pr如何处理音效,如何让你的声音变得干净又清晰?PR音频降噪教程
  17. 063.django之模板层
  18. 编译原理基本概念和术语
  19. 台式计算机最新配置,例举2019推荐组装台式电脑最新配置清单
  20. 【钉钉-场景化能力包】自有OA审批助力费控报销

热门文章

  1. ENA查询SRA并获取相关信息
  2. 踩坑记:水墨屏无线标签卡不能用于工业
  3. 全球首架国产C919正式交付东航;无锡多宁生产基地投产 | 美通企业日报
  4. parseInt的用法
  5. Conda及常用生信软件安装
  6. python语言的特点有没有面向过程_Python语言的特点有哪些?
  7. ZYNQ -Lwip和TCP/IP简介
  8. 2022-11-28关键词扩充,文章自动生成,采集php源码,自动配图源码,SEO提高收录权重无限长尾词
  9. 计算机保研面试经验分享—西北工业大学
  10. echarts 地图类型热力图