Integrating a render engine in Rhinoceros 3D using RhinoCommon: MockingBird – Interactive Rendering (4/5)

This is part 4 in the series on render engine integration in Rhinoceros 3D using RhinoCommon (v6).

For this plug-in we are going to do things in a slightly different way. Not because it is a must, but because it gives an interesting possibility for plug-in developers who want to integrate their own render engines, but without exposing it to the _ Render  command. We do that with a generic utility plug-in. There won’t be an API to implement for the _ Render  command, instead we’ll implement two new classes. One derived from Rhino.Render.RealtimeDisplayMode  and one derived from Rhino.Render.RealtimeDisplayModeClassInfo .

Together these will effectively create and register a conduit that is used during the drawing process of a viewport to display the result of the render engine.

For this example a ChangeQueue  implementation is used, but as said in earlier articles it is possible to do your data conversion directly from the RhinoDoc . If the render engine to be integrated is one using mesh data for geometry I advise strongly to use the ChangeQueue .

Utility plug-in

The plug-in code is very lean, only LoadRetunCode OnLoad()  needs to be overridden. (In this function a call on line 9 to RealtimeDisplayMode.RegisterDisplayModes()  with the plug-in itself as parameter ensures the Rhino plug-in loading mechanism checks for display mode implementations. With latest Rhino WIP (and what will go into v6)  it is no longer necessary to explicitly call RegisterDisplayModes() , since that is done automatically. ) With a proper RealtimeDisplayModeClassInfo and RealtimeDisplayMode implementation the new viewport mode will be registered with Rhino. It’ll show up in the viewport mode dropdown list.

Registering with Rhino

Implement a class derived from Rhino.Render.RealtimeDisplayModeClassInfo . When the plug-in is loaded the automatic registration procedure of the plug-in ensures that this information is used to identify the RealtimeDisplayMode  implementation of the plug-in.

All of the properties of the class are important, but pay especially close attention to Guid GUID . This has to be unique from other plug-ins, so don’t ever copy-paste Guids from sample code.

The Type RealtimeDisplayModeType property should return the type of your RealtimeDisplayMode  implementation.

After the plug-in is loaded the viewport mode can be found from the mode drop-down list.



The viewport implementation

The actual viewport integration is done with a class deriving from RealtimeDisplayMode . When deriving from that class, which we do with MockingRealtimeDisplayMode , Visual Studio will tell that several abstract methods need to be implemented. These methods are the minimum required functions to ensure proper functioning of the integration. The entire class can be found in the Git repository here. Lets step through the process what happens when the user selects the display mode for the viewport.

First of all an instance of our class will be created. If there is the need for initialisation a public default constructor can be implemented where such initialisation can be done. For MockingRealtimeDisplayMode  we don’t need that. During the start up phase of the mode switch the underlying system will be querying whether our engine is started, and whether there are results available. Because this can happen already before we’ve actually managed to start our engine and get some results we’ll be using a boolean flag _started  to communicate our state through the functions IsRendererStarted()  and IsFrameBufferAvailable() . Our real entry into the rendering process happens with StartRenderer() .

For this example I opted to implement a very simple ‘render engine’ to show how working with threads in this environment can be done. So I start by creating an instance of that engine MockingRender . This engine uses a ChangeQueue  internally, so I give the plug-in ID, Rhino document runtime serial number, the ViewInfo  instance and the RenderWindow  instance to it.

To make communication between the MockingRealtimeDisplayMode  and MockingRender  easy I have added several events to MockingRender . I register necessary handlers for those.

Once the render engine has completed a pass it fires the PassRendered  event. In the handler the underlying system gets notified about that fact by calling the SignalDraw()  function provided by the base class RealtimeDisplayMode .

The actual rendering

The MockingRender  class is responsible for generating the pixel data for the viewport. Its entry function is ColorPixels().

It essentially goes into an eternal loop that runs until the _shutdown  flag is set. The render process goes through each pass (and simulates some extra workload by sleeping a whopping 10 milliseconds), then essentially waits for Passes  to get reset or MaxPasses  change such that Passes < MaxPasses . ColorPass()  then fills the pixel buffer, presented to the render engine by means of the RenderWindow . Increasing Passes  will also fire the PassRendered  event.

In ColorPass()  above the most important part to look at is line 5. With the using  idiom the necessary channel from the RenderWindow  is opened ( RGBA  in general, there are other channels too, though, but not in the scope of this article series), then filled with color data per pixel. The using idiom ensures the opened channel is properly disposed of.

Note that the simplest possible pixel buffer filling code would be to have the channel SetValue  loop directly in StartRenderer()  and leave out the entire MockingRender  and Thread  construct.

These are the steps necessary to integrate a new render engine into Rhinoceros 3D (v6) viewport for interactive, real-time rendering using the RhinoCommon SDK.

3 thoughts on “Integrating a render engine in Rhinoceros 3D using RhinoCommon: MockingBird – Interactive Rendering (4/5)

Leave a Comment