Unity3d HDR和Bloom效果(高动态范围图像和泛光)
生活随笔
收集整理的這篇文章主要介紹了
Unity3d HDR和Bloom效果(高动态范围图像和泛光)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章開始先放兩組效果,文章結尾再放兩組效果
本文測試場景資源來自淺墨大神,shader效果為本文效果
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映射為LDR顯示
http://www.ownself.org/blog/2011/tone-mapping.html中的解釋很好
Tone Mapping原是攝影學中的一個術語,因為打印相片所能表現的亮度范圍不足以表現現實世界中的亮度域,而如果簡單的將真實世界的整個亮度域線性壓縮到照片所能表現的亮度域內,則會在明暗兩端同時丟失很多細節,這顯然不是所希望的效果,Tone Mapping就是為了克服這一情況而存在的,既然相片所能呈現的亮度域有限則我們可以根據所拍攝場景內的整體亮度通過光圈與曝光時間的長短來控制一個合適的亮度域,這樣既保證細節不丟失,也可以不使照片失真。人的眼睛也是相同的原理,這就是為什么當我們從一個明亮的環境突然到一個黑暗的環境時,可以從什么都看不見到慢慢可以適應周圍的亮度,所不同的是人眼是通過瞳孔來調節亮度域的。
一個tone-mapping的公式
AvgLogLuminance就是全屏幕或部分屏幕的亮度的對數的平均值
?
AvgLogLuminance的公式
Lw是亮度,n是所取亮度數
這個操作能讓L值限制位[0,1)
一些tone-mapping操作用exposure或gamma作為參數控制最終的圖像。
tone-mapping是非線性的,他對暗色保有一定范圍并且對亮色逐步接近動態
這個技術產生吸引人的視覺效果,有著強烈的對比和細節。
HDR Rendering In OpenGL一文中給出簡要且效果不錯的公式
?
關鍵代碼如下
[cpp]?view plain?copy 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效果。
高斯模糊的濾波器是一種低通濾波器
就是去當前像素和周圍的像素按一定權重混合,產生一定模糊效果
高斯正態分布曲線
可以通過這個公式直接算出權重
[cpp]?view plain?copy 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為所求像素與當前像素距離(半徑)
有現成的就不算了,算這個也消耗一些性能
我們直接用這個權重
關鍵代碼如下
[cpp]?view plain?copy ????????????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,也不影響亮度。
[cpp]?view plain?copy 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
本文測試場景資源來自淺墨大神,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的公式
?
AvgLogLuminance就是全屏幕或部分屏幕的亮度的對數的平均值
?
AvgLogLuminance的公式
Lw是亮度,n是所取亮度數
這個操作能讓L值限制位[0,1)
一些tone-mapping操作用exposure或gamma作為參數控制最終的圖像。
tone-mapping是非線性的,他對暗色保有一定范圍并且對亮色逐步接近動態
這個技術產生吸引人的視覺效果,有著強烈的對比和細節。
HDR Rendering In OpenGL一文中給出簡要且效果不錯的公式
?
關鍵代碼如下
[cpp]?view plain?copy
_Exp,_BM為外部可控變量
HDR流程如下
?
如果分不清HDR與加亮light,可以看看skybox,加亮light是不會加亮skybox的,HDR使顏色更鮮明,像素更清晰。
Bloom泛光
輝光的原因是由于人眼晶狀體的散射我們制造bloom的原理是把圖像的亮的部分通過卷積模糊再疊加到原圖像上,就產生了bloom效果。
高斯模糊的濾波器是一種低通濾波器
就是去當前像素和周圍的像素按一定權重混合,產生一定模糊效果
權重分布如下,離當前像素越遠,權重越低
高斯正態分布曲線
?
可以通過這個公式直接算出權重
[cpp]?view plain?copy
Kernel即為權重
Radius為所求像素與當前像素距離(半徑)
針對這個公式我們可以算出3*3,5*5,7*7等濾波器,出于性能考慮,我們還是使用5*5濾波器
?3*3濾波器
有現成的就不算了,算這個也消耗一些性能
我們直接用這個權重
關鍵代碼如下
[cpp]?view plain?copy
_inten為模糊程度
覺得冗長麻煩也可用for循環代替。
然后我們要取其中的亮色部分與原有圖像混合,
這一部分直接調用unity內部函數Luminance函數求出亮度,把它與模糊的圖像相乘,暗色部分自然消除
但如果直接相乘就會在暗色的邊緣產生不自然的黑影,就是把暗色也“泛光了”,為此我們不讓Luminance后的值為0,再加上0.1,也不影響亮度。
[cpp]?view plain?copy
最終與HDR結合再一起就是上圖例子的最終效果
最后一道工序就是放入相機中,我們建立一個c#并負責傳值
代碼如下:
[csharp]?view plain?copy
Unity 的imageEffect有一個叫做BloomAndLensFlares
與本文的差別是多了色彩平衡和lens flare效果,可以試著再加上去
??????????????????????????????????????????????????????? -------? by wolf96 http://blog.csdn.net/wolf96
總結
以上是生活随笔為你收集整理的Unity3d HDR和Bloom效果(高动态范围图像和泛光)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于Retinex图像增强算法的一些新学
- 下一篇: Tone Mapping