Notifications
Clear all

[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