Community
3ds Max Programming
Welcome to Autodesk’s 3ds Max Forums. Share your knowledge, ask questions, and explore popular 3ds Max SDK, Maxscript and Python topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Reference bitmap textures in an array based on bitmap name with maxscript

6 REPLIES 6
Reply
Message 1 of 7
lukep452
603 Views, 6 Replies

Reference bitmap textures in an array based on bitmap name with maxscript

I'm looking at writing a script that will take the selected bitmap textures in the slate editor, and then automatically connect the nodes to the correct slots on the objects material. I've chosen to do it based on bitmap name as part of the script will make the name of the bitmap node the same name as the image filename.

 

I can then connect the diffuse texture map to the base color map slot of a physical material by searching the selected nodes for bitmap textures with "_Diffuse" in its name, and then doing the same for the other selected nodes in the array ("_Roughness", "_Normal", etc etc).

 

However I'm having trouble search through the array and separately get each selected node to connect to their intended slots, currently this version of the script works but it will just connect the last node in the array and connect it to the base color map slot on the material:

on btn5 pressed do
(
	if sme.IsOpen() do
(
	v = sme.GetView sme.activeView
	pm = physicalMaterial()
	if (node = (v.GetSelectedNodes())[1]) != undefined do
	map = node.reference
	(
		if iskindof map Bitmaptexture do $.material.base_color_map = map
	)

)
)

I've tried a few different things to separate objects in selected nodes based on name including using matchpattern() but I cannot figure it out, I think at the very least I am ruining the syntax when I try to do anything too complex.

 

Any help please?

6 REPLIES 6
Message 2 of 7
denisT.MaxDoctor
in reply to: lukep452

This is a very typical mistake related to the use of "$".
If multiple nodes are selected, "$" means a collection of nodes, if only one node is selected, it means a node.
Therefore, when you apply:

 

$.prop = x

 

in the multiple case, it will assign the value "x" to all nodes at the same time.

 

So never use "$" in the code. You only need it for "dirty scripting" in the MAXScript listener or for quick tests. 
Use, for example, "selection" which is always collection.

Message 3 of 7
lukep452
in reply to: denisT.MaxDoctor

My usecase for this script is simply to apply a set of textures to only ever a single material/object at a time. My use of $ here I guess is a simple way of getting that single material as a target for the bitmap textures.

This should be fine in this case to use $, no? My main issue is getting all the selected bitmaptexture nodes to connect to the respective slots on the selected material node. Quite literally this is a script just to save having to manually connect each texture to each slot on a material.
Message 4 of 7
denisT.MaxDoctor
in reply to: lukep452

 

 

fn mapPhysicalMaterial mat texmaps = 
(
	name_mapper = 
	#(
		#("*_diffuse", 	 #base_color_map),
		#("*_normal",  	 #bump_map),
		#("*_roughness", #roughness_map),
		#("*_metalness", #metalness_map),

		-- or for example:
		
		#("*_D", 	 	#base_color_map),
		#("*_N",  	 	#bump_map),
		#("*_R", 		#roughness_map),
		#("*_M", 		#metalness_map)
		
		/*
		... and so on 
		*/
	)
	
	if iskindof mat PhysicalMaterial do
	(
		tex_set = #()
		
		for tx in texmaps where iskindof tx BitmapTexture do
		(
			if tx.filename != undefined do 
			(
				file = getFilenameFile tx.filename  
				for k=1 to name_mapper.count where matchpattern file pattern:name_mapper[k][1] do
				(
					setproperty mat name_mapper[k][2] tx
					append tex_set #(tx, name_mapper[k][2])
				)
			)
		)
		tex_set
	)
)

/********* USING:

xx = getfiles (pathConfig.appendPath DOWNLOAD_DIR_ "* _*.jpg")  -- these are my test bitmap files
txs = for x in xx collect (bitmaptexture filename:x)

mat = PhysicalMaterial name:#test_mat
obj = box name:#test_obj material:mat

mapPhysicalMaterial obj.mat txs

*/

 

 

 

I believe you can easily adapt it to your needs. Feel free to ask questions, if any...

Message 5 of 7
lukep452
in reply to: denisT.MaxDoctor

Wow awesome thank you!


I've played with some parts of it and got it working well and am managing to feed the grabbed texture files from a seperate getSavePath function on another button.

 

However, how would I go about ignoring the creation of the test obj box and instead just apply the newly created material to the currently selected object? Changing the line:

obj = box name:#test_obj material:mat

 to anything relating to $, when I later call the function 'mapPhysicalMaterial' it doesn't like it.

 

Additionally, I can't figure out how to get the new material to immediately show in the current sme view. I've done it before with createnode function and a getView but I can't work it out in this instance.

Message 6 of 7
denisT.MaxDoctor
in reply to: lukep452

fn mapPhysicalMaterial mat texmaps = if iskindof mat PhysicalMaterial do
(
	name_mapper = 
	#(
		#("*_diffuse", 	 #base_color_map),
		#("*_normal",  	 #bump_map),
		#("*_roughness", #roughness_map),
		#("*_metalness", #metalness_map),

		-- or for example:
		
		#("*_D", 	 	#base_color_map),
		#("*_N",  	 	#bump_map),
		#("*_R", 		#roughness_map),
		#("*_M", 		#metalness_map)
		
		/*
		... and so on 
		*/
	)
	
	tex_set = #()
	
	for tx in texmaps where iskindof tx BitmapTexture do
	(
		if tx.filename != undefined do 
		(
			file = getFilenameFile tx.filename  
			for k=1 to name_mapper.count where matchpattern file pattern:name_mapper[k][1] do
			(
				setproperty mat name_mapper[k][2] tx
				append tex_set #(tx, name_mapper[k][2])
			)
		)
	)
	tex_set
)

mapped fn applyMappedPhysicalMaterial node texmaps force:off = if isvalidnode node do 
(
	if not iskindof node.mat PhysicalMaterial and force do node.mat = PhysicalMaterial()
	mapPhysicalMaterial node.mat texmaps
)

/********* USING:

applyMappedPhysicalMaterial selection texmaps -- all selected nodes
applyMapppedPhysicalMaterial selection[1] texmaps -- first selected node

*/
Message 7 of 7
lukep452
in reply to: denisT.MaxDoctor

This script is far out of my skillset by this point but it seems so close to working, my entire script is pretty functional now however on your post, I can't call the function mapPhysicalMaterial while it's inside the mapped function applyMappedPhysicalMaterial because of its local variable references. If I move the mapPhysicalMaterial fn outside of the btn codeblock, it seems like it can reference it but it throws up undefined "map" errors.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report