Notifications
Clear all

[Closed] Duplicate Materials

Does anyone have a script or know the commands to remove duplicate materials from a scene and apply the first instance of that material to all objects that have that material then delete the old duplicate material?

I was trying to find a command like
if isvalidnode (getnodebyname (onject[a] as string)) == true then (
)
only for material names so then i could do a search for the name before i apply it and if it exists apply the material that is already in the scene and skip reimporting that material.

If there is a better way or if this is a good way what would the command be to do it?

Thanks so much for any help in advance.

3 Replies

if you don’t use multi-sub material, you can try this

  1. Run this tool
  2. Click “Clean matEdit” button (it will clean all your material editor)
  3. Select all objects in sence
  4. Click “mat = tex?” button (it will find all objects using same diffuse texture)
  5. Open material editor –> it will show the number of duplicate texture there
  6. Choose 1 material on material editor
  7. Click “Obj same diffuse” button (it will find all objects using currently selected diffuse texture)
  8. Click apply on material editor to apply your selected material to all objects using same diffuse
  9. Goto step 3 –> repeat until your material editor will empty after step 4

You select all objects, click “Set mat = tex” button, it will automatically do from 1 to 9 step
(but still remain some minor error)


rollout Tools "Tools" rolledUp:false
(
		button btCleanmatEdit "Clean matEdit"
		button btCheckTexMat "mat = tex?"
		button btSelectObj "Obj same diffuse"
		button btSetTexMat "Set mat = tex"

	local lstname = #()
	local lstdup = #()
	local lstdupobj =#()
	local recentPath = ""
	local lstErrorObjs = #()

	function isDuplicate lst sname =
	(
		local isDup = false;
		for s in lst do
			if s == sname then isDup = true
		return isDup
	)
	
	function collectMat sel = 
	(
		local mats = #()
		local objs = #()
		for obj in sel do
		(
			try
			(
				for m in obj.mat do
					if (findItem mats m == 0) then
					(
						append mats m
						append objs obj
					)
			)
			catch
			(
				if (findItem mats obj.mat == 0) then
				(
					append mats obj.mat
					append objs obj
				)
			)
		)			
		return #(mats,objs)
	)
	local lstMatError = #()
	local lstTexError = #()
	function SWV_checkTexMat = 
	(
		local val = collectMat selection
		local lstTexture =#()
		lstMatError = #()
		lstTexError = #()
		for m in val[1] do
		try
			if (m != undefined) then
			(
				local filename = toLower (filenameFromPath m.diffuseMap.filename)
				if (findItem lstTexture filename == 0) then
				(
					append  lstTexture filename
				)
				else
				(
					if (findItem lstTexError filename == 0) then
					(
						append lstMatError m
						append lstTexError filename
					)
				)
			)
		catch()
		local i = 1
		for m in lstMatError do
		(
			if (i < meditMaterials.count) then
			(
				meditMaterials[i] = m
				i += 1
			)
		)
		if (lstTexError.count > 0) then
			return ("Same texture = same material: Fail
- Error:"+ lstTexError as string+"
")		
		else
			return ("Same texture = same material: Done!"+"
")		
	)

	local lstDup1 = #()
	local lstObj1 = #()
	local lstFileFull =#()
	local lstObj1File = #()
	local lstObj1Bool = #()


	
	on btSelectObj pressed do
	(
		local mat = meditMaterials[activeMeditSlot]
		--local mat = $.mat
		local filename = toLower (getFilenameFile mat.diffuseMap.filename)
		local objs = #()
		for obj in geometry do
			try
			(
			if (toLower (getFilenameFile obj.mat.diffuseMap.filename) == filename) then
			(
				append objs obj
				print obj.name
			)
		) catch ()
		max select none
		select objs
	)
	on btCheckTexMat pressed do
	(
		local st= SWV_checkTexMat()
		MessageBox st
		print st
	)
	
	on btSetTexMat pressed do
	(
		local st= SWV_checkTexMat()
		print st
		for obj in selection do
			if (classOf obj == Editable_Poly) then
			try
			(
				local filename = toLower (filenameFromPath obj.mat.diffuseMap.filename)
				local i = findItem lstTexError filename
				if (i>0) then
				(
					obj.mat = lstMatError[i]
					print filename
				)
			)
			catch ()
		
	)
	
	on btCleanmatEdit pressed do
	(
		for i=1 to meditMaterials.count do
		(
			meditmaterials[i] = standardMaterial()
			if i<10 then t = "0"+i as string else t = i as string
			meditmaterials[i].name = t +" - Default"
		)
	)
)

createDialog Tools width:180

Thanks for your response I am using multi material but each object part of a character has its own material slot and I want to combine textures if they already exist in the scene.

if so, I think it is very difficult to solve your case. Because some sub material use same texture but different material ID. So I think you should detach all ID and use my tool above. To detach ID, you can try this link
http://www.scriptspot.com/3ds-max/scripts/detach-by-material-id