Site Tools


Drawing Meshes

Developer: .NET
Summary: Demonstrates how to draw a mesh using a display conduit.
NOTICE: The Rhino.NET SDK is deprecated in Rhino 5. This example adapted for the new RhinoCommon SDK is here

Question

Is it possible to create, in .NET, some graphic objects which are not Rhino objects?

Answer

Yes. The solution is to use a display conduit to draw. For an overview of display conduits, See Display Conduit Introduction

Example

In the following we will dynamically draw a mesh. The first thing we need a display conduit to draw the mesh for us. Considering the following class:

C#

public class DrawBlueMeshConduit : MRhinoDisplayConduit
{
  private OnMesh m_mesh = null;
  private OnColor m_drawing_color = null;
  private MDisplayPipelineMaterial m_material = null;
  private OnBoundingBox m_mesh_bbox = null;
 
  public DrawBlueMeshConduit(OnMesh mesh)
    : base(new MSupportChannels(MSupportChannels.SC_CALCBOUNDINGBOX | MSupportChannels.SC_PREDRAWOBJECTS), false)
  {
    // set up as much data as possible so we do the minimum amount of work possible inside the
    // actual display code
    m_mesh = mesh;
    m_drawing_color = OnColor.FromColor(System.Drawing.Color.Blue);
    m_material = new MDisplayPipelineMaterial();
    m_material.m_FrontMaterial.m_diffuse = m_drawing_color;
    if (m_mesh != null && m_mesh.IsValid())
      m_mesh_bbox = m_mesh.BoundingBox();
  }
 
  public override bool ExecConduit(ref MRhinoDisplayPipeline dp, uint nChannel, ref bool bTerminate)
  {
    if (m_mesh_bbox == null)
      return true;
 
    // this is called every frame inside the drawing code so try to do as little as possible
    // in order to not degrade display speed. Don't create new objects if you don't have to as this
    // will incur an overhead on the heap and garbage collection.
 
    if (nChannel == MSupportChannels.SC_CALCBOUNDINGBOX)
    {
      // Since we are dynamically drawing geometry, we needed to override
      // SC_CALCBOUNDINGBOX. Otherwise, there is a good chance that our
      // dynamically drawing geometry would get clipped.
 
      // Union the mesh's bbox with the scene's bounding box
      m_pChannelAttrs.m_BoundingBox.Union(m_mesh_bbox);
    }
    else if (nChannel == MSupportChannels.SC_PREDRAWOBJECTS)
    {
      // Time to draw our mesh
 
      // Get the active viewport
      MRhinoViewport vp = dp.GetRhinoVP();
      if (vp.DisplayMode() == IOn.display_mode.wireframe_display)
      {
        // If the viewport is in wireframe, draw a wireframe mesh
        dp.DrawWireframeMesh(m_mesh, m_drawing_color);
      }
      else
      {
        // Otherwise, draw a shaded mesh
        dp.DrawShadedMesh(m_mesh, m_material);
      }
    }
    return true;
  }
}

VB.NET

Public Class DrawBlueMeshConduit
  Inherits MRhinoDisplayConduit
 
Private m_mesh As OnMesh = Nothing
Private m_drawing_color As OnColor = Nothing
Private m_material As MDisplayPipelineMaterial = Nothing
Private m_mesh_bbox As OnBoundingBox = Nothing
 
Public Sub New(ByVal mesh As OnMesh)
  MyBase.New(New MSupportChannels(MSupportChannels.SC_CALCBOUNDINGBOX Or MSupportChannels.SC_PREDRAWOBJECTS), False)
 
  ' set up as much data as possible so we do the minimum amount of work possible inside the
  ' actual display code
  m_mesh = mesh
  m_drawing_color = OnColor.FromColor(System.Drawing.Color.Blue)
  m_material = New MDisplayPipelineMaterial()
  m_material.m_FrontMaterial.m_diffuse = m_drawing_color
  If (m_mesh IsNot Nothing AndAlso m_mesh.IsValid()) Then
    m_mesh_bbox = m_mesh.BoundingBox()
  End If
End Sub
 
Public Overrides Function ExecConduit(ByRef pipeline As RMA.Rhino.MRhinoDisplayPipeline, ByVal channel As UInteger, ByRef terminate As Boolean) As Boolean
  If (m_mesh_bbox Is Nothing) Then Return True
 
  ' this is called every frame inside the drawing code so try to do as little as possible
  ' in order to not degrade display speed. Don't create new objects if you don't have to as this
  ' will incur an overhead on the heap and garbage collection.
  If (channel = MSupportChannels.SC_CALCBOUNDINGBOX) Then
    ' Since we are dynamically drawing geometry, we needed to override
    ' SC_CALCBOUNDINGBOX. Otherwise, there is a good chance that our
    ' dynamically drawing geometry would get clipped.

    ' Union the mesh's bbox with the scene's bounding box
    m_pChannelAttrs.m_BoundingBox.Union(m_mesh_bbox)
  ElseIf (channel = MSupportChannels.SC_PREDRAWOBJECTS) Then
    ' Time to draw our mesh

    ' Get the active viewport
    Dim vp As MRhinoViewport = pipeline.GetRhinoVP()
    If (vp.DisplayMode() = IOn.display_mode.wireframe_display) Then
      ' If the viewport is in wireframe, draw a wireframe mesh
      pipeline.DrawWireframeMesh(m_mesh, m_drawing_color)
    Else
      ' Otherwise, draw a shaded mesh
      pipeline.DrawShadedMesh(m_mesh, m_material)
    End If
  End If
  Return True
End Function
 
End Class

More Information

Here we have an MRhinoDisplayConduit derived class. The constructor of the class requires that we define when we want Rhino to call our display conduit. In this case, we want to be called to be called to ensure the drawing bounding box is the correct size (MSupportChannels.SC_CALCBOUNDINGBOX) and when Rhino is drawing visible, non-highlighted objects (MSupportChannels.SC_PREDRAWOBJECTS). All MRhinoDisplayConduit derived class are required to override the ExecConduit abstract member function. This is were all of the action will take place.

To use the above class, we can write a simple command, such as the following that creates a meshed sphere and then draws it with our conduit:

C#

public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
  // Define the sphere
  OnSphere sphere = new OnSphere();
  MArgsRhinoGetSphere args = new MArgsRhinoGetSphere();
  IRhinoCommand.result rc = RhUtil.RhinoGetSphere(args, ref sphere);
  if (rc != IRhinoCommand.result.success)
    return rc;
 
  // Create a mesh sphere
  OnMesh mesh = RhUtil.RhinoMeshSphere( sphere, 10, 10 );
  if( mesh == null )
    return IRhinoCommand.result.failure;
 
  // Create an instance of our conduit
  DrawBlueMeshConduit conduit = new DrawBlueMeshConduit(mesh);
  // Enable the conduit - don't for get to regen
  conduit.Enable();
  context.m_doc.Regen();
 
  // Pause so the user can see our work
  MRhinoGetString gs = new MRhinoGetString();
  gs.SetCommandPrompt("Press <Enter> to continue");
  gs.AcceptNothing();
  gs.GetString();
 
  // Disable the conduit - don't for get to regen
  conduit.Disable();
  context.m_doc.Regen();
 
  return IRhinoCommand.result.success;
 }

VB.NET

Public Overrides Function RunCommand(ByVal context As RMA.Rhino.IRhinoCommandContext) _
  As RMA.Rhino.IRhinoCommand.result
  ' Define the sphere
  Dim sphere As New OnSphere()
  Dim args As New MArgsRhinoGetSphere()
  Dim rc As IRhinoCommand.result = RhUtil.RhinoGetSphere(args, sphere)
  If (rc <> IRhinoCommand.result.success) Then Return rc
 
  ' Create a mesh sphere
  Dim mesh As OnMesh = RhUtil.RhinoMeshSphere(sphere, 10, 10)
  If (mesh Is Nothing) Then Return IRhinoCommand.result.failure
 
  ' Create an instance of our conduit
  Dim conduit As New DrawBlueMeshConduit(mesh)
  ' Enable the conduit - don't for get to regen
  conduit.Enable()
  context.m_doc.Regen()
 
  ' Pause so the user can see our work
  Dim gs As New MRhinoGetString()
  gs.SetCommandPrompt("Press <Enter> to continue")
  gs.AcceptNothing()
  gs.GetString()
 
  ' Disable the conduit - don't for get to regen
  conduit.Disable()
  context.m_doc.Regen()
  conduit.Dispose()
  Return IRhinoCommand.result.success
End Function


developer/sdksamples/meshdrawing.txt ยท Last modified: 2015/09/14 (external edit)