文章开始先放两组效果,文章结尾再放两组效果
本文测试场景资源来自浅墨大神,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

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

  1. HDR和bloom效果的区别和关系

    什么是HDR?        谈论游戏画面时常说的HDR到底是什么呢?HDR,本身是High-Dynamic Range(高动态范围)的缩写,这本来是一个CG概念.HDR的含义,简单说,就是超越普通的 ...

  2. HDR 高动态范围图像

    以下来源于百度百科: 高动态范围图像(High-Dynamic Range,简称HDR),相比普通的图像,可以提供更多的动态范围和图像细节,根据不同的曝光时间的LDR(Low-Dynamic Rang ...

  3. WebGL学习之HDR与Bloom

    原文地址:WebGL学习之HDR与Bloom 什么是HDR HDR (High Dynamic Range,高动态范围),在摄影领域,指的是可以提供更多的动态范围和图像细节的一种技术手段.简单讲就是将 ...

  4. Unity shader学习之屏幕后期处理效果之Bloom效果

    Bloom特效是游戏中常见的一种屏幕效果.这种特效可以模拟真实摄像机的一种图像效果,它让画面中较亮的区域“扩散”到周围的区域中,造成一种朦胧的效果. Bloom的实现原理很简单,首先根据一个阈值提取出 ...

  5. 【温故而知新-Javascript】图片效果(图像震动效果、闪烁效果、自动切换图像)

    1.当鼠标指针经过图像时图像震动效果 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " ...

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

    首先非常感谢大家的支持,因为近期项目吃紧,所以更新的速度可能会有点慢!希望大家谅解,当然大家的支持是我最大的动力.我也会尽我所能写出更好的文章,当然因为本人是个新手并且工作的内容也不是unity3D. ...

  7. 【技术博客】在Unity3d中实现烟花效果

    在游戏开发中,我们经常需要用到类似烟花的效果.在Unity3d中,实现烟花效果的方法不止一种,我选用了Unity3d中新添加的粒子特效工具--visual effect graph来进行实现. 实现过 ...

  8. Unity3D Shader 空气扭动效果

    //预览图 //原理 一个摄像机CullingMask设置只可见"Distortion"的Layer(需要自己手动加),输入到一张RenderTexture,其实就是用于确定哪里要 ...

  9. 【转】Unity3D如何制作落叶效果

    原文地址:http://hi.baidu.com/cupgenie/item/c23861df692f59e3b3f777a8 创建一个粒子系统 GameObject>Create other& ...

随机推荐

  1. iOS军火库-好用的ActionSheetView

    GitHub地址 一个自定义的ActionSheetView,支持显示标题,默认选中,使用block回调. 使用说明 [GLActionSheet showWithDataSource:@[@&quo ...

  2. 洛谷 U2878 小R的分数比赛(fraction)

    题目提供者 2015c07 标签 数论(数学相关) 高精度 难度 尚无评定 通过/提交 0/29 提交该题 记录 题目背景 P5难度系数:★★★☆☆ 小R再次挑战你. 这次的挑战又会是什么呢? 题目描 ...

  3. 2D动态光照

    对场景内所有点发出射线, 如果射线被某条边阻挡, 则射线停留在阻挡的边上, 如果射线顺利抵达终点, 则对射线偏移-0.001, +0.001角度, 再射出2条射线, 停留在后续的阻挡边上. 把最终的射 ...

  4. 我的Hibernate入门

    今天忙了一整天,终于搭建好了我的第一个Hibernate程序,中间关于hibernate.cfg.xml的问题搞了半天,不过最后还是搞明白了,下面来讲一讲过程. 首先在你的eclipse中安装Hibe ...

  5. oracle创建第三方数据接口表,指定特定用户访问某张表

    /*****创建用户并指定操作哪张表开始******/ --1.创建用户并设置默认表空间 CREATE USER CHENGDWY IDENTIFIED BY CHENGDWY DEFAULT TAB ...

  6. Maven介绍,包括作用、核心概念、用法、常用命令、扩展及配置

    由浅入深,主要介绍maven的用途.核心概念(Pom.Repositories.Artifact.Build Lifecycle.Goal).用法(Archetype意义及创建各种项目).maven常 ...

  7. PHP创建桌面快捷方式实例

    要利用php创建桌面快捷方式我们需要借助于header,InternetShortcut及一些我看不懂的代码. 方法:新建一个php文件,然后把下面的代码扔进去,保存为比如shortcut.php,放 ...

  8. 帝国cms7.0设置标题图片(缺失状态下)

    有时候因为我们没有设置标题图片,程序就会是使用自己的标题图片,这就是问题所在,现在有2个办法解决这个问题, [1]直接替换调程序的标签图片,但是这样的方法虽然简单,但是图片大小固定,要是每个模版的图片 ...

  9. 用vscode写博客和发布

    最近想开始写点博客什么的,然后看到在博客园注册了一个账号这么久,也没有写过文章,就想在博客园写点什么来刷个存在感,而且觉得用Markdown编辑器来写文章挺不错,但是博客园自带的Markdown编辑器 ...

  10. 学习Swift -- 构造器(上)

    构造器(上) 构造过程是为了使用某个类.结构体或枚举类型的实例而进行的准备过程.这个过程包含了为实例中的每个存储型属性设置初始值和为其执行必要的准备和初始化任务. 构造过程是通过定义构造器(Initi ...