前言:
这段时间一直在处理项目中有关半透的问题,其中就遇到了,由于半透明混合的关系,导致角色在不同背景下颜色存在差异的问题。
仔细查看了下腿部使用URP内置的Lit.Shader,解决方法也比较简单,由于Lit.Shader默认为SrcAlpha,1-SrcAlpha的混合模式,因此只需要修改为SrcAlpha,Zero。
如果colorbuffer中的颜色我们都不需要是可以如上来处理背景混合问题,但。。。我的项目中美术需要在腿内部保留一个圆环,如下图所示:
因此无法使用上面的方法来解决该问题,稍微花些时间想了想:既然背景不能用来混合,那就创建一张RT颜色清空为纯0,用来写入color,圆环和半透都往这张RT写入,最后在和背景混合的时候:使用假设RT上存在像素不为0,则使用RT,否则使用背景色,那么问题就可以迎刃而解。
下面进入正式的编码:
创建一个RenderFeature,创建RT,并且将圆环和半透写入到这张RT中,最后混合输出到URP的ColorRT(管线部分比较简单,下面直接贴出pass内执行的部分)。
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
var sortFlags = SortingCriteria.CommonTransparent;
var drawSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortFlags);
var drawSettings_Opache = CreateDrawingSettings(m_ShaderTagIdList_Opache, ref renderingData, SortingCriteria.CommonOpaque);
var filterSettings = m_FilteringSettings_Transparent;
cmd.Clear();
cmd.SetRenderTarget(tempColor.id, m_depth);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
//渲染Opache Color
context.DrawRenderers(renderingData.cullResults, ref drawSettings_Opache, ref m_FilteringSettings_Opache, ref m_RenderStateBlock_Transparent);
cmd.Clear();
//渲染Transparent color
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref m_FilteringSettings_Transparent, ref m_RenderStateBlock_Transparent);
cmd.Clear();
cmd.SetGlobalTexture("_TranparentMain", m_color);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
Blit(cmd, tempColor.Identifier(), tempColor2.Identifier(), m_BlendMaterial);
Blit(cmd, tempColor2.Identifier(), m_color);
context.ExecuteCommandBuffer(cmd);
}
CommandBufferPool.Release(cmd);
}
解释:tempColor为那张RT,指定好LightMode,指定好需要渲染到RT的物件的layer(rendererQuality那边需要过滤该Layer),指定好RenderTarget为tempColor与DepthTexture(需要Depth是由于需要其用来参与深度写入与测试),调用Contex.DrawRenderers来渲染指定的物件,最后使用Blit混合后在Blit回ColorRT。
混合shader的Frag:
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
fixed4 mainColor = tex2D(_TranparentMain, i.uv);
fixed3 finnal;
if(col.a > 0)
{
finnal = col.a * col.rgb;
}
else
{
finnal = mainColor.rgb;
}
return fixed4(finnal, 1);
}
总结:
需要额外两张RT,以及开启CopyDepth(如果开启MSAA的话,URP7.7会需要执行prepass,由于关闭了相关layer,变成圆环未写入到prepass的RT中,这样其实会出问题,所以是需要MSAA是需要 稍微定制下prepass那块),内存开销还是比较大。