Unity3d HDR和Bloom效果(高动态范围图像和泛光)

文章开始先放两组效果,文章结尾再放两组效果

本文测试场景资源来自浅墨大神,shader效果为本文效果

HDR

人们有限的视觉系统,只支持16.7百万的颜色,超出这个范围的颜色就不能显示了

bmp或jprg每个像素就是16,24或32位

每个像素都由红绿蓝构成,如果储存为24位,每个值的范围就在0,255之间,

只能表现出256:1的差别,unity的shader中是0到1

然而在自然中太阳光下的对比度是50000:1

HDR(High Dynamic Range)使图像能表现出更大范围的对比,普通的范围就叫LDR(Low Dynamic Range)

你在照相的时候能控制曝光时间从而控制亮度。

HDR效果就是可控的曝光,

色调映射 tone-mapping

传统的显示设备不能完全的显示出HDR,所以我们用tone-mapping技术。

tone-mapping让图像从HDR映射为LDR显示

http://www.ownself.org/blog/2011/tone-mapping.html中的解释很好

Tone Mapping原是摄影学中的一个术语,因为打印相片所能表现的亮度范围不足以表现现实世界中的亮度域,而如果简单的将真实世界的整个亮度域线性压缩到照片所能表现的亮度域内,则会在明暗两端同时丢失很多细节,这显然不是所希望的效果,Tone Mapping就是为了克服这一情况而存在的,既然相片所能呈现的亮度域有限则我们可以根据所拍摄场景内的整体亮度通过光圈与曝光时间的长短来控制一个合适的亮度域,这样既保证细节不丢失,也可以不使照片失真。人的眼睛也是相同的原理,这就是为什么当我们从一个明亮的环境突然到一个黑暗的环境时,可以从什么都看不见到慢慢可以适应周围的亮度,所不同的是人眼是通过瞳孔来调节亮度域的。

一个tone-mapping的公式

Middlegrey为全屏幕或部分屏幕的中间灰度,可以控值屏幕的亮度

AvgLogLuminance就是全屏幕或部分屏幕的亮度的对数的平均值

AvgLogLuminance的公式

Lw是亮度,n是所取亮度数

这个操作能让L值限制位[0,1)

一些tone-mapping操作用exposure或gamma作为参数控制最终的图像。

tone-mapping是非线性的,他对暗色保有一定范围并且对亮色逐步接近动态

这个技术产生吸引人的视觉效果,有着强烈的对比和细节。

HDR Rendering In OpenGL一文中给出简要且效果不错的公式

关键代码如下

			float4 frag(v2f i) :COLOR
			{
				float4 c = tex2D(_MainTex, i.uv_MainTex);
				float y = dot(float4(0.3,0.59,0.11,1),c);
				float yd = _Exp * (_Exp / _BM + 1) / (_Exp + 1);
				return c*yd;
			}

_Exp,_BM为外部可控变量

HDR流程如下

如果分不清HDR与加亮light,可以看看skybox,加亮light是不会加亮skybox的,HDR使颜色更鲜明,像素更清晰。

Bloom泛光

辉光的原因是由于人眼晶状体的散射

我们制造bloom的原理是把图像的亮的部分通过卷积模糊再叠加到原图像上,就产生了bloom效果。

高斯模糊的滤波器是一种低通滤波器

就是去当前像素和周围的像素按一定权重混合,产生一定模糊效果

权重分布如下,离当前像素越远,权重越低

高斯正态分布曲线

二维公式

可以通过这个公式直接算出权重

    double sigma = (double)radius / 3.0;
    double sigma2 = 2.0 * sigma * sigma;
    double sigmap = sigma2 * PI;

    for(long n = 0, i = - radius; i <=radius; ++i)
    {
        long i2 = i * i;
        for(long j = -radius; j <= radius; ++j, ++n)
            kernel[n] = exp(-(double)(i2 + j * j) / sigma2) / sigmap;
     }

Kernel即为权重

Radius为所求像素与当前像素距离(半径)

针对这个公式我们可以算出3*3,5*5,7*7等滤波器,出于性能考虑,我们还是使用5*5滤波器

3*3滤波器

5*5滤波器

有现成的就不算了,算这个也消耗一些性能

我们直接用这个权重

关键代码如下

			float3 mc00 = tex2D (_MainTex, i.uv_MainTex-fixed2(2,2)/_inten).rgb;
			float3 mc10 = tex2D (_MainTex, i.uv_MainTex-fixed2(1,2)/_inten).rgb;
			float3 mc20 = tex2D (_MainTex, i.uv_MainTex-fixed2(0,2)/_inten).rgb;
			float3 mc30 = tex2D (_MainTex, i.uv_MainTex-fixed2(-1,2)/_inten).rgb;
			float3 mc40 = tex2D (_MainTex, i.uv_MainTex-fixed2(-2,2)/_inten).rgb;

			float3 mc01 = tex2D (_MainTex, i.uv_MainTex-fixed2(2,1)/_inten).rgb;
			float3 mc11 = tex2D (_MainTex, i.uv_MainTex-fixed2(1,1)/_inten).rgb;
			float3 mc21 = tex2D (_MainTex, i.uv_MainTex-fixed2(0,1)/_inten).rgb;
			float3 mc31 = tex2D (_MainTex, i.uv_MainTex-fixed2(-1,1)/_inten).rgb;
			float3 mc41 = tex2D (_MainTex, i.uv_MainTex-fixed2(-2,1)/_inten).rgb;

			float3 mc02 = tex2D (_MainTex, i.uv_MainTex-fixed2(2,0)/_inten).rgb;
			float3 mc12 = tex2D (_MainTex, i.uv_MainTex-fixed2(1,0)/_inten).rgb;
			float3 mc22mc = tex2D (_MainTex, i.uv_MainTex).rgb;
			float3 mc32 = tex2D (_MainTex, i.uv_MainTex-fixed2(-1,0)/_inten).rgb;
			float3 mc42 = tex2D (_MainTex, i.uv_MainTex-fixed2(-2,0)/_inten).rgb;

			float3 mc03 = tex2D (_MainTex, i.uv_MainTex-fixed2(2,-1)/_inten).rgb;
			float3 mc13 = tex2D (_MainTex, i.uv_MainTex-fixed2(1,-1)/_inten).rgb;
			float3 mc23 = tex2D (_MainTex, i.uv_MainTex-fixed2(0,-1)/_inten).rgb;
			float3 mc33 = tex2D (_MainTex, i.uv_MainTex-fixed2(-1,-1)/_inten).rgb;
			float3 mc43 = tex2D (_MainTex, i.uv_MainTex-fixed2(-2,-1)/_inten).rgb;

			float3 mc04 = tex2D (_MainTex, i.uv_MainTex-fixed2(2,-2)/_inten).rgb;
			float3 mc14 = tex2D (_MainTex, i.uv_MainTex-fixed2(1,-2)/_inten).rgb;
			float3 mc24 = tex2D (_MainTex, i.uv_MainTex-fixed2(0,-2)/_inten).rgb;
			float3 mc34 = tex2D (_MainTex, i.uv_MainTex-fixed2(-1,-2)/_inten).rgb;
			float3 mc44 = tex2D (_MainTex, i.uv_MainTex-fixed2(-2,-2)/_inten).rgb;
			float3 c=0;
c+=(mc00+mc40+mc04+mc44);//4
c+=4*(mc10+mc30+mc14+mc34+mc01+mc41+mc03+mc43);//16
c+=7*(mc20+mc24+mc02+mc42);//16
c+=16*(mc11+mc13+mc03+mc33);//32
c+=26*(mc21+mc23+mc12+mc32);//64
c+=41*mc22mc;//32
c/=273;

_inten为模糊程度

觉得冗长麻烦也可用for循环代替。

然后我们要取其中的亮色部分与原有图像混合,

这一部分直接调用unity内部函数Luminance函数求出亮度,把它与模糊的图像相乘,暗色部分自然消除

但如果直接相乘就会在暗色的边缘产生不自然的黑影,就是把暗色也“泛光了”,为此我们不让Luminance后的值为0,再加上0.1,也不影响亮度。

			float lum = Luminance(c);
			c = mc22mc + c * (lum+0.1) * _Lum;
			return float4(c,1);

最终与HDR结合再一起就是上图例子的最终效果

最后一道工序就是放入相机中,我们建立一个c#并负责传值

代码如下:

using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class HDRGlow : MonoBehaviour {
    #region Variables
    public Shader curShader;
    private Material curMaterial;
    public float exp = 0.4f;
    public float bm = 0.4f;
    public int inten = 512;
    public float lum = 1f;
    #endregion

    #region Properties
    Material material
    {
        get
        {
            if (curMaterial == null)
            {
                curMaterial = new Material(curShader);
                curMaterial.hideFlags = HideFlags.HideAndDontSave;
            }
            return curMaterial;
        }
    }
    #endregion

    void Start()
    {
        if (!SystemInfo.supportsImageEffects)
        {
            enabled = false;
            return;
        }

        if (!curShader && !curShader.isSupported)
        {
            enabled = false;
        }
    }

    void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
    {
        if (curShader != null)
        {
            material.SetFloat("_Exp", exp);
            material.SetFloat("_BM", bm);
            material.SetFloat("_Inten", inten);
            material.SetFloat("_Lum", lum);
            Graphics.Blit(sourceTexture, destTexture, material);
        }
        else
        {
            Graphics.Blit(sourceTexture, destTexture);
        }
    }
    void OnDisable()
    {
        if (curMaterial)
        {
            DestroyImmediate(curMaterial);
        }
    }
}

Unity 的imageEffect有一个叫做BloomAndLensFlares

与本文的差别是多了色彩平衡和lens flare效果,可以试着再加上去

                                                     -------  by wolf96 http://blog.csdn.net/wolf96

时间: 2024-08-29 21:24:45

Unity3d HDR和Bloom效果(高动态范围图像和泛光)的相关文章

HDR 高动态范围图像

以下来源于百度百科: 高动态范围图像(High-Dynamic Range,简称HDR),相比普通的图像,可以提供更多的动态范围和图像细节,根据不同的曝光时间的LDR(Low-Dynamic Range)图像,利用每个曝光时间相对应最佳细节的LDR图像来合成最终HDR图像,能够更好的反映出真实环境中的视觉效果. 如上文所说HDR,为高动态范围的简称,何为高动态范围,举例说明:现实真正存在的亮度差,即最亮的物体亮度,和最暗的物体亮度之比为108, 而人类的眼睛所能看到的范围是105 左右,但是一般

Unity3D烘培无效果原因

调节以下设置 Unity3D烘培无效果原因

Unity3D——加入剑痕效果(PocketRPG Trail插件)

首先非常感谢大家的支持,因为近期项目吃紧,所以更新的速度可能会有点慢!希望大家谅解,当然大家的支持是我最大的动力.我也会尽我所能写出更好的文章,当然因为本人是个新手并且工作的内容也不是unity3D.可是本人对于这个比較爱好,所以都是在课余的时间去研究这些东西,没有什么实战,不可以更加深入的解读,分析.当然有看我文章的都因该知道我如今写的内容都是再基础只是的,同一时候在博客中也是有非常多人已经写过啦! 至于这个怎么说呢?因为本人不是干这个的.所以说临时还没有什么比較高深的和大家分享.同一时候我也

Unity3D实现弹幕的效果

孙广东   2015.6.15 对于逗比的游戏.无厘头.可以让大家吐糟的游戏,如果有弹幕的功能是极好的. 使用U5和 UGUI 目前实现的很简陋而已. /// <summary> /// 实现看视频时的弹幕效果 /// </summary> public class DanMu : MonoBehaviour { //public Text[] texts; public GameObject textPrefab; [Tooltip("满屏的个数")] pub

Unity3d之遛光效果

所谓遛光效果,如一个图片上一条刀光从左闪到右边,以下为实现代码: c#代码: using System; using UnityEngine; public class WalkLightEffect : MonoBehaviour { public Texture MainTex; public Texture LightTex; public float Duration; public float LightULen; public Vector2 Size; bool m_play; f

unity3d实现广告滑动效果

新建了一个带mask的prefab,加上代码只需要将图片prefab.按钮prefab和所想添加的图片 拖进去会自动生成按钮,滑动速度可以随意调time,滑动效果用itween实现的,所以需要加上itween插件 效果如下:(图片是我最爱的马路小天使(ˉ﹃ˉ)) 附上代码 1 using UnityEngine; 2 using System.Collections.Generic; 3 using UnityEngine.UI; 4 5 public class Mask : MonoBeha

Unity3D 2D Sprite描边效果Shader,可手动调整效果适配

最近两个月学了很多Shader的知识,现在也算入点门了.现在网上有很多2D描边的Shader,说实话大多数很差劲.有些多余的条件判断影响效率,提供的参数也不够适配所有图片.因为美术喜欢在图片上面加一些效果,再加上切图的时候背景图的透明部分不够多,或者透明通道透明不彻底等等问题,2D图片描边效果通常都不尽如人意.这种情况一般是要从美术那边用ps做调整,如果需要描边切图周围需要留出一点区域,我这个Shader提供了两个参数可以调整效果,检测范围和描边粗细,根据图片的不同,参数肯定要做些调整才能达到最

UnityShader实例15:屏幕特效之Bloom

http://blog.csdn.net/u011047171/article/details/48522073 Bloom特效 概述 Bloom,又称"全屏泛光",是游戏中常用的一种镜头效果,是一种比较廉价的"伪HDR"效果(如下右图):使用了Bloom效果后,画面的对比会得到增强,亮的地方曝光也会得到加强,画面也会呈现一种朦胧,梦幻的效果,婚纱摄影中照片处理经常用到这种类似处理效果.Bloom效果一般用来近似模拟HDR效果,效果也比较相向,但实现原理却完全不同.

Unity Shader 屏幕后效果——Bloom外发光

Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https://www.cnblogs.com/koshio0219/p/11152534.html 计算方法: 总共需要用到4个Pass,它们的顺序如下: Pass 1:得到纹理的亮度值(灰度值),由此计算出亮部区域,传递给一个临时的新纹理,这里叫_Bloom Pass 2,3:单独对_Bloom进行高斯模糊(