Reproducing Clipping Plane in C# Conduit

Hi,
I am playing around with some animations that should show extrusion profiles appear by sliding a plane. Basically reproducing what Clipping plane does if I was moving the plane along the extrusion.

My first go-to was some kind of Split or Boolean operation (difference or intersection), but I think that would be way more expensive and slower than whatever is done with the Clipping Plane command. Am I wrong?

Can you tell me how the clipping plane works and is there something exposed in the API I could use to recreate the same effect?

Are you actually cutting/splitting the geometry or is it just a visual (camera) effect?

By the way, I would like to recreate this in the Conduit, inside DrawForeground…I do not need to make any changes to the document (like you are not making any changes with the Clipping Plane I assume).

I appreciate your help.
Thanks.
Milos

1 Like

You might use the DisplayPipeline.AddClippingPlane method.

2 Likes

I had attempted this in Python but never got it hooked up. I assumed there was some kind of enabling of clipping planes or other additional setting I needed to get it working for display conduits.

This was my attempt using a planar surface in the scene as a test “cut plane” to visualize:

Is there something more specific needed to “add objects” to the clipping plane conduit?

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
from Rhino.Display import DisplayConduit
from System.Drawing import Color

class ClippingPlaneConduit(DisplayConduit):
    def __init__(self, plane):
        super(ClippingPlaneConduit, self).__init__()
        self.plane = plane
        self.debug_section_color = Color.Blue
        self.debug_section_mat = Rhino.Display.DisplayMaterial(Color.Blue)
        self.debug_section_mat.Transparency = 0.6

    def DrawForeground(self, e):
        e.Display.EnableDepthTesting(False)
        e.Display.EnableClippingPlanes(True)
        e.Display.AddClippingPlane(self.plane.Origin, self.plane.Normal)

        # Ensure plane_srf is a valid Brep
        if not plane_srf or not isinstance(plane_srf, Rhino.Geometry.Brep):
            return

        # Convert Brep to Mesh for visualization
        plane_mesh = Rhino.Geometry.Mesh.CreateFromBrep(plane_srf)
        if plane_mesh:
            e.Display.DrawMeshShaded(plane_mesh[0], self.debug_section_mat)

        # Extract the actual corner points from the Brep's outer loop
        brep_faces = plane_srf.Faces
        if brep_faces.Count > 0:
            face = brep_faces[0]  # Assuming a single face Brep
            plane_corners = face.ToNurbsSurface().Points

            # Draw bounding box from actual Brep
            bbox = plane_srf.GetBoundingBox(True)
            e.Display.DrawBoxCorners(bbox, self.debug_section_color, 1, 6)

        # Extract Brep edges as polylines for visualization
        plane_edges = []
        for edge in plane_srf.Edges:
            plane_edges.append(edge)

        # Draw edges
        for polyline in plane_edges:
            e.Display.DrawCurve(polyline, self.debug_section_color, 2)

        # Draw direction indicators
        e.Display.DrawDot(self.plane.Origin, "Direction", self.debug_section_color, Color.White)
        e.Display.DrawArrow(Rhino.Geometry.Line(self.plane.Origin, self.plane.Origin + self.plane.Normal * 10), self.debug_section_color)


plane_srf_id = rs.GetObject("Choose a planar surface to use as clipping control", filter=rs.filter.surface, preselect=True)
if plane_srf_id:
    plane_srf = rs.coercebrep(plane_srf_id)
    plane = None
    
    if plane_srf and plane_srf.Faces[0].TryGetPlane():
        plane_tup = plane_srf.Faces[0].TryGetPlane()
        plane = plane_tup[1]
    
    if plane:
        if "ClippingPlaneConduit" in sc.sticky:
            sc.sticky["ClippingPlaneConduit"].Enabled = False
        
        cp_conduit = ClippingPlaneConduit(plane)
        cp_conduit.Enabled = True
        sc.sticky["ClippingPlaneConduit"] = cp_conduit
        print("Clipping plane display conduit updated and enabled.")
    else:
        print("Selected surface is not planar.")
else:
    print("No surface selected.")

sc.doc.Views.Redraw()


Thanks,

But if I am not mistaken this is a global thing, no? If you set this it cuts everything in the scene?

The goal is to manipulate individual objects in the same manner…that is why I wonder what is under th hood of the clipping plane, so that o could apply it to individual objects with more control.

There is also

https://developer.rhino3d.com/api/rhinocommon/rhino.display.displaypipeline/enableclippingplanes

Never used clipping planes via api.

My guess: the graphic card / open gl does the magic

This is probably not the intended/correct way to implement the method (e.g. one should probably track/delete old ones), but extending this old GhPython example seems to only clip the local component conduit/display:



00_DrawViewportWiresMeshes_ClippingPlane.gh (20.5 KB)

2 Likes

Thanks,

but I would love if someone from McNeel told us what is used under the hood to make the Clipping plane work…even as a concept.

I think I will go with some Split or Boolean Difference option if there is no answer. My guess is that the Clippling Plane only alters the view, deals with the Camera frustum or similar, (and does not alter the geometry)…otherwise it could not be so fast. Although it does cap all the cut solids nicely, so how does it do that? :slight_smile: Maybe it is some combination…it creates a section, caps the solids and also adjusts the camera…would love to know in any case.

If it is mostly Camera adjustment then it is probably hard to constrain it to individual objects…and my guess is that they are using a system where it is hard to apply it do individual objects, otherwise thy would offer that option.

1 Like

You are quite right.
With the plugin GHGL you can play a bit with that.
Related thread:

I tried to combine 2 meshes to create the visual effect of a solid boolean operation, but never managed to make buffers work at all :confused:

Anyway, you actually tell each and every pixel if to display on screen or not. When not, the “raycast” from the camera continue and search for the next geometry to display.
(my description probably sucks…)

Accessing this OpenGL coding through a c# or python script is not possible, as far as I understood past then.
Steve might answer you in detail…


Probably it does the same as above but in the the opposite way, using the mesh to discard the plane pixels when the raycast intercepted the mesh an even amount of times before reaching the plane…
Google “openGL depth peeling”.