Drawing 2D Lines with 3D Occlusion

Hi there,

I’m trying to achieve the effect of visualizing a satellite orbit with a constant thickness no matter the viewing distance, so 3D lines with DrawDebugLine() aren’t an option.

Here’s the desired effect:

273128-th.jpg

I’ve only come up with this:

  1. Extending the AHUD class and override the DrawHUD() function. Use AHUD:: Project() to convert 3D coordinates to 2D screen coordinates, then use AHUD:: DrawLine() to draw 2d lines on the HUD.
  2. Do line traces from camera to each point on the orbit to determine if it is blocked by some object, and use binary search to approximate the cut-off point:

https://forums.unrealengine.com/filedata/fetch?filedataid=161101

However there are a few problems with this approach:

  1. Line trace is a synchronous operation which blocks the main game thread. I’ve tested 4,000 line traces within a single frame, and the fps drop is unacceptable (240 fps down to around 80 fps).
  2. If there is a blocking object in between two adjacent orbit points or the shape of the object is irregular, then this approach won’t work.

When the scene gets a bit more complex, there could be visual glitches every where, not to mention the performance. There is some optimization work can be done to minimize the problems, like skipping points based on viewing distance and dealing with every corner case, but I’m not sure if it’s even worth the effort.

So I’m looking for a better approach to achieve the same effect. Any thoughts?

1 Like

There is a DrawCircle function, built into the Primitive Drawing Utils that might be of use?

Thanks for the reminder. I’m currently looking into how spline visualizers are drawn, which utilizes the PrimitiveDrawInterface and it looks promising :D. I’ll give it a try and post my findings. Cheers!

Great stuff! And yeah, please do keep us posted with your findings… and once you have a solution, mark this as answered, so others can use it to find similar fixes :smiley:

With the help of engine source FSplineComponentVisualizer::DrawVisualization and some forum posts, this is what I end up with:

Basically what I did was extending UPrimitiveComponent class and override these two functions:

virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override;

Define your own component bounds to deal with frustum culling with CalcBounds.

Then create another class inheriting from FPrimitiveSceneProxy to get hold of a FPrimitiveDrawInterface pointer ([refer to this forum post][2]) and draw with

PDI->DrawLine(LineStart, LineEnd, Color, SceneDepthPriorityGroup, Thickness);

If you want your line occluded by other objects, the SceneDepthPriorityGroup has to be SDPG_World.

With a thickness of 0.0f the line is constantly 1 pixel wide; however any value above 0.0f results in the line thickness becoming depth dependent. If you need a constant thickness and want to be able to control the thickness as well, check out FSceneView::WorldToScreen, which returns a FVector4, then use the W component of that vector to scale the line thickness.

2 Likes

Hey I was wondering if you can explain how you got the PDI from the PrimitiveSceneProxy? The forum post you linked doesn’t seem to be showing