Enscape seems to be completely clueless about this issue, so I decided to look into issues on technical levels.
First, I suspected Object ID & Material ID, and as it turned out they are static and can’t be altered on worksession. After a bit of trying and error, I’ve noticed that Material Index do get renumbered everytime worksesion gets updated. So, could this be a case of loss of the materials on enscape?
So some questions here, does anyone know what Rhino or Enscape use Material Index for? And, would it be possible to force Rhino to not-renumber them?
I may well be all wrong about this. But it would be great if anyone could shine some light on this issue and hopefully help enscape to resolve this long outstanding issue…
Here are before and after screenshots showing the little code I sued and how Material Index are renumbered after worksession update.
I personally am not aware of a bug logged about this with us. That said, the best way to get the correct materials from objects regardless of where they originate from is to use the .RenderMaterial property on a RhinoObject instance.
from Rhino.Render import RenderTexture as rt
import scriptcontext as sc
for ob in sc.doc.Objects:
render_material = ob.RenderMaterial # get a RenderMaterial
oldskool_material = render_material.SimulatedMaterial(rt.TextureGeneration .Allow) # from the RenderMaterial get the Material
Not sure why anybody in this day and age would want to use the old-school Material. We’re trying to move people to use the RenderMaterial approach instead.
Thank you for an interesting thought, but this method doesn’t seem to be able to get the materials from the objects that are on worksession though; or am I missing sth?
Ah, right. I kinda forgot about the fact this is about worksessions. Could you replicate the OP from the Enscape forum here? I have no login there, so can’t read it.
I don’t know much about the worksession part of our scripting API, I’m asking around how one is supposed to handle those.
That said, on the very first question in your first post: the material index a material or object (ob.Attributes.MaterialIndex) is an index into the old-school materials table. This table works in a peculiar way as that after adding a material to an otherwise empty document doesn’t show in that Materials table. Entries show up only once a material is assigned. Say you add after the material two boxes to the model. Now assign your material to one box. You’ll find that the Materials table now contains one entry. Assign your material also to the other box. You’ll find that the Materials table now contains two entries. A material will have as many entries in the Materials table as it is being used: objects, layers, etc. Indices change on model updates, and I guess that is what is happening here too on activating another attached model.
Anyway, this is all very cumbersome with the old method that includes handling everything yourself, including using the Materials table.
For rendering solutions we’ve introduced the ChangeQueue mechanism in Rhino 6. This unifies a lot of work that render engines each otherwise would have to do themselves: meshing objects, handle block instance hierarchies, worksessions, and so on.
That is why I don’t have to worry about worksessions and all that, because Raytraced and Rhino Render (both running the Cycles render engine) are implemented using the ChangeQueue mechanism. This handles all the intricacies of worksessions, block instances and so on for the renderer. I automatically get all the RenderMaterials for all objects even after another attached model has been made active. I don’t have to match and rematch material indices from the old-school materials. Instead I get to use all the modern, good bits of the Rhino RDK.
Thank you for the detailed explanations! It sounds like Enscape somehow hasn’t fully implemented ChangeQueue mechanism then, despite them supporting only Rhino 6 & 7…
I guess they’re still using the old method of doing everything themselves. I don’t know how they are doing it. But perhaps they are not rereading the new indices from the materials table?
I just tested updating an attached model while having Raytraced running, and that works just fine. New geometry have the materials showing as expected.
Ok, after some asking around you can do something like this to iterate over all objects, including referenced objects from worksession attached models:
from Rhino.Render import RenderTexture as rt
import scriptcontext as sc
import Rhino
import Rhino.DocObjects
obenum = Rhino.DocObjects.ObjectEnumeratorSettings()
obenum.ReferenceObjects = True
for ob in sc.doc.Objects.GetObjectList(obenum):
print ob
render_material = ob.RenderMaterial # get a RenderMaterial
if render_material:
oldskool_material = render_material.SimulatedMaterial(rt.TextureGeneration.Allow) # from the RenderMaterial get the Material
print render_material, render_material.Name, oldskool_material
This way there is no need for knowing material indices and to try fiddle around with matching them up and so on.
Hi @sungbok.song , I only show how to access the modern material API for objects that are references (brought in from worksessions). This in itself does not fix the problem of Enscape not managing the materials correctly - that is up to Enscape devs to fix on their side.
Unfortunately, this is a solution not for us but for Enscape to fix the issue. This solution is also based on a series of the assumptions we made so it may not be right, but only Enscape knows…
if anything it would be great if you could write to escape about this forum discussion, and that may help to resolve the issue once and for all…