[Closed] Creating a MultiMatte render el. per layer
VRay has a render element called MultiMatte. It operates on either ObjectID or Material Effects Channel, and will take three IDs, one each for Red, Green and Blue.
If you don’t have VRay, this script won’t work. If you don’t have VRayScatter or MultiScatter and a huge scene, you probably won’t get the same errors…
I’ve written a script that works on a small scene but is breaking on a large scene.
It runs through the list of layers and gives a unique .gbufferchannel to all objects on each layer. Then generates one MultiMatte per three layers.
Layer01 objects are assigned gbufferchannel 301
Layer02 objects 302
Layer03 objects 303
Layer04 objects 304
Layer05 objects 305
Layer06 objects 306
etc
MultiMatte “Layer01Layer02Layer03” is 301 for Red, 302 for Green, 303 for Blue
etc, etc, through all layers.
It also truncates layers so that the MultiMatte name is <= 31 characters due to the EXR spec for channel names, but that’s irrelevant.
It gets the nodes on each layer using refs.dependents for each layer and then filtering out only the geometryClass nodes. This works fine on small scenes for some reason. But on my current scene with nearly 11,000 objects, it is breaking.
Here is an example of the layerRefs vs the filtered nodes:
layerRefs: #($VRS_GreenRoof_OrnimentalGrass01, ReferenceTarget:NodeSelection, ReferenceTarget:ReferenceTarget, ReferenceTarget:ReferenceTarget, ReferenceTarget:NodeSelection, ReferenceTarget:ParamBlock2, RMVisSetArray2:RMVisSetArray2, Controller:Bezier_Float, ReferenceTarget:ParamBlock2, RMVisSetArray1:RMVisSetArray1, $VRS_GreenRoof_MiscanthusClump02, $VRS_GreenRoof_Fescue02, $VRS_SucculentGarden_Base, ReferenceTarget:NodeNamedSelSet, ReferenceTarget:NamedSelSetList, ReferenceTarget:Scene, ReferenceTarget:ParamBlock2, VRayScatter, ReferenceTarget:ParamBlock2, VRayScatter, …)
layerNodes: #($VRS_GreenRoof_OrnimentalGrass01, $VRS_GreenRoof_MiscanthusClump02, $VRS_GreenRoof_Fescue02, $VRS_SucculentGarden_Base, VRayScatter, VRayScatter, VRayScatter)
The problem is with the highlighted VRayScatter objects.
It works fine a small test scene. It cycles through all layers even with VRayScatter objects and has no problem…
sigh
clearlistener()
fn keepChars str pass: = (
local killChars = case pass of
(
1: "abcdefghijklmnopqrstuvwxyz0123456_"
2: "abcdefghijklmnopqrstuvwxyz"
3: "bcdfghjklmnpqrstvwxyz"
)
for i = str.count to 1 by -1 where (local index = findString killChars str[i]) == undefined do str = replace str i 1 ""
str
)
fn cropString str charMax = (
if str.count > charMax then
(
str = keepChars str pass:1
if str.count >charMax then
(
str = keepChars str pass:2
if str.count > charMax then
(
str = keepChars str pass:3
if str.count > charMax then
(
str = substring str 1 charMax
)
else str
)
else str
)
else str
)
str
)
fn removeElementByPrefix pref = (
clearlistener()
local re = maxOps.GetCurRenderElementMgr()
for i = re.numrenderelements()-1 to 0 by -1 do
(
x = (re.GetRenderElement i)
elName = x.elementName
prefix = substring elName 1 pref.count
if prefix == pref do
(
format "Removing element %
" elName
re.REmoveRenderElement x
)
)
)
(
local re = maxOps.GetCurRenderElementMgr()
local el = multimatteelement
local groupsSoFar = 0
local startID = 300
removeElementByPrefix "LAY_"
for el = 1 to re.numrenderelements() do
(
re.GetRenderElement el
)
while groupsSoFar*3 < layerManager.count-1 do
(
layerGroup = ""
idGroup = #()
for i = 1 to 3 while (x = i+groupsSoFar*3) <= layerManager.count-1 do
(
layer = ILayerManager.getLayerObject x
layerRefs = refs.dependents layer
layerName = (cropString ((layerManager.getLayer x).name) 9)
layerNodes = #()
layerGroup += layerName
append idGroup (startID + x)
for o in layerRefs where classof (superClassOf o) == node and superclassof o == GeometryClass do
(
append layerNodes o
)
for obj = 1 to layerNodes.count do
(
if layerNodes[obj] != "VRayScatter" do
(
layerNodes[obj].gbufferChannel = x
)
)
format "LayerRefs: %
" layerRefs
format "Layer: %
" layerName
format "Objects: %
" layerNodes
format "ObjectID: %
" x
)
if idGroup.count < 3 do
(
append idGroup (idGroup[idGroup.count] + 1)
if idGroup.count < 3 then
(
append idGroup (idGroup[idGroup.count] + 1)
)
else()
)
layerGroup = "LAY_" + layerGroup
format "MultiMatte name: % is % characters.
" layerGroup layerGroup.count
format "IDs in MM: %
" idGroup
format "--------------------
"
if groupsSoFar*3 < layerManager.count-1 do
(
re.addrenderelement (el elementname:layerGroup R_gbufID:idGroup[1] R_gbufIDOn:(on) G_gbufID:idGroup[2] G_gbufIDOn:(on) B_gbufID:idGroup[3] B_gbufIDOn:(on) )
)
groupsSoFar +=1 --increment the groups counter
)
)
I know I have a small audience here (due to the specifics of the problem) but any thoughts would be appreciated.
cheers