Current Renderer Events

I was looking here and there but I can’t find any information on this. Questions regarding RhinoCommon:

Is there any builtin event informing that current rendering engine has started/stopped rendering?
Is there a way to know that current rendering engine has been changed by user?
Is thera a way to trigger change of current rendering engine? - Ok I have this initially thought it would be just setter on this property.

Guys any thoughts in that matter? @andy @nathanletwory

1 Like

Subscribe to BeginCommand and EndCommand, track the command name for Render.

RhinoApp.RendererChanged

2 Likes

Thanks for that. I’m using already Begin/End Command, while Begin seems to fit my needs the End triggers sometimes in other place than desired for me, so i just moved with it to wait for Idle.
Anyway, concluding there is no specialized event for that.

Ahh It’s in RhinoApp!

I’m trying to find a way to integrate Cycles wit RN on my own before any suitable way will become availible. Doing hidden and display culled bake seems to work but to some ammount of objects if ill try to do this with 500k objects Rhino enters eternal Not Responding state.

As long as you are aware that accessing RhinoCycles directly for geometry/scene manipulation outside of the changequeue mechanism and any RhinoCommon API is not supported.

Without seeing any code hard to say what you’re doing. And as said accessing RhinoCycles data structures is not supported - for instance I can’t promise the code doesn’t change between service releases. That said show me what you’re doing and I’ll try to give advice.

notSupported != notPossible - Reflection can do magic but ofc it would be prone to code changes.

Nothing unusual to show. I listen to display mode change or to command and insert all elements to document (only difference that objects aren’t drawn thanks to display pipeline object culling override).
I rather assume the biggest problem here is still putting all elements in the document thats the part which seems to cause lag - actually two things one bake second cleanup - and when numbers gets big it just “hangs” (so much work to do that main thread seems to be stucked).

One thing which I discovered that “Handling mesh instance [current/total] material” can last bit longer when we go beyond 10k objects.


That being said seems every “baking” way will have side effects and will be suboptimal. Due to experimental way I could create own MeshInstance’s and call ApplyMeshInstanceChanges [as you handle it here] but without knowing from where I can obtain vaild IntPtr’s I won’t be able to do any thing. Obtain as my objects are already InstanceDefinitions so I assume those are already there so I would need to know which one is related to which InstanceDefinition Guid.

Putting in huge amounts of objects can indeed be detrimental to startup performance. I am planning on changing strategy here in ways that most likely will break any code that uses reflection based on a certain version.

For Raytraced, how are you handling updating of data while Raytraced is already running? Changes in Rhino Nature to eco systems, domains, etc.

It remains unclear to me how and when you are inserting your data into the document. Also I guess I don’t understand the display pipeline object culling override - what method override is that, on what class?

IntPtrs are generated by the underlying changequeue system. These meshes and mesh instances live only until the end of a flush (meaning all Apply* methods have been called in order). You should not mess with these, not try to create such pointers since you don’t know how this is implemented - you can create severe instability. (also not sure how you would do that without reverse engineering, which is not really allowed according our EULA).

Again, I don’t see the picture you’re trying to paint here, I don’t understand what classes you are using, how you implement things and how it all fits together. I only get the sense that what you try to do is dangerous. Especially the bits about creating your own MeshInstances and calling ApplyMeshInstanceChanges on your own. That in itself is not going to work.

In general puting lots of objects in doc is always a bad idea. However, only possible option now.

I’m just speculating and asking as IntPtr is usually pointer for native interop where I’ve nothing to look for as you mentioned.

In short listening to this and if this is found bake - the same for cleanup when no not found. Updates are actually pretty interesting point as I managed to do it on small ammounts of objects - force set found raytraced modes to wireframe cleanup and rebake and change back to raytraced. However I found it too long with bigger counts and on data update I do doc cleanup and raytraced goes to wireframe (assuming user will make more changes and will change it on his own back to raytraced).

No magic. For Viewport as above, for Modal on BeginCommand both with typical AddInstanceObject.

According to this ObjectCulling is first so will discard matching object drawing, so I’m adding proper attribute to object on bake and checking it in my derived conduit using this override.

Hope this clarifies a bit. Dangerous? Is it? Regular object inserting doesn’t seem to be so dangerous. As I said reflection part was only speculation and searching to find some valid way out.

1 Like

Right, that is what I was afraid of. This is not utilizing the changequeue mechanism, and not triggering changes so that they go through without having to toggle away from Raytraced and back.

Do I understand it correctly that this is all so you don’t have to back your geometry in the file so that it isn’t there when saving? But in the end you still bake for now since you AddInstanceObject?

I see that you are using DisplayConduit. I got confused as you were saying DisplayPipeline object, which is a bit different.

The dangerous part was about fiddling around with IntPtr and calling into RhinoCycles from outside the ChangeQueue mechanism (Apply* methods).

1 Like

Mhm… but if I would do this without jumping to wireframe and back, ChangeQueue is called for each object added and deleted instead of running once for two collections (deleted/added). This creates huge overhead and unbearable wait time on updates.

It’s not only this. First I have to pass data somehow to Cycles so doc (at least AFAIK) is the only middle ground where we can meet now. This creates a bunch of problems - like overloading doc, object visibility in viewport (this amounts takes vp to its knees), autosave happening during rendering causing enormous file sizes due to object count in the scene.

Yes, as I can’t find any other way. If there is something else let me know I’ll test it but I guess there’s not, that’s why I speculated about other hooks but as we both noticed IntPrt is a show stopper.

Sorry about Display stuff confusion, my fault not being precise.

I’m just exploring what is doable or not. Don’t get me wrong I’m waiting for this since 2018, I don’t want to sound pushy (everyone has their own schedules), I just want to do something with it, stop waiting and move it forward. At this point seems that this would work for Modal rendering as during it all stuff is locked and autosave is not called, so it can be baked on BeginCommand and removed on Idle. Viewport rendering handling using these workarounds is far from ideal, however, a bird in the hand is worth two in the bush.

Perhaps in this case you could try pausing the current realtime render viewports:

For each RhinoView query the RealtimeDisplayMode. If the instance you get back is not null you can use the Paused property to manipulate.

For instance:

RealtimeDisplayMode dm = doc.Views.ActiveView.RealtimeDisplayMode;
if(dm!=null)
{
    dm.Paused = true;
}

Once you unpause the viewport and wiggle it a bit all changes should get realized.

Maybe this will work for you?

This method is used in TogglePausedActiveRealtimeViewport. You could try using that function manually in a simple scene where you set a viewport to Raytraced, then pause it, add a couple of objects, then unpause it.

I thought about pausing at some point but the idea floated away. Thanks for bringing it back. Jumping straight to code and will try it and will be back with results. About manual tries, a couple of objects can work as my initial update approach, but this has to work with 10k at a minimum.


Initial ride with manual pause…

I’m hitting many times not responding state this time I’m not sure what is the cause of it. I will put timers everywhere to diag whats actually going on, as it looks like this time its not doc bake/cleanup fault.


@nathanletwory Ok, I found the bottleneck. Cleanup of the doc takes an insane amount of time. Delete for 40k objects can take from ~90sec up to even ~300sec - To be honest I’m not sure why these times vary. On the other hand bake of 100k is below one sec surprisingly.

So I guess this is the point where I can’t do much on my own. Maybe @dale may know the answer on how to delete so many objects quickly? This delete method seems to be very slow in high counts.

[Adding this as followup]

Deleting 2876 object takes +/- 6sec (lowest 5.79 / highest 6.15) isn’t that long for so few elements?

Besides that pause seems to do the job. However I still don’t know why sometimes on manual pause it enters not responding state. Cycles bottleneck is mentioned “Handling mesh instance [current/total] material” it can really take a long while when we go 50k+ objects. However, it stays fairly responsive updating each 1-5k message so users see something is rolling.

Sorry, @dale no emergency here. Those long deletions times are clearly related to something behind ChangeQueue or the rendering process itself. If I will move the cleanup part back to Idle (instead of sequence pause render > cleanup > start render) 10k+ objects are deleted in a fraction of a second.

After various tests in this matter it turns out that the only valid way is to break this into two pieces and by any means do not use Pause (after a longer while I discovered this brings more headaches than solutions). So:

  • go to wireframe
  • redraw views
  • schedule the job to be executed on Idle state
  • in Idle state do the job
  • at the end of Idle it should be continued to revert it back so
  • go to raytraced
  • redraw views

In such construction Delete for 10k+ takes ~0.1 sec (instead of 30 to 60sec). Hope this will save lots of hours of exploration for future readers.

To be clear I deny my earlier statement on this. In this particular case, something behind is causing huge slowdowns and very long not responding states.

Currently the “Handling mesh instance …” is the longest part (ofc if we’re in high object counts).