bloom(转)
轉載:http://www.cnblogs.com/kenkao/archive/2011/08/25/2153752.html
感謝原創者。
?
又稱“全屏泛光”,是大名鼎鼎的虛幻3游戲引擎中最通用的后期特效技術~
Bloom特效的實現主要依賴于PostProcess框架,即實時繪制當前場景到一后臺渲染表面,而后針對其對應貼圖進行像素級渲染~
大家還記得我們之前實現的水面效果中的反射和折射貼圖嗎?此即為PostProcess的典型應用,與Bloom特效有異曲同工之妙。
下面,我們就來揭秘這個Bloom特效的實現流程~
本節我們實現的Bloom特效,在流程上總共分為4步:
1.提取原場景貼圖中的亮色;
2.針對提取貼圖進行橫向模糊;
3.在橫向模糊基礎上進行縱向模糊;
4.所得貼圖與原場景貼圖疊加得最終效果圖。
所用到的Shader主要有三個,分別對應如上4個步驟中的第1步、第2、3步和第4步。我們來看源代碼:
?
BloomExtract.fx /*-------------------------------------代碼清單:BloomExtract.fx
來自:http://create.msdn.com/en-US/(AppHub)
-------------------------------------*/
//提取原始場景貼圖中明亮的部分
//這是應用全屏泛光效果的第一步
sampler?TextureSampler?:?register(s0);
floatBloomThreshold;
float4?ThePixelShader(float2?texCoord?:?TEXCOORD0)?:?COLOR0
{
????//提取原有像素顏色
float4?c?=tex2D(TextureSampler,?texCoord);
????//在BloomThreshold參數基礎上篩選較明亮的像素
returnsaturate((c?-BloomThreshold)?/(1-BloomThreshold));
????
}
technique?BloomExtract
{
????pass?Pass1
????{
????????PixelShader?=compile?ps_2_0?ThePixelShader();
????}
}
?
GaussianBlur.fx /*-------------------------------------代碼清單:GaussianBlur.fx
來自:http://create.msdn.com/en-US/(AppHub)
-------------------------------------*/
//高斯模糊過濾
//這個特效要應用兩次,一次為橫向模糊,另一次為橫向模糊基礎上的縱向模糊,以減少算法上的時間復雜度
//這是應用Bloom特效的中間步驟
sampler?TextureSampler?:?register(s0);
#defineSAMPLE_COUNT?15
//偏移數組
float2?SampleOffsets[SAMPLE_COUNT];
//權重數組
floatSampleWeights[SAMPLE_COUNT];
float4?ThePixelShader(float2?texCoord?:?TEXCOORD0)?:?COLOR0
{
????float4?c?=0;
????
????//按偏移及權重數組疊加周圍顏色值到該像素
????//相對原理,即可理解為該像素顏色按特定權重發散到周圍偏移像素
for(inti?=0;?i?<SAMPLE_COUNT;?i++)
????{
????????c?+=tex2D(TextureSampler,?texCoord?+SampleOffsets[i])?*SampleWeights[i];
????}
????
????returnc;
}
technique?GaussianBlur
{
????pass?Pass1
????{
????????PixelShader?=compile?ps_2_0?ThePixelShader();
????}
}
?
BloomCombine.fx /*-------------------------------------代碼清單:BloomCombine.fx
來自:http://create.msdn.com/en-US/(AppHub)
-------------------------------------*/
//按照特定比例混合原始場景貼圖及高斯模糊貼圖,產生泛光效果
//這是全屏泛光特效的最后一步
//模糊場景紋理采樣器
sampler?BloomSampler?:?register(s0);
//原始場景紋理及采樣器定義
texture?BaseTexture;
sampler?BaseSampler?=sampler_state
{
????Texture???=(BaseTexture);
????MinFilter?=Linear;
????MagFilter?=Linear;
????MipFilter?=Point;
????AddressU??=Clamp;
????AddressV??=Clamp;
};
floatBloomIntensity;
floatBaseIntensity;
floatBloomSaturation;
floatBaseSaturation;
//減緩顏色的飽和度
float4?AdjustSaturation(float4?color,?floatsaturation)
{
????//人眼更喜歡綠光,因此選取0.3,?0.59,?0.11三個值
floatgrey?=dot(color,?float3(0.3,?0.59,?0.11));
????returnlerp(grey,?color,?saturation);
}
float4?ThePixelShader(float2?texCoord?:?TEXCOORD0)?:?COLOR0
{
????//提取原始場景貼圖及模糊場景貼圖的像素顏色
float4?bloom?=tex2D(BloomSampler,?texCoord);
????float4?base=tex2D(BaseSampler,?texCoord);
????
????//柔化原有像素顏色
bloom?=AdjustSaturation(bloom,?BloomSaturation)?*BloomIntensity;
????base=AdjustSaturation(base,?BaseSaturation)?*BaseIntensity;
????
????//結合模糊像素值微調原始像素值
base*=(1-saturate(bloom));
????
????//疊加原始場景貼圖及模糊場景貼圖,即在原有像素基礎上疊加模糊后的像素,實現發光效果
returnbase+bloom;
}
technique?BloomCombine
{
????pass?Pass1
????{
????????PixelShader?=compile?ps_2_0?ThePixelShader();
????}
}
?
三個Shader均來自于微軟WP7開發者俱樂部,如有引用,敬請標明AppHub字樣及其站點網址:http://create.msdn.com/en-US/,以示對作者原創版權的尊重!
?
具備相應的Shader之后,下面我們來看如何運用他們來實現Bloom特效的四個關鍵步驟~
因為最終的效果貼圖本質上是一張與屏幕大小相同的紋理,因此,我們使用原來構建的CSpriteBatch進行繪制。而CSpriteBatch提供的接口是針對于CTexture2D的,所以我們首先要增強并完善CTexture2D類的功能~
以下提供兩個函數,使得CTexture2D可以直接產生渲染貼圖,并允許獲取其后臺渲染表面:
?
boolCTexture2D::CreateRenderTarget(UINT?SizeX,?UINT?SizeY){
????//創建渲染貼圖
HRESULT?hr;
????hr?=D3DXCreateTexture(g_pD3DDevice,?SizeX,?SizeY,?1,
????????D3DUSAGE_RENDERTARGET,?D3DFMT_A8R8G8B8,?D3DPOOL_DEFAULT,?&m_pTexture);
????if(FAILED(hr))
????????returnfalse;
????m_Width??=SizeX;
????m_Height?=SizeY;
????m_SurRect.top????=0;
????m_SurRect.left???=0;
????m_SurRect.right??=m_Width;
????m_SurRect.bottom?=m_Height;
????returntrue;
}
boolCTexture2D::GetRenderSurface(IDirect3DSurface9**pOutSurface)
{
????//獲得貼圖的渲染表面
HRESULT?hr;
????hr?=m_pTexture->GetSurfaceLevel(0,?pOutSurface);
????if(FAILED(hr))
????????returnfalse;
????else
????????returntrue;
}
?
之后,就可以著手構建我們的CBloomEffect效果類了:
?
/*-------------------------------------代碼清單:BloomEffect.h
來自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include?"D3DEffect.h"
#include?"Texture2D.h"
#pragmaonce
//Bloom參數體
typedef?struct_BloomParam
{
????char*_Name;??????????????//Bloom特效名稱
float_BloomThreshold;????//飽和度
float_BlurAmount;????????//模糊程度
float_BloomIntensity;????//模糊劇烈度
float_BaseIntensity;?????//原始劇烈度
float_BloomSaturation;???//模糊飽和度
float_BaseSaturation;????//原始飽和度
_BloomParam(){}
????_BloomParam(char*name,?floatbloomThreshold,?floatblurAmount,
????????floatbloomIntensity,?floatbaseIntensity,
????????floatbloomSaturation,?floatbaseSaturation)
????{
????????_Name?=name;??_BloomThreshold?=bloomThreshold;?_BlurAmount?=blurAmount;
????????_BloomIntensity?=bloomIntensity;???_BaseIntensity?=baseIntensity;
????????_BloomSaturation?=bloomSaturation;?_BaseSaturation?=baseSaturation;
????}
}BloomParam;
classCBloomEffect
{
public:
????CBloomEffect(void);
????~CBloomEffect(void);
public:
????voidCreate();???????//創建Bloom特效
voidRelease();??????//釋放Bloom特效
voidDrawScene();????//場景繪制
voidBegin();????????//開啟Bloom
voidEnd();??????????//關閉Bloom
public:
????voidSetParam(BloomParam*pParam){m_pParam?=pParam;}??//參數體設置
BloomParam*GetParam()??????????????????{returnm_pParam;}????//參數體獲取
private:
????voidPostScene();???????????????????//Bloom場景投遞
voidPostSurface(???????????????????//應用特效投遞貼圖到特定緩存表面,本質就是將一個貼圖應用Shader之后的效果寫入另一個貼圖
CTexture2D*pTexture,??????????//后臺紋理
IDirect3DSurface9*pSurface,???//渲染表面
CD3DEffect*pEffect);??????????//目標特效
boolLoadContent();?????????????????//加載內容
boolGetSurfaces();?????????????????//獲取渲染表面
private:
????floatComputeGaussian(floatn);?????????????????//計算高斯模糊參數
voidSetBlurEffectParam(floatdx,?floatdy);???//計算偏移數組及權重數組
private:
????CD3DEffect*m_pBloomExtractEffect;??//Bloom依次用到的三個特效
CD3DEffect*m_pGaussianBlurEffect;
????CD3DEffect*m_pBloomCombineEffect;
private:
????CTexture2D*m_pResolveTarget;???//原始貼圖
CTexture2D*m_pTexture1;????????//模糊貼圖
CTexture2D*m_pTexture2;????????//臨時模糊貼圖
IDirect3DSurface9*m_pResolveSurface;??//原始貼圖渲染表面
IDirect3DSurface9*m_pSurface1;????????//模糊貼圖渲染表面
IDirect3DSurface9*m_pSurface2;????????//臨時貼圖渲染表面
IDirect3DSurface9*m_pOriSurface;??????//初始渲染表面
private:
????BloomParam*m_pParam;??????????????????//Bloom參數體
};
?
BloomEffect.cpp?
該類共產生了3個渲染表面,并在渲染過程中發生了相互疊加,嗯…有點混亂…
我們不妨來看一看每個步驟所得到的渲染效果,而后再針對4個步驟進行分析。如下是我在渲染過程中提取的效果圖:
有了這個流程圖,大家的思路是不是清晰了一些呢?下面,大家結合這個流程圖來分析各個步驟:
第一步:
應用BloomExtract特效提取原始場景貼圖m_pResolveTarget中較明亮的顏色繪制到m_pTexture1貼圖中(m_pResolveTarget--->m_pTexture1)
第二步:
應用GaussianBlur特效,在m_pTexture1貼圖基礎上進行橫向高斯模糊到m_pTexture2貼圖(m_pTexture1--->m_pTexture2)
第三步:
再次應用GaussianBlur特效,在橫向模糊之后的m_pTexture2貼圖基礎上進行縱向高斯模糊,得到最終的模糊貼圖m_pTexture1(m_pTexture2--->m_pTexture1)
注意:此時,m_pTexture1貼圖即為最終的模糊效果貼圖
如果大家不明白高斯模糊的內部原理,可以參看老師為大家翻譯的這篇文章:http://shiba.hpe.sh.cn/jiaoyanzu/WULI/showArticle.aspx?articleId=518&classId=4
第四步:
應用BloomCombine特效,疊加原始場景貼圖m_pResolveTarget及兩次模糊之后的場景貼圖m_pTexture1,從而實現發光效果(m_pResolveTarget+m_pTexture1)
怎么樣?大家明白了嗎?呵呵~
?
我們來看主體代碼:
D3DGame.cpp?
對Bloom參數體各個成員變量數值進行交叉組合,則我們可以得到一系列不同的Bloom效果:
?
?
?
?
還在羨慕那些專業游戲中美輪美奐的后期特效嗎?現在我們也有能力實現了~ 大家趕快動手嘗試一下吧 ^ ^
以上,謝謝~
轉載于:https://www.cnblogs.com/zengqh/archive/2012/10/09/2716447.html
總結
- 上一篇: Ajax--readyState一直为0
- 下一篇: 图形界面终端下打印内核调试信息