whoimi

A geek blog

View on GitHub

#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
  }
}