浏览代码

Update forward only mechanism

Before we have ForwardOpaqueOnly and ForwardOpaqueDepthOnly and they
were required to be both present at the same time in sahder with regular
pass. Now pass are exclusive:

Guidelines: In deferred by default there is no opaque in forward.
However it is possible to force an opaque material to render in
forward
by using the pass "ForwardOnly". In this case the .shader should
not have "Forward" but only a "ForwardOnly" pass.
It must also have a
"DepthForwardOnly" and no "DepthOnly" pass as forward material (either
deferred or forward only rendering) have always a depth pass.
/stochastic_alpha_test
Sebastien Lagarde 7 年前
当前提交
6dd42b8c
共有 6 个文件被更改,包括 84 次插入138 次删除
  1. 100
      ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  2. 12
      ScriptableRenderPipeline/HDRenderPipeline/HDStringConstants.cs
  3. 8
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
  4. 4
      ScriptableRenderPipeline/HDRenderPipeline/Material/Material.hlsl
  5. 18
      ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Editor/BaseUnlitUI.cs
  6. 80
      ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Unlit.shader

100
ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


RenderTargetIdentifier m_HTileRT;
// The pass "SRPDefaultUnlit" is a fallback to legacy unlit rendering and is required to support unity 2d + unity UI that render in the scene.
ShaderPassName[] m_ForwardPassNames = { new ShaderPassName(), HDShaderPassNames.s_SRPDefaultUnlitName};
ShaderPassName[] m_ForwardAndForwardOnlyPassNames = { new ShaderPassName(), new ShaderPassName(), HDShaderPassNames.s_SRPDefaultUnlitName};
ShaderPassName[] m_ForwardOnlyPassNames = { new ShaderPassName(), HDShaderPassNames.s_SRPDefaultUnlitName};
ShaderPassName[] m_DepthOnlyAndDepthForwardOnlyPassNames = { HDShaderPassNames.s_DepthForwardOnlyName, HDShaderPassNames.s_DepthOnlyName };
ShaderPassName[] m_DepthForwardOnlyPassNames = { HDShaderPassNames.s_DepthForwardOnlyName };
ShaderPassName[] m_DepthOnlyPassNames = { HDShaderPassNames.s_DepthOnlyName };
ShaderPassName[] m_ForwardErrorPassNames = { HDShaderPassNames.s_AlwaysName, HDShaderPassNames.s_ForwardBaseName, HDShaderPassNames.s_DeferredName, HDShaderPassNames.s_PrepassBaseName, HDShaderPassNames.s_VertexName, HDShaderPassNames.s_VertexLMRGBMName, HDShaderPassNames.s_VertexLMName };
ShaderPassName[] m_SinglePassName = new ShaderPassName[1];

// RenderDepthPrepass render both opaque and opaque alpha tested based on engine configuration.
// Forward only renderer: We always render everything
// Deferred renderer: We render a depth prepass only if engine request it. We can decide if we render everything or only opaque alpha tested object.
// Forward opaque with deferred renderer (ForwardOnlyOpaqueDepthOnly pass): We always render everything
// Forward opaque with deferred renderer (DepthForwardOnly pass): We always render everything
// Guidelines: To be able to switch from deferred to forward renderer we need to have forward opaque material with both DepthOnly and ForwardOnlyOpaqueDepthOnly pass.
// This is also required if we want to support optional depth prepass dynamically.
// This is what is assume here. But users may want to reduce number of shader combination once they have made their choice.
// In case of deferred renderer, we can have forward opaque material. These materials need to be render in the depth buffer to correctly build the light list.
// And they will tag the stencil to not be lit during the deferred lighting pass.
// In case of forward only renderer we have a depth prepass. In case of deferred renderer, it is optional
bool addDepthPrepass = m_Asset.renderingSettings.ShouldUseForwardRenderingOnly() || m_Asset.renderingSettings.useDepthPrepassWithDeferredRendering;
// In case of deferred renderer, we can have forward opaque material. These materials need to be render in the depth buffer to correctly build the light list. And they will tag the stencil to not be lit during the deferred lighting pass.
// Caution: If a DepthPrepass is enabled for deferred then the object will be rendered with the pass DepthPrepass. See guidelines. This allow to switch dynamically between both mode.
// So we don't need to render the ForwardOnlyOpaqueDepthOnly pass
// Note that an object can't be in both list
bool addForwardOnlyOpaqueDepthPrepass = !m_Asset.renderingSettings.ShouldUseForwardRenderingOnly() && !m_Asset.renderingSettings.useDepthPrepassWithDeferredRendering;
// Guidelines: In deferred by default there is no opaque in forward. However it is possible to force an opaque material to render in forward
// by using the pass "ForwardOnly". In this case the .shader should not have "Forward" but only a "ForwardOnly" pass.
// It must also have a "DepthForwardOnly" and no "DepthOnly" pass as forward material (either deferred or forward only rendering) have always a depth pass.
if (addDepthPrepass == false && addForwardOnlyOpaqueDepthPrepass == false)
return;
// In case of forward only rendering we have a depth prepass. In case of deferred renderer, it is optional
bool addFullDepthPrepass = m_Asset.renderingSettings.ShouldUseForwardRenderingOnly() || m_Asset.renderingSettings.useDepthPrepassWithDeferredRendering;
bool addAlphaTestedOnly = !m_Asset.renderingSettings.ShouldUseForwardRenderingOnly() && m_Asset.renderingSettings.useDepthPrepassWithDeferredRendering && m_Asset.renderingSettings.renderAlphaTestOnlyInDeferredPrepass;
using (new ProfilingSample(cmd, addDepthPrepass ? "Depth Prepass" : "Depth Prepass forward opaque"))
using (new ProfilingSample(cmd, addAlphaTestedOnly ? "Depth Prepass alpha test" : "Depth Prepass"))
// Default depth prepass (forward and deferred) will render all opaque geometry.
var renderQueueRange = RenderQueueRange.opaque;
// If we want only alpha tested geometry in prepass for deferred we change the RenderQueueRange
if (!m_Asset.renderingSettings.ShouldUseForwardRenderingOnly() && m_Asset.renderingSettings.useDepthPrepassWithDeferredRendering && m_Asset.renderingSettings.renderAlphaTestOnlyInDeferredPrepass)
renderQueueRange = new RenderQueueRange { min = (int)RenderQueue.AlphaTest, max = (int)RenderQueue.GeometryLast - 1 };
// We render first the opaque object as opaque alpha tested are more costly to render and could be reject by early-z (but not Hi-z as it is disable with clip instruction)
// This is handeled automatically with the RenderQueue value (OpaqueAlphaTested have a different value and thus are sorted after Opaque)
// Note: addDepthPrepass and addForwardOnlyOpaqueDepthPrepass can't be both true at the same time. And if we are here both are not false
RenderOpaqueRenderList(cull, camera, renderContext, cmd, addDepthPrepass ? HDShaderPassNames.s_DepthOnlyName : HDShaderPassNames.s_ForwardOnlyOpaqueDepthOnlyName, 0, renderQueueRange);
if (addFullDepthPrepass && !addAlphaTestedOnly) // Always true in case of forward rendering, use in case of deferred rendering if requesting a full depth prepass
{
// We render first the opaque object as opaque alpha tested are more costly to render and could be reject by early-z (but not Hi-z as it is disable with clip instruction)
// This is handled automatically with the RenderQueue value (OpaqueAlphaTested have a different value and thus are sorted after Opaque)
RenderOpaqueRenderList(cull, camera, renderContext, cmd, m_DepthOnlyAndDepthForwardOnlyPassNames, 0, RenderQueueRange.opaque);
}
else // Deferred rendering with partial depth prepass
{
// We always do a DepthForwardOnly pass with all the opaque (including alpha test)
RenderOpaqueRenderList(cull, camera, renderContext, cmd, m_DepthForwardOnlyPassNames, 0, RenderQueueRange.opaque);
// Render Alpha test only if requested
if (addAlphaTestedOnly)
{
var renderQueueRange = new RenderQueueRange { min = (int)RenderQueue.AlphaTest, max = (int)RenderQueue.GeometryLast - 1 };
RenderOpaqueRenderList(cull, camera, renderContext, cmd, m_DepthOnlyPassNames, 0, renderQueueRange);
}
}
}
}

// Render forward is use for both transparent and opaque objects. In case of deferred we can still render opaque object in forward.
void RenderForward(CullResults cullResults, Camera camera, ScriptableRenderContext renderContext, CommandBuffer cmd, bool renderOpaque)
{
// Guidelines: To be able to switch from deferred to forward renderer we need to have forward opaque material with both Forward and ForwardOnlyOpaque pass.
// This is what is assume here. But users may want to reduce number of shader combination once they have made their choice.
// If we are transparent, we add the forward pass. Else (Render Opaque) we add it only if we are forward rendering
bool addForwardPass = !renderOpaque || m_Asset.renderingSettings.ShouldUseForwardRenderingOnly();
// Guidelines: In deferred by default there is no opaque in forward. However it is possible to force an opaque material to render in forward
// by using the pass "ForwardOnly". In this case the .shader should not have "Forward" but only a "ForwardOnly" pass.
// It must also have a "DepthForwardOnly" and no "DepthOnly" pass as forward material (either deferred or forward only rendering) have always a depth pass.
// The RenderForward pass will render the appropriate pass depends on the engine settings. In case of forward only rendering, both "Forward" pass and "ForwardOnly" pass
// material will be render for both transparent and opaque. In case of deferred, both path are used for transparent but only "ForwardOnly" is use for opaque.
// (Thus why "Forward" and "ForwardOnly" are exclusive, else they will render two times"
// In case of deferred we can still have forward opaque object
// It mean that addForwardOnlyOpaquePass = !addForwardPass which is a simplification of: renderOpaque && !m_Asset.renderingSettings.ShouldUseForwardRenderingOnly()
// There is no need to store this case as we don't need to test for it
ShaderPassName passName;
passName = addForwardPass ? HDShaderPassNames.s_ForwardDebugDisplayName : HDShaderPassNames.s_ForwardOnlyOpaqueDebugDisplayName;
profileName = addForwardPass ? (renderOpaque ? "Forward Opaque Debug Display" : "Forward Transparent Debug Display") : "ForwardOnlyOpaqueDebugDisplay";
profileName = renderOpaque ? "Forward Opaque Debug Display" : "Forward Transparent Debug Display";
passName = addForwardPass ? HDShaderPassNames.s_ForwardName : HDShaderPassNames.s_ForwardOnlyOpaqueName;
profileName = addForwardPass ? (renderOpaque ? "Forward Opaque" : "Forward Transparent") : "Forward Only Opaque";
profileName = renderOpaque ? "Forward Opaque" : "Forward Transparent";
}
using (new ProfilingSample(cmd, profileName))

m_LightLoop.RenderForward(camera, cmd, renderOpaque);
m_ForwardPassNames[0] = passName;
if (m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled())
{
m_ForwardAndForwardOnlyPassNames[0] = m_ForwardOnlyPassNames[0] = HDShaderPassNames.s_ForwardOnlyDebugDisplayName;
m_ForwardAndForwardOnlyPassNames[1] = HDShaderPassNames.s_ForwardDebugDisplayName;
}
else
{
m_ForwardAndForwardOnlyPassNames[0] = m_ForwardOnlyPassNames[0] = HDShaderPassNames.s_ForwardOnlyName;
m_ForwardAndForwardOnlyPassNames[1] = HDShaderPassNames.s_ForwardName;
}
// Forward opaque material always have a prepass (whether or not we use deferred) so we pass the right depth state here.
RenderOpaqueRenderList(cullResults, camera, renderContext, cmd, m_ForwardPassNames, HDUtils.k_RendererConfigurationBakedLighting, null, m_DepthStateOpaqueWithPrepass);
var passNames = m_Asset.renderingSettings.ShouldUseForwardRenderingOnly() ? m_ForwardAndForwardOnlyPassNames : m_ForwardOnlyPassNames;
// Forward opaque material always have a prepass (whether or not we use deferred, whether or not there is option like alpha test only) so we pass the right depth state here.
RenderOpaqueRenderList(cullResults, camera, renderContext, cmd, passNames, HDUtils.k_RendererConfigurationBakedLighting, null, m_DepthStateOpaqueWithPrepass);
RenderTransparentRenderList(cullResults, camera, renderContext, cmd, m_ForwardPassNames, HDUtils.k_RendererConfigurationBakedLighting);
RenderTransparentRenderList(cullResults, camera, renderContext, cmd, m_ForwardAndForwardOnlyPassNames, HDUtils.k_RendererConfigurationBakedLighting);
}
}
}

12
ScriptableRenderPipeline/HDRenderPipeline/HDStringConstants.cs


public static readonly string s_ForwardStr = "Forward";
public static readonly string s_ForwardDebugDisplayStr = "ForwardDebugDisplay";
public static readonly string s_DepthOnlyStr = "DepthOnly";
public static readonly string s_ForwardOnlyOpaqueDepthOnlyStr = "ForwardOnlyOpaqueDepthOnly";
public static readonly string s_ForwardOnlyOpaqueStr = "ForwardOnlyOpaque";
public static readonly string s_ForwardOnlyOpaqueDebugDisplayStr = "ForwardOnlyOpaqueDebugDisplay";
public static readonly string s_DepthForwardOnlyStr = "DepthForwardOnly";
public static readonly string s_ForwardOnlyStr = "ForwardOnly";
public static readonly string s_ForwardOnlyDebugDisplayStr = "ForwardOnlyDebugDisplay";
public static readonly string s_GBufferStr = "GBuffer";
public static readonly string s_GBufferWithPrepassStr = "GBufferWithPrepass";
public static readonly string s_GBufferDebugDisplayStr = "GBufferDebugDisplay";

public static readonly ShaderPassName s_ForwardName = new ShaderPassName(s_ForwardStr);
public static readonly ShaderPassName s_ForwardDebugDisplayName = new ShaderPassName(s_ForwardDebugDisplayStr);
public static readonly ShaderPassName s_DepthOnlyName = new ShaderPassName(s_DepthOnlyStr);
public static readonly ShaderPassName s_ForwardOnlyOpaqueDepthOnlyName = new ShaderPassName(s_ForwardOnlyOpaqueDepthOnlyStr);
public static readonly ShaderPassName s_ForwardOnlyOpaqueName = new ShaderPassName(s_ForwardOnlyOpaqueStr);
public static readonly ShaderPassName s_ForwardOnlyOpaqueDebugDisplayName = new ShaderPassName(s_ForwardOnlyOpaqueDebugDisplayStr);
public static readonly ShaderPassName s_DepthForwardOnlyName = new ShaderPassName(s_DepthForwardOnlyStr);
public static readonly ShaderPassName s_ForwardOnlyName = new ShaderPassName(s_ForwardOnlyStr);
public static readonly ShaderPassName s_ForwardOnlyDebugDisplayName = new ShaderPassName(s_ForwardOnlyDebugDisplayStr);
public static readonly ShaderPassName s_GBufferName = new ShaderPassName(s_GBufferStr);
public static readonly ShaderPassName s_GBufferWithPrepassName = new ShaderPassName(s_GBufferWithPrepassStr);
public static readonly ShaderPassName s_GBufferDebugDisplayName = new ShaderPassName(s_GBufferDebugDisplayStr);

8
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl


{
// For Deferred:
// If we have a prepass, we need to remove the clip from the GBuffer pass (otherwise HiZ does not work on PS4)
// For Forward (Full forward or ForwardOnlyOpaque in deferred):
// For Forward
#if ((SHADER_PASS == SHADERPASS_GBUFFER) && !defined(_BYPASS_ALPHA_TEST)) || (SHADER_PASS == SHADERPASS_FORWARD && defined(SURFACE_TYPE_TRANSPARENT))
clip(alpha - alphaCutoff);
#endif
#if !(SHADER_PASS == SHADERPASS_FORWARD && defined(SURFACE_TYPE_OPAQUE)) && !(SHADER_PASS == SHADERPASS_GBUFFER && defined(_BYPASS_ALPHA_TEST))
clip(alpha - alphaCutoff);
#endif
}
// TODO: move this function to commonLighting.hlsl once validated it work correctly

4
ScriptableRenderPipeline/HDRenderPipeline/Material/Material.hlsl


//-----------------------------------------------------------------------------
// This should match the possible blending modes in any material .shader file (lit/layeredlit/unlit etc)
#if defined(_BLENDMODE_LERP) || defined(_BLENDMODE_ADD) || defined(_BLENDMODE_SOFT_ADD) || defined(_BLENDMODE_MULTIPLY) || defined(_BLENDMODE_PRE_MULTIPLY)
# define SURFACE_TYPE_TRANSPARENT
#define SURFACE_TYPE_TRANSPARENT
# define SURFACE_TYPE_OPAQUE
#define SURFACE_TYPE_OPAQUE
#endif
//-----------------------------------------------------------------------------

18
ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Editor/BaseUnlitUI.cs


public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
public static GUIContent alphaCutoffShadowText = new GUIContent("Alpha Cutoff Shadow", "Threshold for alpha cutoff in case of shadow pass");
public static GUIContent alphaCutoffPrepassText = new GUIContent("Alpha Cutoff Prepass", "Threshold for alpha cutoff in case of depth prepass");
public static GUIContent transparentDepthPrepassEnableText = new GUIContent("Enable transparent depth prepass", "It allow to ");
public static GUIContent transparentDepthPrepassEnableText = new GUIContent("Enable transparent depth prepass", "It allow to ");
public static GUIContent distortionEnableText = new GUIContent("Distortion", "Enable distortion on this shader");
public static GUIContent distortionEnableText = new GUIContent("Distortion", "Enable distortion on this shader");
public static GUIContent distortionVectorMapText = new GUIContent("Distortion Vector Map - Dist(RG) Blur(B)", "Vector Map for the distorsion - Dist(RG) Blur(B)");
public static GUIContent distortionBlendModeText = new GUIContent("Distortion Blend Mode", "Distortion Blend Mode");
public static GUIContent distortionVectorMapText = new GUIContent("Distortion Vector Map - Dist(RG) Blur(B)", "Vector Map for the distorsion - Dist(RG) Blur(B)");
public static GUIContent distortionBlendModeText = new GUIContent("Distortion Blend Mode", "Distortion Blend Mode");
public static GUIContent distortionScaleText = new GUIContent("Distortion Scale", "Distortion Scale");
public static GUIContent distortionBlurScaleText = new GUIContent("Distortion Blur Scale", "Distortion Blur Scale");
public static GUIContent distortionBlurRemappingText = new GUIContent("Distortion Blur Remapping", "Distortion Blur Remapping");

SetKeyword(material, "_ALPHATEST_ON", alphaTestEnable);
if (material.HasProperty(kDistortionEnable))
{
{
bool distortionDepthTest = material.GetFloat(kDistortionDepthTest) > 0.0f;
if (distortionDepthTest)
{

// If distortion only is enabled, disable all passes (except distortion and debug)
bool enablePass = !(distortionEnable && distortionOnly);
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardOnlyOpaqueDepthOnlyStr, enablePass);
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardOnlyOpaqueStr, enablePass);
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardOnlyOpaqueDebugDisplayStr, true);
material.SetShaderPassEnabled(HDShaderPassNames.s_DepthForwardOnlyStr, enablePass);
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardOnlyStr, enablePass);
material.SetShaderPassEnabled(HDShaderPassNames.s_ForwardOnlyDebugDisplayStr, true);
material.SetShaderPassEnabled(HDShaderPassNames.s_GBufferStr, enablePass);
material.SetShaderPassEnabled(HDShaderPassNames.s_GBufferWithPrepassStr, enablePass);
material.SetShaderPassEnabled(HDShaderPassNames.s_GBufferDebugDisplayStr, true);

80
ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Unlit.shader


ENDHLSL
}
Pass
{
Name "DepthOnly"
Tags{ "LightMode" = "DepthOnly" }
Cull[_CullMode]
ZWrite On
HLSLPROGRAM
#define SHADERPASS SHADERPASS_DEPTH_ONLY
#include "../../ShaderVariables.hlsl"
#include "../../Material/Material.hlsl"
#include "ShaderPass/UnlitDepthPass.hlsl"
#include "UnlitData.hlsl"
#include "../../ShaderPass/ShaderPassDepthOnly.hlsl"
ENDHLSL
}
// Unlit opaque material need to be render with ForwardOnlyOpaqueDepthOnly. Unlike Lit that can be both deferred and forward,
// unlit require to be forward only, that's why we need this pass.
// Also in case of forward rendering, unlit will use regular DepthOnly pass.
// (Code is exactly the same as "Forward", it simply allow our system to filter objects correctly)
// Unlit shader always render in forward
Name "ForwardOnlyOpaqueDepthOnly"
Tags{ "LightMode" = "ForwardOnlyOpaqueDepthOnly" }
Name ""
Tags{ "LightMode" = "DepthForwardOnly" }
Cull[_CullMode]

ENDHLSL
}
// Unlit shader always render in forward
Tags { "LightMode" = "Forward" }
Tags { "LightMode" = "ForwardOnly" }
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]

Pass
{
Name "ForwardDebugDisplay"
Tags { "LightMode" = "ForwardDebugDisplay" }
Tags { "LightMode" = "ForwardOnlyDebugDisplay" }
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]

#define DEBUG_DISPLAY
#define SHADERPASS SHADERPASS_FORWARD_UNLIT
#include "../../Debug/DebugDisplay.hlsl"
#include "../../Material/Material.hlsl"
#include "ShaderPass/UnlitSharePass.hlsl"
#include "UnlitData.hlsl"
#include "../../ShaderPass/ShaderPassForwardUnlit.hlsl"
ENDHLSL
}
// Unlit opaque material need to be render with ForwardOnlyOpaque. Unlike Lit that can be both deferred and forward,
// unlit require to be forward only, that's why we need this pass. Unlit transparent will use regular Forward pass
// Also in case of forward rendering, unlit will use regular forward pass too
// (Code is exactly the same as "Forward", it simply allow our system to filter objects correctly)
Pass
{
Name "ForwardUnlit"
Tags { "LightMode" = "ForwardOnlyOpaque" }
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]
Cull [_CullMode]
HLSLPROGRAM
#define SHADERPASS SHADERPASS_FORWARD_UNLIT
#include "../../Material/Material.hlsl"
#include "ShaderPass/UnlitSharePass.hlsl"
#include "UnlitData.hlsl"
#include "../../ShaderPass/ShaderPassForwardUnlit.hlsl"
ENDHLSL
}
Pass
{
Name "ForwardUnlit"
Tags { "LightMode" = "ForwardOnlyOpaqueDebugDisplay" }
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]
Cull [_CullMode]
HLSLPROGRAM
#define SHADERPASS SHADERPASS_FORWARD_UNLIT
#include "../../Debug/DebugDisplay.hlsl"
#include "../../Material/Material.hlsl"

正在加载...
取消
保存