笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN课程视频网址:http://edu.csdn.net/lecturer/144

后处理是游戏场景渲染的重要一环,利用这节给读者介绍运用于场景中的后处理渲染效果,后处理效果也是体现GPU强大的处理能力。最常用的后处理效果渲染:Bloom渲染、Blur渲染、HDR渲染等被称为后处理渲染。Bloom渲染又称为全屏泛光,后处理渲染在端游里应用的最广泛,通俗的讲就是场景首先经过CPU处理后,是每帧处理后再通过GPU在原有渲染的基础上再渲染一遍,最后将其在屏幕上显示出来的过程称为后处理渲染。实现方式新建一个文本文件把扩展名改成.fx。在编写Shader文件之前先讲一下Bloom实现原理主要分为4步:

1、提取原场景贴图中的亮色;

2、针对提取贴图进行横向Blur模糊;

3、在横向模糊基础上进行纵向Blur模糊;

4、所得贴图与原场景贴图叠加得最终效果图。

根据这4个步骤,开始着手编写Shader代码,还是新建一个文本文件将扩展名命名为fx。对应的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 performance
float 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 alphacolor.a = highlights(color);return color;
}// blur
//----------------------------------------------------------------
// blur filter weights
const float weights7[7] = {0.05, 0.1, 0.2, 0.3, 0.2, 0.1, 0.05};
//横向Blur
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会节省很多运算float2 uvi = uv + float2(texelSize*(i-3),0);color += tex2D(sourceSampler, uvi) * weights7[i];}return color;
}//纵向Blur
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会节省很多运算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();}
}

以上是整个Shader代码的编写,接下来对于一些核心知识点重点介绍一下:第一步是实现提取原场景贴图中的亮色,因为Bloom又称为全屏泛光,所以要提取贴图中的亮色。对应的代码函数如下所示:

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 performance
float highlights(float3 c)
{return smoothstep(HighlightThreshold, 1.0, luminance(c.rgb));
}

第二步在第一步的基础上,针对需要渲染的贴图进行横向Blur模糊。函数代码如下:

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会节省很多运算float2 uvi = uv + float2(texelSize*(i-3),0);color += tex2D(sourceSampler, uvi) * weights7[i];}return color;
}

第三步在第二步的基础上,针对提取贴图进行纵向Blur模糊。函数代码如下:

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会节省很多运算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;
}

下面开始介绍在引擎中的实现了,其C++实现也是根据Shader的思路编写的。首先通过函数创建三张纹理,这三张纹理都是在内存中的,第一张用于存放游戏中提取原场景贴图中的亮色,第二张用于存放横向模糊的图片,第三张用于存放纵向模糊的图片。另外编写的Shader文件必须要程序加载才能生效,C++方面也有对应着Shader编程的代码,主要分了四步:取样,横向Blur,纵向Blur,组合。现将C++核心代码展示如下:

bool PostProcessBloom::init(IDirect3DDevice9 *pD3DDevice)
{m_pD3DDevice = pD3DDevice;if(!m_scene.init(pD3DDevice))return false;// 创建所需的render targetsHRESULT hr = pD3DDevice->CreateTexture(clientWidth, clientHeight,1,//mip-mapD3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pRTFull,NULL);if(FAILED(hr))return false;//创建纹理存放横向Blurhr = pD3DDevice->CreateTexture(clientWidth/2, clientHeight/2,1,//mip-mapD3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pRTQuarterA,NULL);if(FAILED(hr))return false;hr = pD3DDevice->CreateTexture(clientWidth/2, clientHeight/2,1,//mip-mapD3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&m_pRTQuarterB,NULL);if(FAILED(hr))return false;// create effectm_pEffect = DrawingUtil::getInst()->loadEffect(pD3DDevice,"Shader\\Bloom.fx");// pictuehr = D3DXCreateTextureFromFileEx(pD3DDevice, "Media\\gf.jpg",D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2,1, //mip lv0,//usageD3DFMT_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{// 把场景渲染到RT fullSetRenderTarget 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();}// composehr = 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();
}

上述代码是根据我们说的Bloom四步法实现的,C++代码中设置了四个Pass通道与Shader文件对应着处理。Bloom渲染技术也是面试官经常询问的问题,比如问面试者关于Bloom实现的原理,希望通过本节课的讲解对大家有所帮助。Bloom后处理渲染在游戏中的效果如下图:

Bloom在端游特别是次时代游戏中使用是最多的,可以说是必不可少的后处理渲染,在评价一款游戏品质方面也占很大的比重,所以必须要重点掌握。

3D游戏引擎系列十一相关推荐

  1. 3D游戏引擎系列十二

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  2. 火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第二节:Cocos引擎开发环境搭建与项目创建!

    <使用Cocos2d-x 开发3D游戏>系列在线课程 第二节:Cocos引擎开发环境搭建与项目创建! 视频地址:http://edu.csdn.net/course/detail/1330 ...

  3. 3D游戏引擎剖析【较全面】

    转自:http://blog.csdn.net/is01sjjj/article/details/430125 第1部分: 游戏引擎介绍, 渲染和构造3D世界 介绍 自Doom游戏时代以来我们已经走了 ...

  4. 转:3D游戏引擎技术剖析

     转自 http://blog.csdn.net/jbjwpzyl3611421/article/details/12681047 3D游戏引擎技术剖析 分类: Unity3D2013-10-13 1 ...

  5. 3D游戏引擎底层数据结构的封装之Array

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  6. 从DOOM到CE3 20年3D游戏引擎发展史漫谈

    代表游戏:毁灭公爵3D(Duke Nukem 3D).猎鹿人(Redneck Deer Hunting).血祭 (Blood)代表游戏:上古卷轴:战斗尖顶(The Elder Scrolls:Batt ...

  7. 从《Doom》到《Dunia》 回顾3D游戏引擎发展历程二

    Quake III / id Tech 3 就像AMD与Intel,Nvidia与ATI,10年前,游戏引擎的战争主要集中在Quake III(现在被称为id Tech 3)与Unreal之间. 顾名 ...

  8. 【直播预告】7月18日3D游戏引擎免费公开课答疑,參与送C币!

    喜讯喜讯! 为了酬谢广大学员.CSDN学院特推出iOS和3D游戏引擎开发免费技术答疑公开课,让您度过一个充实的暑假~ 參与本次公开课,即有机会获得50C币! 答疑公开课时间:7月18日 晚7:30-9 ...

  9. 提炼游戏引擎系列:开篇介绍

    前言 大家好!本系列记录了从炸弹人游戏中提炼2D游戏引擎YEngine2D雏形的实战过程,您可以通过本系列了解到引擎提炼的思想.引擎的设计以及引擎是如何从游戏中提炼的,学习引擎开发的知识.希望对您能有 ...

最新文章

  1. 火热物联网下,中国传感器的冷思考
  2. C#面向集合的扩展(讨论)
  3. easyUI的combobox选中无法显示
  4. 一条消息未发,粉丝已破千万
  5. icon 做成html形式,一段生成iconfont预览html的代码
  6. 原生mysql启动_单实例MySQL的启动和关闭的方法
  7. 「管理数学基础」1.5 矩阵理论:方阵的行列式因子、不变因子、初等因子
  8. 获取当前时间getDate()注意点
  9. Web前端第三季(JavaScript):十一:第3章: 字符串和对象:309-如何创建对象+310-如何创建构造函数+311-给对象添加普通函数和对象属性的遍历
  10. CBLUE: A Chinese Biomedical LanguageUnderstanding Evaluation Benchmark
  11. 2022年最新京东滑块验证码破解思路(算法过验)
  12. USB Host、USB Device和USB otg的理论简析
  13. 经典歌曲多版本欣赏:刘欢《情怨》:华夏元素鲜明的“中国风格“
  14. 在Linux Mint 19.2 XFCE(x64)中安装Canon LBP2900+打印机驱动程序
  15. 微信id修改服务器繁忙,微信终于可以修改ID了! 但,你可能不行......
  16. 计算机会议论文EI检索,ei检索会议论文算期刊_ei论文检索_ei会议论文算核心吗...
  17. Springboot旧教材交易系统a6151计算机毕业设计-课程设计-期末作业-毕设程序代做
  18. GNU Radio教程1
  19. SSM整合ActiveMQ
  20. 离散数学复习:命题逻辑

热门文章

  1. NYOJ_170聪明的kk
  2. 深度学习常规概念(持续更新)
  3. 【PhotoShop】利用PS制作唯美咖啡泡
  4. android 耳机孔 红外,手机遥控器,3.5mm耳机接口红外遥控改造解析
  5. K9F1G08U0D Nand芯片
  6. 计算机物联网前沿技术汇总
  7. 2020年机修钳工(技师)考试题库及机修钳工(技师)免费试题
  8. 博导谈寒门子弟上大学:要相信双一流大学没有“废物”
  9. ​创新不是公司的救命良药
  10. 浅谈微信营销的价值与优势