Script to apply materials to objects by name

Script to apply materials to objects by name

danZL2KU
Participant Participant
2,105 Views
23 Replies
Message 1 of 24

Script to apply materials to objects by name

danZL2KU
Participant
Participant

Hi

 

We currently link our models into 3ds max from Revit by material name. For example:

-Plywood Face Natural
-Plywood Edge Natural

 

We then select each of these, one by one and apply a material to them from our library.

I have set up the materials with the exact same name.

 

It is quite simple but it takes time to apply as we can have 20 or 30 objects/materials.

 

Is there a script which I can run to do this:

It would be something like this.

1. Select all objects.

2. Apply materials from a library which have a name match.

 

Thanks

 

Dan

www.madeinply.co.uk

 

 

 

0 Likes
Accepted solutions (1)
2,106 Views
23 Replies
Replies (23)
Message 2 of 24

denisT.MaxDoctor
Advisor
Advisor

 

fn applyMatByName nodes: mats: exact:on = 
(
	if nodes == unsupplied do nodes = geometry as array
	if mats == unsupplied do mats = currentMaterialLibrary
		
	applied = 0
	for node in nodes do
	(
		for mat in mats do
		(
			matname = mat.name
			if not exact do matname += "*"
				
			if matchpattern node.name pattern:matname do exit with (
				node.mat = mat
				applied += 1
			)
		)
	)
	applied
)

/********* run below code to execute: *********

applyMatByName exact:off

*/

 

 

you have the additional #exact option. If #exact is FALSE, all nodes that have a unique suffix in the name but have the same base name as the material will receive the material. If #exact is TRUE, only nodes with an exact match by name will receive the material. 

 

 

 
0 Likes
Message 3 of 24

danZL2KU
Participant
Participant

Message was deleted. Did you have a solution?

0 Likes
Message 4 of 24

denisT.MaxDoctor
Advisor
Advisor

@danZL2KU wrote:

Message was deleted. Did you have a solution?


be patient... I've just improved the version 😉

0 Likes
Message 5 of 24

danZL2KU
Participant
Participant

Sorry was just making sure I had not missed anything. Testing it now. Thanks

0 Likes
Message 6 of 24

danZL2KU
Participant
Participant

I have created 3 boxes and 3 materials. Both are named the same. Run the script but nothing? Can you provide any more assistance to get this working?

0 Likes
Message 7 of 24

denisT.MaxDoctor
Advisor
Advisor

where are your materials? the script works with the currentMaterialLibrary by default. You can make or load the current library by loading it from the user interface. You can also put any material from the material editor into the current library.

Furthermore, you can use materials in the material editor as a list of materials in the function:

 

applyMatByName mats:meditmaterials exact:on

 

 

0 Likes
Message 8 of 24

danZL2KU
Participant
Participant

The materials are all saved in my own library.

Your extra code worked when I had those materials in the material editor. However, I don't want to have to take this step of adding them here.

Can we run this and tell 3dsmax to look in my library?

 

0 Likes
Message 9 of 24

denisT.MaxDoctor
Advisor
Advisor

how does the #exact option work?

 

let's say you have objects: "bricks", "bricks_001", "bricks_002", "bricks_large", "bricks_for_small_pigs"...

 

if #exact is TRUE, the material named "bricks" will only apply to the "bricks" node, but with #exact FALSE it will apply to all of those nodes because they match the pattern "bricks" (the exact name of the material).

  

0 Likes
Message 10 of 24

denisT.MaxDoctor
Advisor
Advisor

@danZL2KU wrote:

The materials are all saved in my own library.

Your extra code worked when I had those materials in the material editor. However, I don't want to have to take this step of adding them here.

Can we run this and tell 3dsmax to look in my library?

 


technically you have to load the material library yourself... but we can add the loading option:

 

 

loadMaterialLibrary <filename_string>

 

 

 

 

or 

 

 

fn applyMatByName nodes: mats: exact:on = 
(
	if nodes == unsupplied do nodes = selection as array
	if iskindof mats string do
	(
		if doesfileexist mats do mats = loadTempMaterialLibrary mats
	)
	
	if mats == unsupplied do mats = currentMaterialLibrary
		
	applied = 0
	for node in nodes do
	(
		for mat in mats do
		(
			matname = mat.name
			if not exact do matname += "*"
				
			if matchpattern node.name pattern:matname do exit with (
				node.mat = mat
				applied += 1
			)
		)
	)
	applied
)

/********* run below code to execute: *********

applyMatByName mats:"c:/.../my_material_libray_path/my_material_library_name.lib"

*/

 

 

0 Likes
Message 11 of 24

danZL2KU
Participant
Participant

For me, it will work better if it's an exact match only. i.e. exact off

---

But how do I get it to look in my library, not the current one?

 

 

 

0 Likes
Message 12 of 24

denisT.MaxDoctor
Advisor
Advisor

 

 

 

applyMatByName mats:"c:/.../my_material_libray_path/my_material_library_name.mat"

 

 

 

with this option your library will be loaded and used as material list but will not become the current library

 

 
0 Likes
Message 13 of 24

danZL2KU
Participant
Participant

This is my library location:

 

G:\My Drive\2 production\1 design\2 3ds max\materiallibraries\Birch_Plywood.mat

 

Does not work. I am confused if it should be .lib or .mat?

 

0 Likes
Message 14 of 24

denisT.MaxDoctor
Advisor
Advisor

by default the material library file extension is ".mat" 

0 Likes
Message 15 of 24

denisT.MaxDoctor
Advisor
Advisor

 

fn applyMatByName nodes: mats: exact:on = 
(
	if nodes == unsupplied do nodes = selection as array
	if iskindof mats string do
	(
		if doesfileexist mats do mats = loadTempMaterialLibrary mats
	)
	
	if mats == unsupplied do mats = currentMaterialLibrary
		
	applied = 0
	for node in nodes do
	(
		for mat in mats do
		(
			matname = mat.name
			if not exact do matname += "*"
				
			if matchpattern node.name pattern:matname do exit with (
				node.mat = mat
				applied += 1
			)
		)
	)
	applied
)

applymatbyname mats:@"G:/My Drive/2 production/1 design/2 3ds max/materiallibraries/Birch_Plywood.mat"

 

 

the path looks weird for me, but the code above must work

 

the function returns the number of nodes with re-applied materials.

 

 

0 Likes
Message 16 of 24

danZL2KU
Participant
Participant

Just cant get it working. Does it work for you to load from a library?

0 Likes
Message 17 of 24

denisT.MaxDoctor
Advisor
Advisor

of course it works for me...  every different way!

 

the last attempt to help you:

 

 

/***************************** TEST SCENE *****************************/
--- execute all steps ...


-------- 0. Define the function:
fn applyMatByName nodes: mats: exact:on = 
(
	if nodes == unsupplied do nodes = selection as array
	if iskindof mats string do
	(
		if doesfileexist mats do mats = loadTempMaterialLibrary mats
	)
	
	if mats == unsupplied do mats = currentMaterialLibrary
		
	applied = 0
	for node in nodes do
	(
		for mat in mats do
		(
			matname = mat.name
			if not exact do matname += "*"
				
			if matchpattern node.name pattern:matname do exit with (
				node.mat = mat
				applied += 1
			)
		)
	)
	applied
)


-------- 1. Create new empty scene:
delete objects
gc()

names = #("checker", "stucco", "smoke", "noise")


-------- 2. Create four teapots:
nodes = for k=1 to names.count collect
(
	teapot name:names[k] radius:20 mapcoords:on rotation:(eulerangles 0 0 90) pos:[(k-1)*50,0,0] wirecolor:gray
)


-------- 3. Create four materials and put them in new material library:
matlib = materialLibrary()
mats = for k=1 to names.count collect
(
	mat = standard name:names[k] diffusemap:(createinstance (execute names[k])) 
	append matlib mat	
	mat
)


-------- 4. Save temp material library:
matlib_name = @"c:/temp/test_matlib.mat"
saveTempMaterialLibrary matlib matlib_name


-------- 5. Apply materials by name for all objects in scene using material library path:
applymatbyname nodes:objects mats:matlib_name 

 

 

 

 

 

0 Likes
Message 18 of 24

danZL2KU
Participant
Participant

I have it working. I got it to work just before your last message, however, it only seems to work if the objects in the scene already have a material applied.

---

I had a scene with 3 objects. Run the script and it returned 1 result.

I did this again but applied materials from the material editor slots to the 3 objects then run the script and it returned 3 results.

Any idea why that is?

0 Likes
Message 19 of 24

danZL2KU
Participant
Participant

Figured it out. I have to select the objects and then run the script

0 Likes
Message 20 of 24

danZL2KU
Participant
Participant

I wonder if there is a way to create a button to run the script. So I can then select the objects and click the button?

0 Likes