Indigo Renderer plug-in

Hi all,

Just opening a dedicated thread for chat about Indigo Renderer ( plug-in development!



Good move (:

Do you know about plans for a Rhino plug-in? @tom_svilans

Hey Giulio, we’re assembling and discussing on the Indigo side. I have a work-in-progress exporter that basically works, but we’re trying to coordinate to get something properly done.


@nathanletwory Just installing VS2017 and getting setup now, but is the ChangeQueue available on the C++ side as well? I think we may go the C++ route for now on the Windows side, and then see what to do about Mac…

Just out of curiosity, is this primarily because of programming language familiarity or is there a different reason?

Yes, RhinoCommon ChangeQueue essentially wraps the C++ change queue.

If you’re thinking of targetting both platforms I strongly suggest using RhinoCommon. Yes, you will have to write some P/Invoke interface with Indigo if it is implemented with C/C++, but that will be a minor pain. Using RhinoCommon you will be able to use the Eto.Forms cross-platform UI library we’re using ourselves to implement panels and UI for commands cross-platform. This is the road we take for the Cycles integration as well.


1 Like

I’m comfortable in either C++ or C#, but I think it’s primarily a matter of straight-forwardness: the Indigo SDK is in C++ and it would be in several ways easier and more maintainable to have the plug-in in C++ as well. As far as I understand, the Rhino 6 SDK is almost portable to Mac (something about MFC being removed?).

Anyway, I’ve started wrapping some of the Indigo SDK to see how tricky it is. So far, so good. If I get some time in the next few weeks, I’ll try to get a working example from Rhino in .NET at some point.

Cycles is also C++, but having a thin wrapper around it for .NET makes life much easier, especially wrt GUI. As you may already know there is no C++ SDK on the Mac, but RhinoCommon (the .NET SDK) is available. That combined with Eto.Forms and you have the recipe for cross-platfrom plug-in development.

Feel free to check out the .NET wrapper I created for Cycles:

together with the simple C API:

Another added bonus with using RhinoCommon is that you can easily create an API for your plug-in that can be called from Grasshopper and Python.

We have a command line application that we wrote that automatically generates pInvokes for a set of C API functions that you would expose for Indigo. It isn’t well documented and really only used internally, but we have no problem sharing it to see if that would help. There are also several other C++ binding projects out there that could assist in automating to process of creating pInvokes.

Yep, I’ve been using this as a guide for the Indigo wrapper, super helpful.

It’s pretty straight-forward at the moment, though it may need a bit more thought once it gets into the plug-in. I’ve set that up as well, so I’ll try to flesh it out and get them working together at a basic level, then make it pretty from there.

Yeah, I do like the options of having it then exposed to all sorts of other things - like GH and Python.

At the moment, doing all the pInvoke stuff manually is sort of a welcome bit of mindless work. I’ll get the bare minimum in to see how much more needs to be wrapped.

Wouldn’t mind trying out your app, though, if it’s available! Could you send it to tom dot svilans at gmail dot com?

This will probably take a little tweaking to get it just right for you. The application is called methodgen and I just copied the V6 version of this over to a public branch of our rhinocommon gituhub site


There’s also a guide wrapping code more in general (with also Mac in mind):

and a small methodgen “end user” guide (not regarding setup but regarding how to use it), here:

Thanks for that.

I’m slogging through a wrapper using pInvoke at the moment. The tricky thing always is classes with this method. I’m a bit hesitant with passing pointers around (void* -> IntPtr), though maybe someone can advise on the boons / dangers of this? I.e. create a class instance on the native side -> return a pointer to it to the wrapper / .NET interface as a IntPtr -> pass that IntPtr to the next wrapped function. I’ve run into some casting issues there, though…

The easiest way seems to be to keep all the references in vectors and maps on the native side, and refer to them by index / id, which looks like the way CSycles does it.

@nathanletwory Hey Nathan, I notice you’ve written a Database class to hold changes / data from the ChangeQueue. This looks specific to RhinoCycles, but seems like a good, generic way to access data from the ChangeQueue. Otherwise, I can’t find a documented example of accessing stuff from the ChangeQueue… the render examples and your articles gloss over that:

  1. Add the ChangeQueue to the RenderContext
  2. In Render(), call ChangeQueue.CreateWorld()
  3. Missing -> Get ChangeQueue mesh / object / light data… ?
  4. Profit.

EDIT: Nevermind, I am an idiot. But if your renderer is initialized at the start of Render(), you need some way to add scene data to it after that, and I’m not sure at what point ChangeQueue.ApplyMeshChanges(…), etc. happens, and what if you need a reference to your renderer there… Is this where the Database classes come in handy? To store the mesh changes and expose them when setting up the renderer?

I looked again at the MockinBird ChangeQueue article, and indeed some important parts are left unsaid. I’ll improve the article tonight, but until then the most important bits to know are:

Override and implement at least NotifyEndChanges(). When that is called by the underlying system you know changes have been collected. To get those you issue a call to base class Flush(). You can see from the linked API doc the order in which the Apply* functions of your implementation get called.

If you are doing a modal renderer, then you actually don’t need the NotifyEndChanges(), but after CreateWorld() you can directly call Flush().

The ChangeDatabase et al I mainly use to map between Rhino and Cycles data IDs.

Hey Nathan, thanks a lot for that. I’ve been very busy lately but still dipping in every now and then. I’ll check out the updated article when I get some free time.

Quick one - or maybe not so quick… - what is the logic behind having a Client and Scene object for your Cycles wrapper? It seems all the Client is used for is logging and holding a reference to a Scene? I’m a bit confused about why that is the entry point and not Scene… if you have a minute to shed some light, that’d be great!

By the way, are you also based at the Barcelona office?

1 Like

Pretty interesting discussions getting place around here :wink: