Rhino Sample that combines DisplayMode, ChangeQueue and EventWatcher?

I am trying to set up a custom renderer plugin and I am investigating how to catch user’s actions, like add lighting, meshes, delete objects, etc.
I am not sure about the hierarchy of the required classes in order to achieve this.

  1. Which class should have as a member the event watcher to catch these actions?
    I have added it in the plugin.h and the eventwatcher indeed works, but I don’t know how trigger the changequeue to apply the changes and give the command to the Display Mode to render the new modified scene.

  2. Is there a Rhino Sample that combines DisplayMode, ChangeQueue and EventWatcher?

So far, I have:

eventwatcher in plunin.h
changequeue in displaymode.h

but I am missing the connection between eventwatcher and displaymode->changequeue.
Any suggestions?

If you are building on ChangeQueue you shouldn’t have to implement an event watcher at all if the goal is to react to document changes: changes to render content, geometry, lights. The ChangeQueue will automatically trigger with NotifyBeginChanges and NotifyEndChanges. Once the latter one is called you can call Flush on your ChangeQueue implementation. This will have the system call all relevant Apply* methods in order if there are changes for those. There is also a NotifyDynamicUpdatesAreAvailable, but in practice there is not much difference between it and NotifyBeginUpdates. When something changes you’ll get either NotifyBeginChanges or NotifyDynamicUpdatesAreAvailable first, followed by NotifyEndChanges. The idea is that you can signal your render engine to get ready for data between these two triggers. You’ll then Flush, handle all data and upload to your engine, after which you can continue.

RhinoCycles is implemented on top of the ChangeQueue. Although it is written in C# the RhinoCommon wrapper around the C++ ChangeQueue code is very thin, so it is pretty much similar in construct.

In RhinoCycles I called my ChangeQueue implementation ChangeDatabase.

Places to look at related to this are:

In the ChangeDatabase note all the Apply* overrides

In my implementation I added a Synchronize method to start the data upload process to Cycles

You’ll find the different Upload* methods also in the ChangeDatabase. The main UploadData method is in RhinoCycles/RenderEngine.UploadData.cs at 75f16a859f3dd4be4b89bfce1d8830077a25afbc · mcneel/RhinoCycles · GitHub

So to react to light changes you’ll wait for NotifyEndChanges, call Flush on your ChangeQueue implementation. The mechanism will call your implementation of ApplyLightChanges.

This is pretty much what you do also when you first start your engine and what you hopefully already have implementation, barring the NotifyEndChanges. Instead you’d have called CreateWorld, followed by a Flush to have your Apply* methods triggered.

1 Like

Thank you very much, it was really helpful!
I had some troubles realizing the differences between ChangeQueue and EventWatcher (I thought somehow they had to be combined together). I have some quick questions in order to clear out these concepts and how to use them in my renderer.

  1. Flush: I just added Flush(true) in NotifyEndUpdates() and that made the whole mechanism to catch user’s reactions successfully! Is this the only thing I have to add in order to make change queue work regarding the User-Rhino interaction?

  2. What type of tasks should be carried out by the renderer between NotifyBeginUpdates() and NotifyEndUpdates() ? I have a rendereInit(_scene, _options) in my renderer, but I have inserted it in the DisplayMode just before calling rendering the scene.

  3. Figuring out what ChangeQueue does I am not sure what’s the purpose of EventWatcher. Is it for catching other GUI-related user actions? Is there any sample code for the EventWatcher ?


  1. That is enough.
  2. That entirely depends on your renderer. I have for Raytraced almost nothing other than logging really. You may have seen that for both Notify* calls I check whether the viewport is locked (user has clicked the lock icon in the HUD) and just return if that is the case. The idea is that the user can prevent the viewport with realtime display integration from updating if they choose to do so.
  3. Before the ChangeQueue was introduced you had to write code that included an event watcher. Since that was going to be pretty much the same for all renderer integrations we decided to create a mechanism that does all the reacting to events in the document and handle a lot of the logic that can be quite complex. For instance the ChangeQueue will fully handle geometry, block instances, materials, lights etc. All code that each render engine integration would have to write on their own. This is now centralised in the ChangeQueue. That also means that if there is a bug in code handling changes you can blame us, and we fix it - and everybody building on top of the ChangeQueue benefits from that. Under the hood the ChangeQueue builds on top of the EventWatcher and DisplayConduit. So, when you build on top of the ChangeQueue you don’t have to worry about events, changes to the document and so on.

When you have more questions feel free to ask. Maybe useful to start separate topics for each of your future questions.

1 Like