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

plug-in

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

publicclassMockingViewportPlugIn:Rhino.PlugIns.PlugIn

{

publicMockingViewportPlugIn()

{

if(Instance==null)Instance=this;

}

publicstaticMockingViewportPlugInInstance{get;privateset;}

protectedoverrideLoadReturnCode OnLoad(refstringerrorMessage)

{

// RealtimeDisplayMode.RegisterDisplayModes(this);

// call to RegisterDisplayModes no longer necessary, it is automatically called.

returnLoadReturnCode.Success;

}

}

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.

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 .

C#

1

2

3

4

5

privatevoidReng_PassRendered(objectsender,PassRenderedEventArgse)

{

_currentPass=e.Pass;

SignalRedraw();

}

The actual rendering

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

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

publicvoidColorPixels()

{

RenderStarting?.Invoke(this,EventArgs.Empty);

Passes=0;

RenderStarted?.Invoke(this,EventArgs.Empty);

while(true)

{

while(Passes<MaxPasses)

{

ColorPass(Passes);

Thread.Sleep(10);

if(_shutdown)break;

Passes+=1;

}

if(!_completionTriggered&&Passes>=MaxPasses)

{

_completionTriggered=true;

MaxPassesCompleted?.Invoke(this,EventArgs.Empty);

}

Thread.Sleep(10);

if(_shutdown)break;

}

}

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.

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

privatevoidColorPass(intpass)

{

varfac=pass/(float)MaxPasses;

varc=Color4f.FromArgb(1.0f,_color.R*fac,_color.G*fac,_color.B*fac);

using(varchannel=rw.OpenChannel(RenderWindow.StandardChannels.RGBA))

{

varsize=rw.Size();

for(varx=0;x<size.Width;x++)

{

for(vary=0;y<size.Height;y++)

{

channel.SetValue(x,y,c);

}

if(_shutdown)break;

}

}

}

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.