MAXScript: How to find duplicate texturemap names via maxscript?


#1

I have a large scene that uses a huge number of texturemap (bitmap, mix, composite etc. etc.), but many different texturemap have the same name, although they are different texturemap (not instances). How can I find texturemap with duplicate names and assign a new name to such a texturemap?
I tried different methods using uniqueName, but this did not give the desired result - some texturemap are renamed again and still have the same names, although they are different texturemap. Is there some quick and reliable way to do this?

Here is one of the methods I tried, but it didn’t give the desired result:
here mapsArray - all texturemaps array from scene


fn renMapsName mapsArray = (
		uniques = #()
		dups = #()
		for i in mapsArray where not (appendifunique uniques i.name) do (
			appendIfUnique dups i
		)
		
		for n in dups do (
			n.name=uniqueName n.name
		)
	)

renMapsName mapsArray

#2

I don’t have a good scene to test it so can’t really tell how bad it performs :slight_smile: cause it renames all the maps that share same base name whenever two of them have duplicate names.


keys       = #()
textures   = #()
duplicates = #{}

base_keys     = #()
base_textures = #()

for tex_class in textureMap.classes do
(
	for tex in getClassInstances tex_class do
	(	
		key   = toLower tex.Name		
		index = findItem keys key
		
		if index > 0 then 
		(
			append textures[ index ] tex
			duplicates[ index ] = true
		)
		else
		(
			append keys key
			textures[ keys.Count ] = #( tex )	
		)

		base_key   = trimRight key "0123456789"
		base_index = findItem base_keys base_key
		
		if base_index > 0 then 
		(
			append base_textures[ base_index ] tex			
		)
		else
		(
			append base_keys base_key
			base_textures[ base_keys.Count ] = #( tex )	
		)
	)
)

for index in duplicates do
(

	base_name = toLower (trimRight textures[ index ][1].Name "0123456789")
	
	j = findItem base_keys base_name
		
	i = 0
	for tex in base_textures[ j ] do
	(		
		tex.Name = base_name + (formattedPrint (i += 1) format:"03d")		
	)
)

#3

Thanks Serejah, but your method is renaming ALL texturemaps from scene, but it is necessary that only those that have the same names are renamed.
For example, there is a Fallow texturemap named “Map # 001” that contains two texturemap with the same names “Map # 001”. After processing, these two maps should be assigned new names (ie “Map # 002” and “Map # 003”). Other texturemaps that already have unique names do not need to be renamed.
Thanks again!


#4

No, it doesn’t rename all texturemaps.
What it does, it finds all texturemaps than have same name prefix and rename these maps. It discards numbers suffix and rename maps staring from 001 to the end.

Example:

mAp #001    -- name prefix 'map #'
MAP #535    -- name prefix 'map #'
map #855393 -- name prefix 'map #'
mAp #001    -- duplicate name, name prefix 'map #'. All maps starting with 'map #' will be renamed
Smoke #42   -- name prefix 'Smoke #', not going to be renamed

and the result:

map #001
map #002
map #003
map #004
Smoke #42

Maybe it is better to collect all the scene maps names and then find a new name for each duplicate that doesn’t collide with the rest of the existing names. Instead of renaming all the maps sharing the same prefix.


#5

No, no. There is no need to search for texturemaps only by prefix, since many maps will have the same prefix, but the suffix will be different, which means they are already different names. It is necessary to rename only those texmaps that have completely identical names along with the prefix and suffix.

_ren_before

_ren_after


#6

Actually Max has a method to rename maps, but for some reason it always increments map suffixes :frowning:

details

just a quick demo:

g = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
rename = g.coreinterface14.AssignNewName

textures = #()
for tex_class in textureMap.classes do
(
	join textures (getClassInstances tex_class)
)

for tex in textures do
(
	anim = g.animatable.getanimbyhandle (dotNetObject "system.uintptr" (getHandleByAnim tex))	
	rename anim
)

#7

This is probably correct in order to create a unique name. It seems to me that assignNewName not only changes the name, but also copies the map, which in this case does not need to be done.

anname

So I think it’s better to use uniqueName for renaming.
No problem to rename. The problem is to find and rename only those texmaps that have identical names but are not instances.


#8

you can collect all texmaps with the same name and then make unique array to discard instances. Or better use appendIfUnique when filling textures array


keys       = #()
textures   = #()
duplicates = #{}

for tex_class in textureMap.classes do
(
	for tex in getClassInstances tex_class do
	(	
		key   = toLower tex.Name		
		index = findItem keys key
		
		if index > 0 then 
		(
			append textures[ index ] tex
			duplicates[ index ] = true
		)
		else
		(
			append keys key
			textures[ keys.Count ] = #( tex )	
		)
	)
)


for index in duplicates do
(
	unique_duplicates = makeUniqueArray textures[ index ]
	
	if unique_duplicates.count > 1 do
	(
		map_name = unique_duplicates[1].Name
		base_name = trimRight map_name "0123456789"
		num_digits = map_name.Count - base_name.Count
		num = (substring map_name (1 + base_name.Count) num_digits) as integer
		
		format_string = "0" + num_digits as string + "d"
		i = num
		for j = 2 to unique_duplicates.Count do
		(		
                        -- replace below code with something like: new_name = MakeUniqueTexmapName base_name keys
                        new_name = base_name + (formattedPrint (i += 1) format:format_string)
                        -- to do: check that this new name isn't used by any texmap or mtl and make a new one if it does

			unique_duplicates[j].Name = new_name
                       -- to do: append new name to the array of used names i.e. append keys (tolower new_name) 
		)
	)
)

#9

Thank you so much Serejah! I will try this. It looks like your code should work as expected.:ok_hand:


#10

Hi Serejah!

I tested your code on several large scenes with maps with the dublicate names and found that some maps were given new names that other maps already have.
How can I prevent the duplication of new names assigned to maps?

Thank!


#11

I’ve added a few todo’s to the previously posted code.
Add a name maker function that will use keys array to check whether new name is already used by another texmap.
Use this function to make a new name for each duplicate and don’t forget to append this lowercased new name to the keys array


#12

Yes, I first wrote a question, and then I saw that comments were added to the source code. :slightly_smiling_face:
Thanks for the hint, I solved this problem!