国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

3D游戲引擎系列十一

2019-11-09 18:27:42
字體:
供稿:網(wǎng)友

筆者介紹:姜雪偉,IT公司技術(shù)合伙人,IT高級(jí)講師,CSDN社區(qū)專家,特邀編輯,暢銷書作者,國(guó)家專利發(fā)明人;已出版書籍:《手把手教你架構(gòu)3D游戲引擎》電子工業(yè)出版社和《Unity3D實(shí)戰(zhàn)核心技術(shù)詳解》電子工業(yè)出版社等。

CSDN課程視頻網(wǎng)址:http://edu.csdn.net/lecturer/144

后處理是游戲場(chǎng)景渲染的重要一環(huán),利用這節(jié)給讀者介紹運(yùn)用于場(chǎng)景中的后處理渲染效果,后處理效果也是體現(xiàn)GPU強(qiáng)大的處理能力。最常用的后處理效果渲染:Bloom渲染、Blur渲染、HDR渲染等被稱為后處理渲染。Bloom渲染又稱為全屏泛光,后處理渲染在端游里應(yīng)用的最廣泛,通俗的講就是場(chǎng)景首先經(jīng)過CPU處理后,是每幀處理后再通過GPU在原有渲染的基礎(chǔ)上再渲染一遍,最后將其在屏幕上顯示出來的過程稱為后處理渲染。實(shí)現(xiàn)方式新建一個(gè)文本文件把擴(kuò)展名改成.fx。在編寫Shader文件之前先講一下Bloom實(shí)現(xiàn)原理主要分為4步:

1、提取原場(chǎng)景貼圖中的亮色;

2、針對(duì)提取貼圖進(jìn)行橫向Blur模糊;

3、在橫向模糊基礎(chǔ)上進(jìn)行縱向Blur模糊;

4、所得貼圖與原場(chǎng)景貼圖疊加得最終效果圖。

根據(jù)這4個(gè)步驟,開始著手編寫Shader代碼,還是新建一個(gè)文本文件將擴(kuò)展名命名為fx。對(duì)應(yīng)的Shader完整代碼如下所示:

texture texSource;texture texScene;struct VS_INPUT{	float4 pos : POSITION;	float2 uv  : TEXCOORD0;};struct VS_OUTPUT{	float4 pos : POSITION;	float2 uv  : TEXCOORD0;};VS_OUTPUT quad_vs(VS_INPUT vert){	VS_OUTPUT vsout = (VS_OUTPUT)0;		vsout.pos = vert.pos;	vsout.uv = vert.uv;		return vsout;}sampler sourceSampler = sampler_state{		Texture = <texSource>;    MinFilter = LINEAR;    MagFilter = LINEAR;};// 向下取樣//---------------------------------------------------const float HighlightThreshold = 0.5;float luminance(float3 c){	return dot( c, float3(0.3, 0.59, 0.11) );}// this function should be baked into a texture lookup for performancefloat highlights(float3 c){	return smoothstep(HighlightThreshold, 1.0, luminance(c.rgb));}float4 ps_downsample(float2 uv : TEXCOORD0) : COLOR{	float4 color = tex2D(sourceSampler, uv);		// store hilights in alpha	color.a = highlights(color);		return color;}// blur//----------------------------------------------------------------// blur filter weightsconst float weights7[7] = {0.05, 0.1, 0.2, 0.3, 0.2, 0.1, 0.05};	//橫向Blurfloat4 ps_hblur(float2 uv : TEXCOORD0) : COLOR{	float texelSize = 1.0f/512.0f;	//1除以貼圖大小	float4 color = 0;	for(int i=0; i<7; i++)	{		// 把uv的生成放到vs會(huì)節(jié)省很多運(yùn)算		float2 uvi = uv + float2(texelSize*(i-3),0);		color += tex2D(sourceSampler, uvi) * weights7[i];	}		return color;}//縱向Blurfloat4 ps_vblur(float2 uv : TEXCOORD0) : COLOR{	float texelSize = 1.0f/384.0f;	//1除以貼圖大小	float4 color = 0;	for(int i=0; i<7; i++)	{		// 把uv的生成放到vs會(huì)節(jié)省很多運(yùn)算		float2 uvi = uv + float2(0, texelSize*(i-3));		color += tex2D(sourceSampler, uvi) * weights7[i];	}		return color;}// 組合//------------------------------------------------------------------sampler sceneSampler = sampler_state{		Texture = <texScene>;    MinFilter = None;    MagFilter = None;    AddressU = CLAMP;    AddressV = CLAMP;};float4 ps_compose(float2 uv : TEXCOORD0) : COLOR{	float4 blurColor = tex2D(sourceSampler, uv);	float4 sceneColor = tex2D(sceneSampler, uv);		return sceneColor*0.8 + blurColor*0.2 + blurColor*blurColor.a;}// technique//------------------------------------------------------------------technique PP_Bloom{	pass DownSample	{		CullMode = none;		ZEnable = false;		ZWriteEnable = false;				VertexShader = compile vs_1_1 quad_vs();		PixelShader = compile ps_2_0 ps_downsample();	}		pass HBlur	{		VertexShader = compile vs_1_1 quad_vs();		PixelShader = compile ps_2_0 ps_hblur();	}		pass VBlur	{		VertexShader = compile vs_1_1 quad_vs();		PixelShader = compile ps_2_0 ps_vblur();	}		pass Compose	{		VertexShader = compile vs_1_1 quad_vs();		PixelShader = compile ps_2_0 ps_compose();	}}以上是整個(gè)Shader代碼的編寫,接下來對(duì)于一些核心知識(shí)點(diǎn)重點(diǎn)介紹一下:第一步是實(shí)現(xiàn)提取原場(chǎng)景貼圖中的亮色,因?yàn)锽loom又稱為全屏泛光,所以要提取貼圖中的亮色。對(duì)應(yīng)的代碼函數(shù)如下所示:

const float HighlightThreshold = 0.5;float luminance(float3 c){	return dot( c, float3(0.3, 0.59, 0.11) );}// this function should be baked into a texture lookup for performancefloat highlights(float3 c){	return smoothstep(HighlightThreshold, 1.0, luminance(c.rgb));}

第二步在第一步的基礎(chǔ)上,針對(duì)需要渲染的貼圖進(jìn)行橫向Blur模糊。函數(shù)代碼如下:

const float weights7[7] = {0.05, 0.1, 0.2, 0.3, 0.2, 0.1, 0.05};	float4 ps_hblur(float2 uv : TEXCOORD0) : COLOR{	float texelSize = 1.0f/512.0f;	//1除以貼圖大小	float4 color = 0;	for(int i=0; i<7; i++)	{		// 把uv的生成放到vs會(huì)節(jié)省很多運(yùn)算		float2 uvi = uv + float2(texelSize*(i-3),0);		color += tex2D(sourceSampler, uvi) * weights7[i];	}		return color;}

第三步在第二步的基礎(chǔ)上,針對(duì)提取貼圖進(jìn)行縱向Blur模糊。函數(shù)代碼如下:

float4 ps_vblur(float2 uv : TEXCOORD0) : COLOR{	float texelSize = 1.0f/384.0f;	//1除以貼圖大小	float4 color = 0;	for(int i=0; i<7; i++)	{		// 把uv的生成放到vs會(huì)節(jié)省很多運(yùn)算		float2 uvi = uv + float2(0, texelSize*(i-3));		color += tex2D(sourceSampler, uvi) * weights7[i];	}		return color;}

第四步將模糊處理的圖片和原場(chǎng)景貼圖分別進(jìn)行紋理取樣,最后將二者按照線性公式混合處理得到最終的結(jié)果。函數(shù)代碼如下:

sampler sceneSampler = sampler_state{		Texture = <texScene>;    MinFilter = None;    MagFilter = None;    AddressU = CLAMP;    AddressV = CLAMP;};float4 ps_compose(float2 uv : TEXCOORD0) : COLOR{	float4 blurColor = tex2D(sourceSampler, uv);	float4 sceneColor = tex2D(sceneSampler, uv);		return sceneColor*0.8 + blurColor*0.2 + blurColor*blurColor.a;}

下面開始介紹在引擎中的實(shí)現(xiàn)了,其C++實(shí)現(xiàn)也是根據(jù)Shader的思路編寫的。首先通過函數(shù)創(chuàng)建三張紋理,這三張紋理都是在內(nèi)存中的,第一張用于存放游戲中提取原場(chǎng)景貼圖中的亮色,第二張用于存放橫向模糊的圖片,第三張用于存放縱向模糊的圖片。另外編寫的Shader文件必須要程序加載才能生效,C++方面也有對(duì)應(yīng)著Shader編程的代碼,主要分了四步:取樣,橫向Blur,縱向Blur,組合。現(xiàn)將C++核心代碼展示如下:

bool PostPRocessBloom::init(IDirect3DDevice9 *pD3DDevice){	m_pD3DDevice = pD3DDevice;	if(!m_scene.init(pD3DDevice))		return false;	// 創(chuàng)建所需的render targets	HRESULT hr = pD3DDevice->CreateTexture(clientWidth, clientHeight,		1,//mip-map		D3DUSAGE_RENDERTARGET,		D3DFMT_A8R8G8B8,		D3DPOOL_DEFAULT,		&m_pRTFull,		NULL);	if(FAILED(hr))		return false;	//創(chuàng)建紋理存放橫向Blur	hr = pD3DDevice->CreateTexture(clientWidth/2, clientHeight/2,		1,//mip-map		D3DUSAGE_RENDERTARGET,		D3DFMT_A8R8G8B8,		D3DPOOL_DEFAULT,		&m_pRTQuarterA,		NULL);	if(FAILED(hr))		return false;		hr = pD3DDevice->CreateTexture(clientWidth/2, clientHeight/2,		1,//mip-map		D3DUSAGE_RENDERTARGET,		D3DFMT_A8R8G8B8,		D3DPOOL_DEFAULT,		&m_pRTQuarterB,		NULL);	if(FAILED(hr))		return false;	// create effect	m_pEffect = DrawingUtil::getInst()->loadEffect(pD3DDevice,"Shader//Bloom.fx");	// pictue	hr = D3DXCreateTextureFromFileEx(pD3DDevice, "Media//gf.jpg",		D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,		1, //mip lv		0,//usage		D3DFMT_A8R8G8B8,		D3DPOOL_MANAGED,		D3DX_DEFAULT,		D3DX_DEFAULT,		0,		NULL,		NULL,		&m_pPic);	if(FAILED(hr))		return false;		D3DSURFACE_DESC sd;	hr = m_pPic->GetLevelDesc(0, &sd);	return m_screenQuad.init(pD3DDevice);}void PostProcessBloom::render(){	HRESULT hr;	IDirect3DTexture9 *pScene = NULL;		if(m_bUsePic)		pScene = m_pPic;	else	{		// 把場(chǎng)景渲染到RT full		SetRenderTarget SRT(m_pD3DDevice, m_pRTFull);		m_scene.render();		pScene = m_pRTFull;	}	UINT numPass = 0;	hr = m_pEffect->Begin(&numPass,0);	assert(numPass == 4);	// down sample	{		hr = m_pEffect->SetTexture("texSource", pScene);		hr = m_pEffect->BeginPass(0);				SetRenderTarget SRT(m_pD3DDevice, m_pRTQuarterA);		m_screenQuad.draw();		hr = m_pEffect->EndPass();	}	// H blur	{		hr = m_pEffect->SetTexture("texSource", m_pRTQuarterA);		hr = m_pEffect->BeginPass(1);		SetRenderTarget SRT(m_pD3DDevice, m_pRTQuarterB);		m_screenQuad.draw();		hr = m_pEffect->EndPass();	}	// V blur	{		hr = m_pEffect->SetTexture("texSource", m_pRTQuarterB);		hr = m_pEffect->BeginPass(2);		SetRenderTarget SRT(m_pD3DDevice, m_pRTQuarterA);		m_screenQuad.draw();		hr = m_pEffect->EndPass();	}	// compose	hr = m_pEffect->SetTexture("texSource", m_pRTQuarterA);	hr = m_pEffect->SetTexture("texScene", pScene);	hr = m_pEffect->BeginPass(3);	m_screenQuad.draw();	hr = m_pEffect->EndPass();	hr = m_pEffect->End();}上述代碼是根據(jù)我們說的Bloom四步法實(shí)現(xiàn)的,C++代碼中設(shè)置了四個(gè)Pass通道與Shader文件對(duì)應(yīng)著處理。Bloom渲染技術(shù)也是面試官經(jīng)常詢問的問題,比如問面試者關(guān)于Bloom實(shí)現(xiàn)的原理,希望通過本節(jié)課的講解對(duì)大家有所幫助。Bloom后處理渲染在游戲中的效果如下圖:

Bloom在端游特別是次時(shí)代游戲中使用是最多的,可以說是必不可少的后處理渲染,在評(píng)價(jià)一款游戲品質(zhì)方面也占很大的比重,所以必須要重點(diǎn)掌握。


上一篇:servlet筆記_01

下一篇:自定義屬性步驟

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 囊谦县| 衢州市| 正安县| 邵武市| 汶川县| 黄平县| 三台县| 闵行区| 新乡县| 堆龙德庆县| 贡觉县| 淄博市| 西安市| 边坝县| 肥乡县| 漳平市| 浦城县| 孙吴县| 商河县| 永康市| 抚松县| 多伦县| 林口县| 抚州市| 祁门县| 海盐县| 无锡市| 云龙县| 永福县| 唐河县| 崇明县| 浏阳市| 昌江| 高密市| 满洲里市| 汝南县| 安康市| 改则县| 老河口市| 武清区| 岱山县|