Draw To Screen Space Foreground From DrawViewportWires

Hi All,

I’m experimenting with implementing DrawViewportWires in GHPython for drawing e.g. legends on top of 3D geometry generated in Grasshopper. Here’s a quick example:

The issue I’m trying to resolve is that the rectangles (drawn with Draw2dRectangle ) are drawn behind the 3D geometry that is drawn by Grasshopper (though it still appears to obscure the wires of the 3D mesh), while the text is drawn in the foreground:

Here’s a minimal example and file of this behaviour:


201125_DrawRectangle2d_00.gh (4.9 KB)

I can see that this issue has been brought up previously by @andheum. But I’ve not been able to find any examples/code that demonstrate how one has resolved this (notably how to “add a callback to the DisplayPipeline.DrawForeground event”). I should also mention that I’ve been given great pointers by @dave_stasiuk and @tom_svilans on how they draw to the foreground from a display conduit in a compiled component. But before going down that path, I just wanted to make sure that I’m not missing something here.

So, is it possible to always draw to the screen space foreground from DrawViewportWires?

Best,

Anders

4 Likes

Apologies for bumping. Maybe @stevebaer, @piac, or @DavidRutten have some suggestions?

You really want to have HUD type display done in the DrawForeGround stage of drawing. DrawForeground occurs after DrawViewportWires and has depth testing turned off which is exactly what you want with a HUD.

Here is what I was able to cook up. It’s not as clean as just having a DrawForeground override in the component class, but it should work. Let me know if you have any questions.

201125_DrawRectangle2d_00.gh (16.1 KB)

1 Like

@piac helped me make a cleaner version.
Here’s an update 201125_DrawRectangle2d_00.gh (13.6 KB)

3 Likes

This is fantastic, thanks so much! Will have a go at implementing this into the legend component ASAP. You guys rock :metal:

I ended up using a combination of the two methods: Implementing both the hack to pipe into DrawViewportWires and the __enter__/__exit__ methods to add/remove the DrawForeground method. This means the component still behaves like a “normal” Grasshopper component (i.e. one can turn Preview off to stop drawing etc.).

It seems to work okay so far:

And here’s the minimal case again, with these edits:
201203_DrawRectangle2d_02.gh (5.3 KB)

Thanks again guys, very much appreciated :beers:

6 Likes

I took a stab at a HUD display leveraging the DisplayPipeline.DrawForeground event handler in C#. Basic functionality works as expected, but I have a few questions on how to further customize it:

  1. The event fires for each viewport separately. Is there a way to limit the HUD to only the active viewport?

  2. Fill color of 2D shapes respects transparency, 2D text color ignores it. Is this intended behavior?

  3. Using the ViewCaptureToFile command with increased resolution doesn’t scale the HUD correctly and causes it to be drawn multiple times. Any ideas how to address this?
    ScreenCaptureToFile:


    ViewCaptureToFile:

Any ideas @AndersDeleuran @stevebaer ?

201208_DrawRectangle2d_03.gh (6.2 KB)

1 Like

I added this conditional to only render in the active viewport:

Afraid I don’t have any ideas on the other two issues.

2 Likes

Thanks Anders,

works like a charm! C# equivalent below if anyone is interested:

    private void DrawForeground(object sender, DrawEventArgs e)
    {
        if (e.Viewport.Id == Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewportID)
        {
         // do magic
        }
    }
3 Likes

Using the doc that gets passed as part of the DrawEventArgs is better to use over ActiveDoc

2 Likes

Thanks @stevebaer, fixed that part:

private void DrawForeground(object sender, DrawEventArgs e)
{
    if (e.Viewport.Id == e.RhinoDoc.Views.ActiveView.ActiveViewportID)
    {
     // do magic
    }
}

Any suggestions on how to attack the scaling and transparency issues?

Hi @stevebaer, @mrhe, I adapted a similar code based on the old forum, but I have some similar issues with geometries in Rhino and GH since I didn’t use DrawForeground, because of my limited C# knowledge. could you help me to fix it, please
Even in the Rendered mode is incomplete and sometimes disappeared.
Regards,
T.


DrawRec.gh (3.9 KB)

Hi @ThomasE,

to keep your dashboard consistently above the remaining 3d geometry you need to use the DrawForeground method. Here is what I did:

public override void BeforeRunScript()
  {
    _point.Clear();
    _box = BoundingBox.Empty;
    
    // Unregister & register new event
    Rhino.Display.DisplayPipeline.DrawForeground -= DrawForeground;
    Rhino.Display.DisplayPipeline.DrawForeground += DrawForeground;
  }


  public override BoundingBox ClippingBox
    {get{return _box;}}

  // Event function
  private void DrawForeground(object sender, Rhino.Display.DrawEventArgs e)
  {
    for (int i = 0; i < _point.Count; i++)
      DrawRec(e, _point[i]);
  }

  private void DrawRec(Rhino.Display.DrawEventArgs pipeline, Point3d point)
  {
    if (pipeline.Viewport.Id == pipeline.RhinoDoc.Views.ActiveView.ActiveViewportID)
    {
      Rectangle SQ = new Rectangle((int) point.X, (int) point.Y, 50, 50);
      pipeline.Display.Draw2dRectangle(SQ, Color.Black, 5, Color.LimeGreen);
    }
  }

This gets you 80% there. You will notice, however, that the dashboard is now persistent even if you remove the script from your document or switch to a different one. Ideally, you would unregister from the DrawForeground event handler in the following two cases but I only know how to do it from a compiled component. Maybe someone else can help you with the script component counterparts:

public override void DocumentContextChanged(GH_Document document, GH_DocumentContext context) {}

public override void RemovedFromDocument(GH_Document document) {}

image

drawForeground.gh (2.7 KB)

2 Likes

Some fun with this

2 Likes

Hi @stevebaer this ViewportCaptureToFile problem related with the scale persists. Is there any temporary fix? please!

@dave_stasiuk any trick to deal with it. :pray:t2:

Alas, none that I ever found. Unfortunately I think it has to do with the display pipeline calling the DrawForeground override for each subdivided screen tile when the ViewCapture commands are run, and I was never able to figure out how to get around it.

I did start up a pipeline using SVG.NET to output vector-based representations of Conduit DrawObjects, but that work never made it into a released version.

2 Likes

@ThomasE @mrhe
I also had difficulties with this -

There isn’t really any trick to deal with it; no way to get around it with the ViewportCaptureToFile command.

In the end, I had to write a custom command to produce a PDF output (in my case), starting with a new Rhino.Display.ViewCaptureSettings and the Rhino.FileIO.FilePDF classes. Then for all the custom 2d UI elements (like your floating “52”) that has to be drawn separately on the PDF (or image in your case), taking it out of your display conduit override. (All the 3d model elements in the viewport get rendered correctly.) You can do this by adding a check on the DrawEventArgs.Display.IsPrinting or IsInViewCapture field then skipping over those elements that are getting repeated.

Some examples:

1 Like

Mariusz, thank you for your script! A HUD for analysis in GH is essential IMO.
Did anyone figure out how the drawings can be removed again?

FWIW the GHPython code doesn’t have this issue. It does have other ones though (for instance, having two components on the canvas that draws to screen space can become “entangled”). Anywho, I’ve suggested to Ehsan that perhaps they can add DrawForeground as a standard override in the new script editor (i.e. in addition to DrawViewportWires and DrawViewportMeshes). Which would hopefully give us a simple and unified method for drawing into screen space :pray:

1 Like

Thank you for your answer, I guess I’ll play around with your script then for now. (just learning C#, my Python skills are even lower, but probably a good exercise)

2 Likes