FViewElementPDI::DrawLine calls for SDPG_World are not rendered in PIE or in Game

When View.Family->EngineShowFlags.CompositeEditorPrimitives is false in the function

static void RenderEditorPrimitivesForDPG(

FRDGBuilder& GraphBuilder,

const FViewInfo& View,

FOpaqueBasePassParameters* PassParameters,

const FMeshPassProcessorRenderState& DrawRenderState,

ESceneDepthPriorityGroup DepthPriorityGroup,

FInstanceCullingManager& InstanceCullingManager)

This code picks which version of the batched lines to render

const FBatchedElements& BatchedViewElements = DepthPriorityGroup == SDPG_World ? View.BatchedViewElements : View.TopBatchedViewElements;

However at the bottom of the function:

// Draw the view’s batched simple elements(lines, sprites, etc).

View.TopBatchedViewElements.Draw(RHICmdList, DrawRenderState, View.GetFeatureLevel(), View, false, 1.0f, EBlendModeFilter::All, View.GetStereoPassInstanceFactor());

Should read

// Draw the view’s batched simple elements(lines, sprites, etc).

BatchedViewElements.Draw(RHICmdList, DrawRenderState, View.GetFeatureLevel(), View, false, 1.0f, EBlendModeFilter::All, View.GetStereoPassInstanceFactor());

Also it appears that since RenderEditorPrimitivesForDPG() is called multiple time for World and for Foreground, the Mesh rendering is executed multiple times.

As both the ViewMeshElements and TopViewMeshElements are rendered in each case

I believe the fix should be thus:

static void RenderEditorPrimitivesForDPG(
	FRDGBuilder& GraphBuilder,
	const FViewInfo& View,
	FOpaqueBasePassParameters* PassParameters,
	const FMeshPassProcessorRenderState& DrawRenderState,
	ESceneDepthPriorityGroup DepthPriorityGroup,
	FInstanceCullingManager& InstanceCullingManager)
{
	const FScene* Scene = View.Family->Scene->GetRenderScene();

	GraphBuilder.AddPass(
		RDG_EVENT_NAME("%s", *UEnum::GetValueAsString(DepthPriorityGroup)),
		PassParameters,
		ERDGPassFlags::Raster,
		[&View, DrawRenderState, DepthPriorityGroup](FRHICommandList& RHICmdList)
	{
		RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);

		View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::OpaqueAndMasked, DepthPriorityGroup);

		if (!View.Family->EngineShowFlags.CompositeEditorPrimitives)
		{
			DrawDynamicMeshPass(View, RHICmdList,
				[&View, &DrawRenderState, DepthPriorityGroup](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
				{
					FEditorPrimitivesBasePassMeshProcessor PassMeshProcessor(
						View.Family->Scene->GetRenderScene(),
						View.GetFeatureLevel(),
						&View,
						DrawRenderState,
						false,
						DynamicMeshPassContext);

					const uint64 DefaultBatchElementMask = ~0ull;
					// <FIX> Render the appropriate set of data depending on the depth priority
					if (DepthPriorityGroup == SDPG_World)
					{
						for (int32 MeshIndex = 0; MeshIndex < View.ViewMeshElements.Num(); MeshIndex++)
						{
							const FMeshBatch& MeshBatch = View.ViewMeshElements[MeshIndex];
							PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
						}
					}
					else
					{
						for (int32 MeshIndex = 0; MeshIndex < View.TopViewMeshElements.Num(); MeshIndex++)
						{
							const FMeshBatch& MeshBatch = View.TopViewMeshElements[MeshIndex];
							PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
						}
					}
				});

			const FBatchedElements& BatchedViewElements = DepthPriorityGroup == SDPG_World ? View.BatchedViewElements : View.TopBatchedViewElements;

			// Draw the view's batched simple elements(lines, sprites, etc).
			// <FIX> Render the set we want depending on the DepthPriorityGroup
			//View.TopBatchedViewElements.Draw(RHICmdList, DrawRenderState, View.GetFeatureLevel(), View, false);
			BatchedViewElements.Draw(RHICmdList, DrawRenderState, View.GetFeatureLevel(), View, false);
			// </FIX>
		}
	});
}



[Attachment Removed]

Steps to Reproduce
When View.Family->EngineShowFlags.CompositeEditorPrimitives is false in PIE or in Game try rendering some lines like:

void Draw(FViewElementPDI& PDI)

{

for (int LineIndex \= 0; LineIndex \< Lines.Num(); \+\+LineIndex)

{

  Line\& Entry \= Lines\[LineIndex];

  PDI.DrawLine(Entry.Start, Entry.End, Entry.Color, SDPG\_World);

}

}

And notice they appear in the DepthPass but not in the BasePass (a renderdoc capture will confirm this)

This was discovered in 5.3 but it appears the the 5.7 git still has this problem as well.

[Attachment Removed]

A more succinct version of the method:

static void RenderEditorPrimitivesForDPG(
	FRDGBuilder& GraphBuilder,
	const FViewInfo& View,
	FOpaqueBasePassParameters* PassParameters,
	const FMeshPassProcessorRenderState& DrawRenderState,
	ESceneDepthPriorityGroup DepthPriorityGroup,
	FInstanceCullingManager& InstanceCullingManager)
{
	const FScene* Scene = View.Family->Scene->GetRenderScene();
 
	GraphBuilder.AddPass(
		RDG_EVENT_NAME("%s", *UEnum::GetValueAsString(DepthPriorityGroup)),
		PassParameters,
		ERDGPassFlags::Raster,
		[&View, DrawRenderState, DepthPriorityGroup](FRHICommandList& RHICmdList)
	{
		RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
 
		View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::OpaqueAndMasked, DepthPriorityGroup);
 
		if (!View.Family->EngineShowFlags.CompositeEditorPrimitives)
		{
			DrawDynamicMeshPass(View, RHICmdList,
				[&View, &DrawRenderState, DepthPriorityGroup](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
			{
				FEditorPrimitivesBasePassMeshProcessor PassMeshProcessor(
					View.Family->Scene->GetRenderScene(),
					View.GetFeatureLevel(),
					&View,
					DrawRenderState,
					false,
					DynamicMeshPassContext);
 
				const uint64 DefaultBatchElementMask = ~0ull;
				const TIndirectArray<FMeshBatch, SceneRenderingAllocator>& MeshElements = DepthPriorityGroup == SDPG_World ? View.ViewMeshElements : View.TopViewMeshElements;
				for (int32 MeshIndex = 0; MeshIndex < MeshElements.Num(); MeshIndex++)
				{
					const FMeshBatch& MeshBatch = MeshElements[MeshIndex];
					PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
				}
			});
 
			const FBatchedElements& BatchedViewElements = DepthPriorityGroup == SDPG_World ? View.BatchedViewElements : View.TopBatchedViewElements;
 
			// Draw the view's batched simple elements(lines, sprites, etc).
			BatchedViewElements.Draw(RHICmdList, DrawRenderState, View.GetFeatureLevel(), View, false);
		}
	});
}

version of the function

[Attachment Removed]

Hi Alex,

Thanks for reaching out. Is it possible for you to propose these changes in a GitHub pull request? That is our preferred method for implementing code changes, such as the one you suggested. Please let me know if you have any questions about this process.

[Attachment Removed]

Hi Tim,

Thanks for your reply. I am extremely busy here. So sadly I don’t have time to do this for you. But the code is quite obviously broken so it would be wonderful if someone in Epic can pick up this fix. Thanks

[Attachment Removed]

Hi Alex, no worries. I have created a Jira task for a developer to review your proposed changes and address the issue you raised. You can follow along the progress here: https://issues.unrealengine.com/issue/UE-359736. If you have any further questions, please don’t hesitate to let me know.

[Attachment Removed]