Notifications
Clear all

[Closed] Instancing duplicate RPM Material Sub-Materials Script

Little script to re-instance RPMaterial sub-mats that have the same name and are the same class.

-- finds all like named materials in an RPMaterial and isntances them. 
-- Gavin Greenwalt
-- Straightface Studios, Seattle, WA
-- 11/9/11

fn instanceLikeMats objMat =
(
	if classof objMat == RPMMaterial do
	(
		matNames =  makeUniqueArray (for o in objMat.materials where o != undefined collect o.name)
		masterMats = for o in matNames collect ((for m in objMat.materials where m != undefined and m.name == o collect m)[1])

		for o in masterMats do
		(
			for i = 1 to objMat.Materials.count do 
			(
				if objMat.Materials[i] != undefeind and (objMat.Materials[i].name) == (o.name) and (classof objMat.Materials[i]) == (classof o) do
				(
					objMat.Materials[i] = o
				)
			)
		)
	)
)

print "Starting RPM sub-material istance hunt..."
for o in objects where o.material != undefined and classof o.material == RPMMaterial do 
(
	o.material.name = "RPMM "+o.material.materials[1].name
	instanceLikeMats o.material
)
print "Finished instancing RPM sub-materials."
4 Replies
1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

is it a problem or a solution?

It’s a solution.

When you create an RPM Material it just copies it to all of the passes. So if you make a change to the material in one pass it doesn’t propagate by default. THis way you can always copy a specific render pass material but the rest stay in sync as instances.

Quite a few years ago I suggested to Grant that I thought the best default for the same sub-material in RPM materials would be auto-instance rather than copy. He changed it for a while, but I think people must have complained ’cause he changed it back. I can see reasons why either way could be preferable, but I personally prefer the instanced option so your script is very welcome.

Cg.

why did I ask about a problem? because the solution that you gave doesn’t work right… I modified your code to make it work with Composite Material (i don’t have RPM as many of us) but I left the same algorithm.


  fn instanceLikeMats objMat =
  (
  	if classof objMat == compositematerial do
  	(
  		matNames =  makeUniqueArray (for o in objMat.materiallist where o != undefined collect o.name)
  		masterMats = for o in matNames collect ((for m in objMat.materiallist where m != undefined and m.name == o collect m)[1])
  
  		for o in masterMats do
  		(
  			for i = 1 to objMat.materiallist.count do 
  			(
  				if objMat.materiallist[i] != undefeind and (objMat.materiallist[i].name) == (o.name) and (classof objMat.materiallist[i]) == (classof o) do
  				(
  					objMat.materiallist[i] = o
  				)
  			)
  		)
  	)
  )
  
  t1 = timestamp()
  for o in objects where o.material != undefined and classof o.material == compositematerial do instanceLikeMats o.material
  format "time:%
" (timestamp() - t1)
  

try this scene setup:


  with undo off with redraw off
  (
  	delete objects
  	seed 0
  
  --	classes = #(Standard)
  	classes = #(Standard, Blend, Shellac)
  --	names = #("A", "B", "C", "a", "b", "c")
  	names = #("A", "B", "C", "A", "B", "C")
  
  	for k=1 to 100 where (random 1 5) == 1 do 
  	(
  		b = box name:(k as string)
  		b.mat = compositematerial()
  		for k=1 to b.mat.materiallist.count do b.mat.materiallist[k] = classes[random 1 classes.count] name:names[random 1 names.count]
  	)
  	gc()
  )
  

after executing your code you will see for example that:
objects[1].mat.materiallist[2] != objects[1].mat.materiallist[3]
objects[2].mat.materiallist[5] != objects[2].mat.materiallist[10]

and it’s wrong

also it will be better to make the material names comparison not case sensitive.

here is my version:


  fn instanceSimilarReplace mat = 
  (
  	local n = 1
  	local count = mat.materiallist.count
  	
  	while n < count do 
  	(
  		if iskindof (source = mat.materiallist[n]) Material do
  		(
  			for k=n+1 to count where iskindof (target = mat.materiallist[k]) Material and target != source do
  			(
  				if stricmp target.name source.name == 0 and (classof target == classof source) do replaceinstances target source 
  			)
  		)
  		n += 1
  	)
  )
  t1 = timestamp()
  for mat in (getclassinstances compositematerial target:rootnode) do instanceSimilarReplace mat
  format "time:%
" (timestamp() - t1)
  

as you see the first algorithm “works” [/i]faster than main. but it’s just because it’s not complete.

anyone who sees the better solution is welcome.