游戏蛮牛学习群(纯技术交流,不闲聊):959392658
游戏蛮牛 手机端
开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:2371

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 920|回复: 5

[韩宇飞] 后期处理实现高亮描边

[复制链接]  [移动端链接]
3偶尔光临
281/300
排名
14627
昨日变化
8

32

主题

39

帖子

281

积分

Rank: 3Rank: 3Rank: 3

UID
67815
好友
8
蛮牛币
1009
威望
0
注册时间
2015-1-12
在线时间
86 小时
最后登录
2018-10-1

专栏作家

QQ
发表于 2018-10-1 21:58:57 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本文首发于知乎专栏:MACK的游戏开发笔记,欢迎各位关注。

因为项目需要希望实现gao'liang'b高亮描边的效果,一开始先尝试了火炬之光使用的光照的高亮描边。就是计算法线和Camera的夹角来计算光照,越靠近边缘的地方法线和Camera夹角越大顶点越亮。但是感觉效果不好,正好当时星际2发布了,里面的后期处理描边效果非常好,原理也不复杂因此也在项目中实现了一下。
原理很简单,在RT上渲染出人物的片,然后通过高斯模糊进行模糊和扩散,然后再通过模板挖空留下边的效果,最后在和正常渲染结果的RT叠加。原理如下:
未命名图片.png
暗黑3以及轩辕的后处理描边效果  
111.jpg 222.png

高亮描边流程:
1.在场景物件的渲染阶段,渲染并写入高亮物体的模版值到高亮效果的输入RT上。

  • 首先在渲染角色前,打开后期处理高亮描边并将高亮物体设置不渲染,这么做是因为写模版值时需要考虑深度,如果被其他人物遮挡的部分则不能写入模版值


  • 然后在角色物体全部渲染完后,,添加模版写入属性(CStencilPropertySwaper)并渲染高亮物体,其中特效和半透明物件不加模版写入属性不描边。伪代码如下:
m_pkStencilProperty->SetStencilOn(TRUE);
m_pkStencilProperty->SetStencilFunction(TEST_ALWAYS);
m_pkStencilProperty->SetStencilPassAction(ACTION_REPLACE);
m_pkStencilProperty->SetStencilFailAction(ACTION_KEEP);
m_pkStencilProperty->SetStencilPassZFailAction(ACTION_KEEP);
m_pkStencilProperty->SetStencilReference(0x1);


  • 最后还原高亮物体的模版属性

2.在后期处理阶段,拷贝模版缓冲,并完成后期处理描边,通过宏DEVIATION可以调整扩散范围,也就是粗细,越小越细,MULTIPLITER可以调整模糊程度,越小越不模糊

  • 复制深度模版缓冲,为了使用抗拒齿渲染场景时必须使用默认RT,所以要拷贝默认的模版缓冲
pktDefaultDepthStencilBuffer->Copy(m_pkTargets[RRT_FULL_1]->GetRenderTargetGroup()->GetDepthStencilBuffer(),NULL, NULL, COPY_FILTER_LINEAR);


  • 使用输入RT的深度模版缓冲绘制描边色RT,渲染到RRT_FULL_1(正常大小),结果就是人物形状的片。伪代码如下:
StencilEnable= true;
StencilFunc= equal;
StencilRef= 0x1;
StencilPass = keep;

//-------------------------------------------------------------------------
//Pixel Shader: PS_HighLightObject
//Desc: 填充高亮颜色.
//-------------------------------------------------------------------------
float4PS_HighLightObject() : COLOR
{
    returnfloat4(0.7f, 0.7f, 0.5f, 0.0f);
}


  • 降采样,渲染到RRT_DOWN_0,主要是为了优化,对1/4大小RT模糊。伪代码如下:
//-------------------------------------------------------------------------
//Pixel Shader: PS_DownFilter
//Desc: Perform a high-pass filter and on the source texture and scale down.
//-------------------------------------------------------------------------
float4PS_DownFilter(in float2 _f2Tex : TEXCOORD0) : COLOR0
{
    float4f4Color = 0;

    for(int i = 0; i < 16; i++)
  {
      f4Color +=tex2D(g_BaseTexutre, _f2Tex + TexelCoordsDownFilter.xy);
  }

  return f4Color / 16;
}


  • 混合采样16遍第张贴图(横向高斯模糊),使用模版测试渲染到RRT_DOWN_1,结果就是挖掉人物部分只剩轮廓边的贴图。伪代码如下:
//-------------------------------------------------------------------------
//Pixel Shader: Bloom
//Desc: Blur the source image along one axis using a gaussian
//       distribution. Since gaussian blurs areseparable, this shader is
//       called twice; first along the horizontalaxis, then along the
//       vertical axis.
//-------------------------------------------------------------------------
float4Bloom(in float2 kScreenPosition : TEXCOORD0) : COLOR
{
    float4 kSample = 0.0f;
    float4 kColor = 0.0f;

    float2 kSamplePosition;

    // Perform a one-directional gaussian blur
    for (int iSample = 0; iSample < 15;iSample++)
    {
        kSamplePosition = kScreenPosition +gakSampleOffsets[iSample];
        kColor = tex2D(BasePointClampSampler,kSamplePosition);
        kSample += gakSampleWeights[iSample] *kColor;
    }

    return kSample;
}


  • 混合采样16遍第张贴图(横向高斯模糊),使用模版测试渲染回RRT_DOWN_0,结果就是挖掉人物部分只剩轮廓边的贴图


  • 升采样,渲染到RRT_FULL_1,还原正常大小并挖去中间轮廓只剩下边。伪代码如下:
  • StencilEnable = true;
StencilFunc= notequal;
StencilRef= 0x1;
StencilPass = keep;

//-------------------------------------------------------------------------
//Pixel Shader: PS_UpFilter
//Desc: Perform a high-pass filter and on the source texture and scale down.
//-------------------------------------------------------------------------
float4PS_UpFilter(in float2 _f2Tex : TEXCOORD0) : COLOR
{
    float4f4Color =  tex2D(g_BaseTexutre, _f2Tex);

    returnf4Color;
}


  • 最后采样第0张贴图(后期处理的输入,就是最终渲染结果)和采样第1张贴图(边),然后混合相加,渲染到最终RenderTarget,就是带边的场景了。伪代码如下:
//-------------------------------------------------------------------------
//Pixel Shader: PS_HighLightBlend
//Desc: 在最终渲染结果上添加描边.
//-------------------------------------------------------------------------
float4PS_HighLightBlend(in float2 _f2Tex : TEXCOORD0) : COLOR
{
    float4f4Color1 = tex2D(g_BaseTexutre, _f2Tex);
    float4f4Color2 = tex2D(g_ShaderTexure, _f2Tex);

    returnf4Color1 + f4Color2;
}

虽然功能很快实现了,但是真正应用的时候还是花了一些时间优化和遇到很多问题。

  • 开启抗锯齿之后深度缓冲不能共享导致的问题。通过使用StretchRect来拷贝DepthStencilBuffer,来解决开了AA之后描边的问题。伪代码如下:
LPDIRECT3DSURFACE9 lpBackSurfaceSx9 = NULL;
HRESULT hr =lpDevice9->GetDepthStencilSurface(&lpBackSurfaceSx9);
lpDevice9->StretchRect( lpBackSurfaceSx9, NULL,((NiDX92DBufferData*)m_spDepthStencilBuffer->GetRendererData())->GetSurface(),NULL, D3DTEXF_LINEAR );

  • 实现了多种颜色描边,并解决了多种颜色描边在不同电脑上显示不连续等bug
  • 偶现描边导致屏幕变白的BUG。因为在没有描边物体时跳过描边物体渲染流程,但这个判断加在了判断是否打开描边后期处理的流程之前。所以虽然关闭了描边物体的渲染流程但是没有关闭描边的后期处理流程。当游戏正好在描边状态时,系统自动降低配置关闭描边效果后,会导致后期处理无限循环扩大,也就是边界无限扩大。通过在判断没有描边物体中断描边物体的渲染流程时同时也关闭描边的后期处理流程解决
  • 描边闪烁因为是beginrendertarget放到了BeginOffscreen之前了,应该放在之间
  • Alphatest的问题,这是因为xx渲染颜色时写入模版值的这个时候因为要用alpha做暗边所以没有考虑alphatest。最终的方案是先话正常物件,再画高亮物件同时写模版值,最后再画一遍写颜色值这时不通过深度比较而是通过模版值比较因为多重采样的情况下因为z精度的问题边会乱
  • 在设置模版采样之后必须要还原渲染状态否则自己写的Shader会一直开启Stencil
  • 因为在copy深度模版缓冲之后清空了Zbuf,在有的电脑上会连Stencil一起清掉。最终解决的办法是在去掉情况zbuf,在渲染不通描边物体颜色时不使用copy不精确的z多重采样zcopy会不精确,关掉画颜色时ztestzwrite)而是使用模版比较(模版值没有小数问题)
  • 解决了描边时设备丢失崩溃的问题。这是因为设备丢失时copy深度buff导致通过在设备丢失时关闭后期处理在设备丢失好以后打开后期处理解决





回复

使用道具 举报

7日久生情
1563/5000
排名
1453
昨日变化
6

0

主题

457

帖子

1563

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
87577
好友
0
蛮牛币
5291
威望
0
注册时间
2015-3-31
在线时间
266 小时
最后登录
2018-12-11
发表于 2018-10-6 14:52:58 | 显示全部楼层
too good too strong!
[发帖际遇]: blastblade 在网吧通宵,花了 3 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1210/1500
排名
2490
昨日变化
5

0

主题

300

帖子

1210

积分

Rank: 6Rank: 6Rank: 6

UID
119648
好友
3
蛮牛币
1702
威望
0
注册时间
2015-8-25
在线时间
352 小时
最后登录
2018-12-11
QQ
发表于 2018-10-8 09:11:55 | 显示全部楼层
too good too strong!

回复 支持 反对

使用道具 举报

4四处流浪
484/500
排名
17804
昨日变化
5

1

主题

184

帖子

484

积分

Rank: 4

UID
213085
好友
5
蛮牛币
343
威望
0
注册时间
2017-3-20
在线时间
265 小时
最后登录
2018-12-10
发表于 2018-10-8 09:12:37 | 显示全部楼层
正好需要  谢谢

回复 支持 反对

使用道具 举报

7日久生情
1647/5000
排名
2350
昨日变化
10

16

主题

654

帖子

1647

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
214924
好友
3
蛮牛币
4776
威望
0
注册时间
2017-3-28
在线时间
389 小时
最后登录
2018-12-11
发表于 2018-10-8 09:13:21 | 显示全部楼层
strong到害怕

回复

使用道具 举报

3偶尔光临
267/300
排名
9509
昨日变化
88

4

主题

68

帖子

267

积分

Rank: 3Rank: 3Rank: 3

UID
279482
好友
1
蛮牛币
82
威望
0
注册时间
2018-5-1
在线时间
81 小时
最后登录
2018-12-10
发表于 2018-10-8 10:31:36 | 显示全部楼层

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表