#HDRP Decal
Unity提供了贴花功能,现在能够控制Decal具体要投射到哪些物体上。。
Decal 渲染最开始需要一个深度图:
需要透视Decal的物体会渲染
m_DepthOnlyPassNames :渲染深度
m_DepthForwardOnlyPassNames:渲染法线
Decal需要进行可以进行异步剪裁
if (hdCamera.frameSettings.enableDecals)
{
// decal system needs to be updated with current camera, it needs it to set up culling and light list generation parameters
DecalSystem.instance.CurrentCamera = camera;
DecalSystem.instance.BeginCull();
}
// 其他计算。
m_DbufferManager.enableDecals = false;
if (hdCamera.frameSettings.enableDecals)
{
using (new ProfilingSample(cmd, "DBufferPrepareDrawData", CustomSamplerId.DBufferPrepareDrawData.GetSampler()))
{
DecalSystem.instance.EndCull();
m_DbufferManager.enableDecals = true; // mesh decals are renderers managed by c++ runtime and we have no way to query if any are visible, so set to true
DecalSystem.instance.UpdateCachedMaterialData(); // textures, alpha or fade distances could've changed
DecalSystem.instance.CreateDrawData(); // prepare data is separate from draw
DecalSystem.instance.UpdateTextureAtlas(cmd); // as this is only used for transparent pass, would've been nice not to have to do this if no transparent renderers are visible, needs to happen after CreateDrawData
}
}
关于Dbuffer
如果没有Decals 则不需要Dbuffer,Decal是需要渲染到Dbuffer当中的,Dbuffer的结构类似Gbuffer.
下面是Dbuffer渲染代码:
void RenderDBuffer(HDCamera hdCamera, CommandBuffer cmd, ScriptableRenderContext renderContext, CullResults cullResults)
{
// 不需要Decals 则不需要Dbuffer
if (!hdCamera.frameSettings.enableDecals)
return;
// 深度信息 放入Depth Buffer(从 m_SharedRTManager.GetDepthStencilBuffer() => m_SharedRTManager.GetDepthTexture())
CopyDepthBufferIfNeeded(cmd);
bool rtCount4 = m_Asset.GetRenderPipelineSettings().decalSettings.perChannelMask;
// Depth texture is now ready, bind it.
// 设置全局纹理
cmd.SetGlobalTexture(HDShaderIDs._CameraDepthTexture, m_SharedRTManager.GetDepthTexture());
// 清理纹理设置成渲染目标,内部这只了多个渲染目标,m_SharedRTManager.GetDepthStencilBuffer()只是指定了深度用哪一个。
m_DbufferManager.ClearAndSetTargets(cmd, hdCamera, rtCount4, m_SharedRTManager.GetDepthStencilBuffer());
renderContext.ExecuteCommandBuffer(cmd);
// 这里cmd重置了
cmd.Clear();
DrawRendererSettings drawSettings = new DrawRendererSettings(hdCamera.camera, HDShaderPassNames.s_EmptyName)
{
rendererConfiguration = 0,
sorting = { flags = SortFlags.CommonOpaque }
};
// 渲染目标数量 决定渲染方式,即需要绘制的pass名字
if (rtCount4)
{
drawSettings.SetShaderPassName(0, HDShaderPassNames.s_MeshDecalsMName);
drawSettings.SetShaderPassName(1, HDShaderPassNames.s_MeshDecalsAOName);
drawSettings.SetShaderPassName(2, HDShaderPassNames.s_MeshDecalsMAOName);
drawSettings.SetShaderPassName(3, HDShaderPassNames.s_MeshDecalsSName);
drawSettings.SetShaderPassName(4, HDShaderPassNames.s_MeshDecalsMSName);
drawSettings.SetShaderPassName(5, HDShaderPassNames.s_MeshDecalsAOSName);
drawSettings.SetShaderPassName(6, HDShaderPassNames.s_MeshDecalsMAOSName);
}
else
{
drawSettings.SetShaderPassName(0, HDShaderPassNames.s_MeshDecals3RTName);
}
// 所有不透明物体
FilterRenderersSettings filterRenderersSettings = new FilterRenderersSettings(true)
{
renderQueueRange = HDRenderQueue.k_RenderQueue_AllOpaque
};
// 先绘制一次可见物体的decallpass,这个是说不用DecalProjector的方式的Decal? 经过测试这句话即使注释掉也没反应。
renderContext.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, filterRenderersSettings);
// 这里再用cmd绘制是直接绘制到屏幕上了,收集相同材质的Decal,使用Instance绘制Decal,Shader是Decal,Dbuffer 有多个渲染目标和深度
DecalSystem.instance.RenderIntoDBuffer(cmd);
m_DbufferManager.UnSetHTile(cmd);
m_DbufferManager.SetHTileTexture(cmd); // mask per 8x8 tile used for optimization when looking up dbuffer values
}
}