Custom Preview - Draw Order / Draw Foreground

Hello,

Would anyone else be interested in the ability to set the Draw Order on the Custom Preview component?

I know we can set the draw order of objects with the new Drafting Attributes of the Model Object data type and this works great if the intention is to bake the geometry.

However, it would be very beneficial to expose this functionality extended to the Custom Preview component to create ease of use in highlighting objects without Z-Fighting, previewing Model Hatches or Surfaces acting as solid model hatches (by nature of having a draw order above the occluding geometry), and for many other debugging and diagrammatic purposes.

Currently my workflow entails creating and baking lots of geometry for “display/diagramming” purposes that has no Geometrical reason to exist outside of the Display Pipeline and is really only hogging resources and file space by being baked into the model to be “displayed”.

So of course the Custom Preview component works great for these elements but the ability to control draw order is still needed for said elements.

When you are previewing GH objects it actually works this way already, bringing the selected object to the foreground:

Here you see a “Break Line” that would benefit from a forward draw order without needing to bake:

Thanks for your thoughts and time!

Here’s my attempt so far with a python component and while this does handle the solid fill portion, I can’t seem to get the draw order to bring itself to the foreground.

Graph Space:
image

Model Space:

Python:

from ghpythonlib.componentbase import executingcomponent as component
import Grasshopper
import System
from System.Drawing import Color
import Rhino as rh

class CustomDisplayDrawOrder(component):

    def RunScript(self, M, C):
        self.meshes = M  # M is a list of meshes

        # Set Display Color
        self.material = rh.Display.DisplayMaterial(Color.Black)
        self.material.Emission = C

        # Add event handlers for drawing
        rh.Display.DisplayPipeline.CalculateBoundingBox += self.CalculateBoundingBox
        rh.Display.DisplayPipeline.PostDrawObjects += self.DrawViewportMeshes

    def CalculateBoundingBox(self, sender, e):
        for mesh in self.meshes:
            e.IncludeBoundingBox(mesh.GetBoundingBox(True))

    def DrawViewportMeshes(self, sender, e):
        for mesh in self.meshes:
            e.Display.DrawMeshShaded(mesh, self.material)

    def __del__(self):
        # Remove event handlers when the component is deleted
        rh.Display.DisplayPipeline.CalculateBoundingBox -= self.CalculateBoundingBox
        rh.Display.DisplayPipeline.PostDrawObjects -= self.DrawViewportMeshes

    def __exit__(self):
        # Handle Draw Order
        rh.Display.DisplayPipeline.DrawForeground -= self.DrawViewportMeshes

    def __enter__(self):
        # Handle Draw Order - Draw In Foreground
        rh.Display.DisplayPipeline.DrawForeground += self.DrawViewportMeshes

@AndersDeleuran I cannibalized bits of your code from this post and then tried to utilize the draw foreground method you shared with me in this post here but can’t seem to get it to apply properly to this implementation above. I also attempted to clear the display with this method you shared but I think I’m just muddying the logic trying to combine everything…

I also found this “DepthMode” method but can’t seem to get it to work either:
https://developer.rhino3d.com/api/rhinocommon/rhino.display.depthmode

Essentially I am looking to mimic the “shaded” functionality of a color input with a custom preview component while controlling the draw order to the foreground or background.

Any help is greatly appreciated, thank you all!

Okay, I went back to some previous posts @AndersDeleuran shared such as this one:

And figured it out.

Here’s the updated Python code if anyone is interested:

from ghpythonlib.componentbase import executingcomponent as component
import Grasshopper
import System
from System.Drawing import Color
import Rhino as rh

class CustomDisplayForeground(component):

    def RunScript(self, O, M):
        # M is a list of meshes
        self.meshes = O  

        # Set Display Color
        self.material = rh.Display.DisplayMaterial(Color.Black)
        self.material.Emission = M

    #Setup Objects To Be Drawn
    def DrawForeground(self, sender, arg):
        if self.drawingWires:
            self.drawingWires = False

        for mesh in self.meshes:
            arg.Display.DrawMeshShaded(mesh, self.material)

    def DrawViewportWires (self,arg):
        self.drawingWires = True

    #Handle Draw Foreground Events
    def __exit__(self):
        rh.Display.DisplayPipeline.DrawForeground -= self.DrawForeground
        
    def __enter__(self):
        rh.Display.DisplayPipeline.DrawForeground += self.DrawForeground

Model Space:

image

1 Like

Just a quick sidenote/tip: When drawing 3D meshes with overlapping faces, I typically use Mesh.Offset to slightly offset them away from each other, like how the real world objects would stack to prevent Z-fighting. It’s a brute force solution, but it does the trick and is pretty fast to compute :slight_smile:

1 Like

Thanks @AndersDeleuran , this is the method I’ve been using for Floor Plan hatching and such prior to R8 Draw Order on the Drafting Attributes was implemented. And I still need this in cases like room diagram coloring where I want the colors “contained” in the rooms so I can’t draw to foreground but the offset is needed, as you mentioned, to prevent the Z-Fighting

With this drawForeground method it appears to have no Z-fighting since it’s layering itself Infront of the other objects in the display pipeline, is that correct?

That is my understanding yes. You can check out the DrawForeground method documentation here:

https://developer.rhino3d.com/api/rhinocommon/rhino.display.displayconduit/drawforeground

1 Like

Thanks for sharing! It seems that Display Conduits in general are where I need to spend time reading as there’s a lot of possibilities packed in there

1 Like