334 lines
11 KiB
C#
334 lines
11 KiB
C#
using XCEngine;
|
|
using XCEngine.Rendering;
|
|
|
|
namespace XCEngine.Rendering.Universal
|
|
{
|
|
public sealed class UniversalRenderer : ScriptableRenderer
|
|
{
|
|
private const string kMainLightShadowsKeyword =
|
|
"XC_MAIN_LIGHT_SHADOWS";
|
|
private readonly UniversalRendererData m_rendererData;
|
|
private readonly BuiltinFinalColorPass m_builtinFinalColorPass =
|
|
new BuiltinFinalColorPass();
|
|
private readonly DrawObjectsPass m_drawShadowCasterPass =
|
|
new DrawObjectsPass(
|
|
RenderPassEvent.BeforeRenderingShadows,
|
|
SceneRenderPhase.Opaque,
|
|
RendererListDesc.CreateDefault(
|
|
RendererListType.ShadowCaster));
|
|
private readonly DrawObjectsPass m_drawDepthPrepass =
|
|
new DrawObjectsPass(
|
|
RenderPassEvent.BeforeRenderingPrePasses,
|
|
SceneRenderPhase.Opaque,
|
|
RendererListDesc.CreateDefault(
|
|
RendererListType.Opaque));
|
|
private readonly DrawObjectsPass m_drawOpaqueObjectsPass =
|
|
new DrawObjectsPass(
|
|
RenderPassEvent.RenderOpaques,
|
|
SceneRenderPhase.Opaque,
|
|
RendererListDesc.CreateDefault(
|
|
RendererListType.Opaque));
|
|
private readonly DrawSkyboxPass m_drawSkyboxPass =
|
|
new DrawSkyboxPass();
|
|
private readonly DrawObjectsPass m_drawTransparentObjectsPass =
|
|
new DrawObjectsPass(
|
|
RenderPassEvent.RenderTransparents,
|
|
SceneRenderPhase.Transparent,
|
|
RendererListDesc.CreateDefault(
|
|
RendererListType.Transparent));
|
|
|
|
public UniversalRenderer(
|
|
UniversalRendererData rendererData)
|
|
{
|
|
m_rendererData =
|
|
rendererData ??
|
|
ScriptableObject
|
|
.CreateInstance<UniversalRendererData>() ??
|
|
new UniversalRendererData();
|
|
}
|
|
|
|
protected override void ConfigureCameraFramePlan(
|
|
ScriptableRenderPipelinePlanningContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ConfigureShadowCasterStage(
|
|
context,
|
|
m_rendererData.GetShadowCasterBlockInstance());
|
|
ConfigureDepthOnlyStage(
|
|
context,
|
|
m_rendererData.GetDepthPrepassBlockInstance());
|
|
}
|
|
|
|
protected override void FinalizeCameraFramePlan(
|
|
ScriptableRenderPipelinePlanningContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
base.FinalizeCameraFramePlan(context);
|
|
ConfigureFinalOutputStage(context);
|
|
}
|
|
|
|
protected override void ConfigureRenderSceneSetup(
|
|
RenderSceneSetupContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.SetEnvironmentNone();
|
|
context.ClearGlobalShaderKeywords();
|
|
|
|
Camera camera = context.camera;
|
|
if (ShouldUseSkyboxEnvironment(
|
|
context,
|
|
camera))
|
|
{
|
|
if (camera.hasSkyboxMaterial)
|
|
{
|
|
context.UseCameraSkyboxMaterial();
|
|
}
|
|
else
|
|
{
|
|
context.SetProceduralSkybox(
|
|
camera.skyboxTopColor,
|
|
camera.skyboxHorizonColor,
|
|
camera.skyboxBottomColor);
|
|
}
|
|
}
|
|
|
|
context.SetGlobalShaderKeyword(
|
|
kMainLightShadowsKeyword,
|
|
context.hasMainDirectionalShadow);
|
|
}
|
|
|
|
protected override void ConfigureDirectionalShadowExecutionState(
|
|
DirectionalShadowExecutionContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ShadowCasterBlockData shadowCaster =
|
|
m_rendererData.GetShadowCasterBlockInstance();
|
|
if (!context.hasPlannedMainDirectionalShadow ||
|
|
shadowCaster == null ||
|
|
!shadowCaster.enabled)
|
|
{
|
|
context.ClearDirectionalShadowExecution();
|
|
return;
|
|
}
|
|
|
|
context.UseDefaultMainDirectionalShadowExecution();
|
|
}
|
|
|
|
protected override void AddRenderPasses(
|
|
RenderingData renderingData)
|
|
{
|
|
if (renderingData == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UniversalMainSceneData mainScene =
|
|
m_rendererData.GetMainSceneInstance();
|
|
ShadowCasterBlockData shadowCaster =
|
|
m_rendererData.GetShadowCasterBlockInstance();
|
|
DepthPrepassBlockData depthPrepass =
|
|
m_rendererData.GetDepthPrepassBlockInstance();
|
|
|
|
if (shadowCaster.enabled)
|
|
{
|
|
EnqueueShadowCasterPasses(shadowCaster);
|
|
}
|
|
|
|
if (depthPrepass.enabled)
|
|
{
|
|
EnqueueDepthPrepass(depthPrepass);
|
|
}
|
|
|
|
if (mainScene.renderOpaque)
|
|
{
|
|
EnqueueOpaquePasses(mainScene);
|
|
}
|
|
|
|
if (mainScene.renderSkybox)
|
|
{
|
|
EnqueueSkyboxPasses(mainScene);
|
|
}
|
|
|
|
if (mainScene.renderTransparent)
|
|
{
|
|
EnqueueTransparentPasses(mainScene);
|
|
}
|
|
|
|
EnqueueFinalOutputPasses(renderingData);
|
|
}
|
|
|
|
private void EnqueueShadowCasterPasses(
|
|
ShadowCasterBlockData shadowCaster)
|
|
{
|
|
m_drawShadowCasterPass.Configure(
|
|
shadowCaster.passEvent,
|
|
SceneRenderPhase.Opaque,
|
|
shadowCaster.rendererListDesc,
|
|
shadowCaster.drawingSettings);
|
|
EnqueuePass(m_drawShadowCasterPass);
|
|
}
|
|
|
|
private void EnqueueDepthPrepass(
|
|
DepthPrepassBlockData depthPrepass)
|
|
{
|
|
m_drawDepthPrepass.Configure(
|
|
depthPrepass.passEvent,
|
|
SceneRenderPhase.Opaque,
|
|
depthPrepass.rendererListDesc,
|
|
depthPrepass.drawingSettings);
|
|
EnqueuePass(m_drawDepthPrepass);
|
|
}
|
|
|
|
private void EnqueueOpaquePasses(
|
|
UniversalMainSceneData mainScene)
|
|
{
|
|
m_drawOpaqueObjectsPass.Configure(
|
|
mainScene.opaquePassEvent,
|
|
SceneRenderPhase.Opaque,
|
|
mainScene.opaqueRendererListDesc,
|
|
mainScene.opaqueDrawingSettings);
|
|
EnqueuePass(m_drawOpaqueObjectsPass);
|
|
}
|
|
|
|
private void EnqueueSkyboxPasses(
|
|
UniversalMainSceneData mainScene)
|
|
{
|
|
m_drawSkyboxPass.Configure(
|
|
mainScene.skyboxPassEvent);
|
|
EnqueuePass(m_drawSkyboxPass);
|
|
}
|
|
|
|
private void EnqueueTransparentPasses(
|
|
UniversalMainSceneData mainScene)
|
|
{
|
|
m_drawTransparentObjectsPass.Configure(
|
|
mainScene.transparentPassEvent,
|
|
SceneRenderPhase.Transparent,
|
|
mainScene.transparentRendererListDesc,
|
|
mainScene.transparentDrawingSettings);
|
|
EnqueuePass(m_drawTransparentObjectsPass);
|
|
}
|
|
|
|
private static void ConfigureShadowCasterStage(
|
|
ScriptableRenderPipelinePlanningContext context,
|
|
ShadowCasterBlockData shadowCaster)
|
|
{
|
|
if (shadowCaster != null &&
|
|
shadowCaster.enabled)
|
|
{
|
|
context.RequestShadowCasterStage();
|
|
return;
|
|
}
|
|
|
|
context.ClearShadowCasterStage();
|
|
}
|
|
|
|
private static void ConfigureDepthOnlyStage(
|
|
ScriptableRenderPipelinePlanningContext context,
|
|
DepthPrepassBlockData depthPrepass)
|
|
{
|
|
if (depthPrepass != null &&
|
|
depthPrepass.enabled &&
|
|
context.RequestCameraDepthOnlyStage())
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.ClearDepthOnlyStage();
|
|
}
|
|
|
|
private static void ConfigureFinalOutputStage(
|
|
ScriptableRenderPipelinePlanningContext context)
|
|
{
|
|
if (!context.HasFinalColorProcessing())
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.ClearFullscreenStage(
|
|
CameraFrameStage.FinalOutput);
|
|
|
|
CameraFrameColorSource finalOutputSource =
|
|
CameraFrameColorSource.MainSceneColor;
|
|
if (context.IsStageRequested(
|
|
CameraFrameStage.PostProcess))
|
|
{
|
|
CameraFrameColorSource postProcessSource =
|
|
context.GetStageColorSource(
|
|
CameraFrameStage.PostProcess);
|
|
if (postProcessSource !=
|
|
CameraFrameColorSource.ExplicitSurface)
|
|
{
|
|
if (!context.UsesGraphManagedOutputColor(
|
|
CameraFrameStage.PostProcess))
|
|
{
|
|
context.ClearFullscreenStage(
|
|
CameraFrameStage.PostProcess);
|
|
context.RequestFullscreenStage(
|
|
CameraFrameStage.PostProcess,
|
|
postProcessSource,
|
|
true);
|
|
}
|
|
|
|
finalOutputSource =
|
|
CameraFrameColorSource.PostProcessColor;
|
|
}
|
|
}
|
|
|
|
context.RequestFullscreenStage(
|
|
CameraFrameStage.FinalOutput,
|
|
finalOutputSource);
|
|
}
|
|
|
|
private static bool ShouldUseSkyboxEnvironment(
|
|
RenderSceneSetupContext context,
|
|
Camera camera)
|
|
{
|
|
if (context == null ||
|
|
camera == null ||
|
|
!context.hasMainSceneDepthAttachment ||
|
|
(context.clearFlags & RenderClearFlags.Color) == 0 ||
|
|
!camera.skyboxEnabled)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return camera.projectionType ==
|
|
CameraProjectionType.Perspective;
|
|
}
|
|
|
|
private void EnqueueFinalOutputPasses(
|
|
RenderingData renderingData)
|
|
{
|
|
if (renderingData == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!renderingData.isFinalOutputStage &&
|
|
!renderingData.finalColorData.requiresProcessing)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EnqueuePass(m_builtinFinalColorPass);
|
|
}
|
|
}
|
|
}
|