Notifications
Clear all

[Closed] Help request: altering Max5+ script to make it Max3 compatible version

Hello gentlemen,

I’m here to ask for a little help as I’m not any professional or even amateur MaxScripter. A while ago I’ve been helped by Galagast who was kind enough to write me a script I needed. There’s no problems with it, it works like a charm, except that it won’t work for 3dsmax R3 / 3.1 . I’m part of the group of enthusiasts who like to make 3D racing tracks for racing simulations and we’re obliged to use R3 because there are certain plugins made for it which are not available for higher versions of 3dsmax.

Below is the script which works fine in all max versions starting from 5. The error I get when I run the script in Max R3 is “– Unable to convert: 120 to type: String”. This message is in a small popup window. I close it and nothing happens. And ideally, the menu/rollout should apper with a couple of options. Anybody of you guys can figure out what language structures are used in this script which are not understood by Max R3? Is it possible to make some small changes to make it compatible with R3? Or at least make it a R3-only script?

I would really appreciate the help. I’ve posted a few times here, either via my brother or myself, and was always helped, which is why I keep coming back

And just a quick description of the script: it splits the objects by their material IDs and hence creates smaller objects, naming them by the texture file name (without extension) they have assigned. I know there is a “MaterialID Object Splitter v0.2” plugin for 3dsmax R3, but it doesn’t name the objects after their texture file name and we need this option a lot.

Best Regards,
Oleg


rollout detachByID "Detach by ID" width:120 height:135
(
local name_type = true
local ran_color = true
local the_name = "Element_"
local the_mats = #()
local id_list = #()
radiobuttons name_rd "" pos:[10,15] width:60 height:32 labels:#("Material", "Prefix") default:1 columns:1 
edittext name_edt "" pos:[10,50] width:100 height:15 visible:false text:the_name
checkbox del_bot "Delete Original" pos:[5,75] width:110 height:15 checked:true
checkbox rancolor_chk "RandomWireColors" pos:[5,90] width:110 height:15 checked:true
button detach_bot "DETACH" pos:[5,110] width:110 height:21
GroupBox name_grp "Naming: " pos:[5,0] width:110 height:70
label name_lbl "- Texture Name -" pos:[10,50] width:100 height:15 visible:true 
 
on detach_bot pressed do
undo "Detach by ID" on
(
obj = undefined
the_sel = selection as array
if the_sel != undefined do
(
for obj in the_sel where superclassof obj == GeometryClass do
(
id_list = #() -- empty the id_list array
the_mats = #() -- empty the the_mats array
try(convertToPoly obj)catch() -- convert the object to polygon
the_orig = obj --store the current object here
the_polyobj = copy the_orig --copy the original object
the_facecount = getnumfaces the_polyobj --get the face count
 
-- the ff will collect matrial ids
for i in 1 to the_facecount do
	(
	the_faceid = the_polyobj.getfacematerial i
	if not (finditem id_list the_faceid) != 0 then append id_list the_faceid
	) --thus store them in an array [id_list]
 
 
-- the ff will collect material names
try (	 
	if obj.material != undefined then -- if the object has a material...
	 (
	 if classof obj.material == multimaterial then -- check if it is a multimaterial	 
	 ( 
	 for i in id_list do -- loop through the collected id list
	 (
	 the_objmat = obj.material[i] -- objects material is stored in here
	 try
		(
		the_mapfile = the_objmat.diffusemap.bitmap.filename --get the diffuse bitmap filename
		the_filename = getfilenamefile the_mapfile + "-" -- get the filename
		append the_mats (uniquename the_filename ) --collect the names 
		)
	 catch (append the_mats obj.name; format "%'s multimaterial[%] has no diffuse bitmap
" obj.name i)
	 )
	 )		
	 else
	 (
	 if classof obj.material == standard do
	 (
	 the_objmat = obj.material
	 try
		(
		the_mapfile = the_objmat.diffusemap.bitmap.filename
		the_filename = getfilenamefile the_mapfile + "-"
		append the_mats (uniquename the_filename)
		)
	 catch (append the_mats obj.name; format "%'s has no diffuse bitmap
" obj.name)
	 )
	 )
	 )
	else (append the_mats obj.name; format "% has no material
" obj.name)
	)
catch (append the_mats obj.name; format "unknown error occured on %
" obj.name)
-- thus store them in [the_mats]
 
-- the ff will loop through the collected ids, select faces using the face ids...
-- then detach those faces, and also use the collected names by index to name it
the_index = 0
for i in id_list do
	 (
	 the_index += 1 --increment the index
	 the_polyobj.selectbymaterial i --select the faces using the material ids collected
	 the_faces = getfaceselection the_polyobj
	 -- this will set what naming convention is used
	 if name_type then (the_name = uniquename the_mats[the_index])
	 else (the_name = (uniquename the_name))
	 polyOp.detachFaces the_polyobj the_faces asnode:true name:the_name --detach
	 if ran_color then (getnodebyname the_name).wirecolor = random black white
	 )
the_index = 0
if del_bot.checked do delete the_orig
delete the_polyobj
)
)
)
on name_edt entered txt do (the_name = txt)
on rancolor_chk changed val do (ran_color = val)
on name_rd changed val do
(
case val of
(
1: 
(
name_edt.visible = false
name_lbl.visible = true
name_type = true
)
2: 
(
name_edt.visible = true
name_lbl.visible = false
name_type = false
)
)
)
)
createdialog detachByID 
 
-- script request by Eye of Hawk (CGTalk)
-- author: Galagast 05/05/24

12 Replies

This is a bit tricky as the code operates on Editable Poly objects which don’t exist as class in Max 3. The script would have to operate on Editable Mesh instead. Unfortunately, I don’t have a copy of the R3 MAXScript Help and don’t remember whether it featured the meshOp.detachFaces method. It would be great if you could open the Help and do a search for “meshop.detachfaces” and see if you will get anything back. There ARE workarounds for R3 if it does not exist, but the code would become much more complex.

It would be even better if you could put the R3 MAXScript help online somewhere for me to download.

Hi Bobo,

First of all, thank you for the quick reply!

I now start to remember why it wasn’t working for R3. Yes, indeed, MaxR3 doesn’t have the editable poly class. I guess it then won’t be as easy as I thought yesterday.

I didn’t know if I could just post the help file here, so I sent the link to MaxScript R3 help file to you via PM.

Thanks again for the reply and hope it’s still possible. I’ll keep my fingers crossed

Kind Regards,
Oleg

Got it, thanks.
Looking at the help, R3 does not support the meshOp. struct directly (although I am sure it was available in a DLX extension, Avguard or MaxAgni, might still be there on Scriptspot.com…)

I will try to get the same result using a different approach and will let you know whether it works or not.

Hey Bobo,

how’s things? Any luck with the approach?

Sorry, was busy during the week, will fix it now.

1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

Here is an attempt for a R3 version:


(

global detachByID_Floater --define the dialog rollout
rollout detachByID_Rollout  "Detach by ID" 
(
	radiobuttons name_rd "" pos:[10,15] width:60 height:32 labels:#("Material", "Prefix") default:1 columns:1 
	edittext name_edt "" pos:[10,50] width:100 height:15 visible:false text:"Element"
	checkbox del_bot "Delete Original" pos:[5,75] width:110 height:15 checked:true
	checkbox rancolor_chk "RandomWireColors" pos:[5,90] width:110 height:15 checked:true
	button detach_bot "DETACH" pos:[5,110] width:110 height:21
	GroupBox name_grp "Naming: " pos:[5,0] width:110 height:70
	label name_lbl "- Texture Name -" pos:[10,50] width:100 height:15 visible:true 
	 
	on detach_bot pressed do
	(
		undo "Detach by ID" on
		(
			the_sel = for o in selection where superclassof o == GeometryClass and classof o != TargetObject collect o
			for obj in the_sel do
			(
				local theClone = convertToMesh (copy obj) --create temp. EMesh copy 
				local id_list = #{} --init. ID list as bitarry and collect all IDs used in the mesh:
				for i in 1 to theClone.numfaces do id_list[getfacematID theClone i] = true
				 
				local the_mats = #()  --init. an array to collect material names
				for i in id_list do  --for each ID found
				(
					if name_rd.state == 1 then --if use texture names
					(
						case classof obj.material of --depending on the material class
						(
							multimaterial: (
								try
									the_mats[i] = obj.name + "_MatID" + i as string + "_" + (getfilenamefile obj.material[i].diffusemap.bitmap.filename)
								catch 
									the_mats[i] = obj.name + "_MatID" + i as string
								 )	
							 standard: (
								 try
									the_mats[i] = obj.name + "_MatID" + i as string + "_" + (getfilenamefile obj.material.diffusemap.bitmap.filename)
								 catch 
									 the_mats[i] = obj.name + "_MatID" + i as string
							)		
							default: the_mats[i] = obj.name + "_MatID" + i as string --for all other classes, just use object and ID
						)--end case
					)
					else --if prefix requested, use whatever is in the text field and add MatID to it.
						the_mats[i] = name_edt.text + "_MatID" +i as string 
				)--end i loop 
					
				for i in id_list do --for each ID found
				 (
					 local newObject = copy theClone --create a new copy of the temp. object
					newObject.name = uniquename (the_mats[i] + "_") --name it using the name collected above
					--go through all faces backwards and delete any faces with ID not equal to the current one
					for f = newObject.numfaces to 1 by -1 where getFaceMatID newObject f != i do deleteFace newObject f
					local usedVerts = #{1..newObject.numverts} --init. a bitarray with all vertices set to true
					for f = 1 to newObject.numfaces do  --go through all faces
					(
						theFaceDef = getFace newObject f --get the face definition
						usedVerts[theFaceDef.x]  = false --and set its vertices to false
						usedVerts[theFaceDef.y]  = false
						usedVerts[theFaceDef.z]  = false
					)
					usedVerts = usedVerts as array --now we have an array of all isolated vertices not used by faces
					--delete them:
					for v =  usedVerts.count to 1 by -1 do deleteVert newObject usedVerts[v]
					--assign wirecolor depending on the option
					if rancolor_chk.state then 
						newObject.wirecolor = random black white
					else	
						newObject.wirecolor = obj.wirecolor
				 )
				if del_bot.checked do delete obj --if requested, delete the original
				delete theClone --delete the temp. clone
			)--end obj loop
		)--end undo
	)--end on
	
	on name_rd changed val do --enable/disable controls depending on radio buttons
	(
		name_edt.visible = val == 2
		name_lbl.visible = val == 1
	)
)

if detachByID_Floater != undefined do closeRolloutFloater detachByID_Floater
detachByID_Floater = newRolloutFloater "Detacher" 130 170
addRollout detachByID_Rollout detachByID_Floater
 
-- script request by Eye of Hawk (CGTalk)
-- author: Galagast 05/05/24
-- Max R3 version: Bobo 06/12/16

)

I had to use a Floater since R3 had no dialogs yet and work around mesh detaching using cloning and deleting.
It works in R9, but somebody should test it in R3 and see if everything still works – there might be some method not available there or a different behaviour.

The script is not 100% the same as the original – at least the material naming is slightly different as I used the object name, a suffix “MatID” with the actual face Material ID and then the diffuse map name if found. But this part of the script is easy to change if necessary.

I simplified large parts of the original script, got rid of most temp. variables etc.

Give it a try.

Hey Bobo,

no problems with the delay at all Thank you for working on it very much!

Now onto the new script. There seems to be some problems with it, first task is to make it run and do some job, correct or wrong. When I first launched it, I got this error:

So I tried and removed the whole line which starts with the word ‘GroupBox’ … as far as I understand it’s not crucial to have it there, just a groupbox control. Once removed, the rollout menu appeared and I could press the DETACH button. After clicking the DETACH button, I got this error:

well, I tried and removed the block which starts with ‘undo “Detach by ID” on’ as I thought that was not vital as well, at least for testing purposes, but then I got this:

And that’s where I stopped any more removal tricks. Is this fixable?

Oh my, I never use groupBox unless necessary, I forgot that it was not in R3.
Also, the .visible property was added in Max 5 or 6 or so if I am not mistaken.
I left the whole UI as is, will redo it completely, let’s see if it solves your problems.

This this one:

(
 
 global detachByID_Floater --define the dialog rollout
 rollout detachByID_Rollout  "Detach by ID" 
 (
 	radiobuttons name_rd "" labels:#("Material", "Prefix") default:1 columns:2 offset:[0,-3]
 	edittext name_edt "" text:"Element" offset:[-11,0]
 	checkbox del_bot "Delete Original" checked:true offset:[-7,0]
 	checkbox rancolor_chk "RandomWireColors" checked:true offset:[-7,0]
 	button detach_bot "DETACH" width:110 height:21
 	 
 	on detach_bot pressed do
 	(
 		undo on
 		(
 			the_sel = for o in selection where superclassof o == GeometryClass and classof o != TargetObject collect o
 			for obj in the_sel do
 			(
 				local theClone = convertToMesh (copy obj) --create temp. EMesh copy 
 				local id_list = #{} --init. ID list as bitarry and collect all IDs used in the mesh:
 				for i in 1 to theClone.numfaces do id_list[getfacematID theClone i] = true
 				 
 				local the_mats = #()  --init. an array to collect material names
 				for i in id_list do  --for each ID found
 				(
 					if name_rd.state == 1 then --if use texture names
 					(
 						case classof obj.material of --depending on the material class
 						(
 							multimaterial: (
 								try
 									the_mats[i] = obj.name + "_MatID" + i as string + "_" + (getfilenamefile obj.material[i].diffusemap.bitmap.filename)
 								catch 
 									the_mats[i] = obj.name + "_MatID" + i as string
 								 )	
 							 standard: (
 								 try
 									the_mats[i] = obj.name + "_MatID" + i as string + "_" + (getfilenamefile obj.material.diffusemap.bitmap.filename)
 								 catch 
 									 the_mats[i] = obj.name + "_MatID" + i as string
 							)		
 							default: the_mats[i] = obj.name + "_MatID" + i as string --for all other classes, just use object and ID
 						)--end case
 					)
 					else --if prefix requested, use whatever is in the text field and add MatID to it.
 						the_mats[i] = name_edt.text + "_MatID" +i as string 
 				)--end i loop 
 					
 				for i in id_list do --for each ID found
 				 (
 					 local newObject = copy theClone --create a new copy of the temp. object
 					newObject.name = uniquename (the_mats[i] + "_") --name it using the name collected above
 					--go through all faces backwards and delete any faces with ID not equal to the current one
 					for f = newObject.numfaces to 1 by -1 where getFaceMatID newObject f != i do deleteFace newObject f
 					local usedVerts = #{1..newObject.numverts} --init. a bitarray with all vertices set to true
 					for f = 1 to newObject.numfaces do  --go through all faces
 					(
 						theFaceDef = getFace newObject f --get the face definition
 						usedVerts[theFaceDef.x]  = false --and set its vertices to false
 						usedVerts[theFaceDef.y]  = false
 						usedVerts[theFaceDef.z]  = false
 					)
 					usedVerts = for i in usedVerts collect i --now we have an array of all isolated vertices not used by faces
 					--delete them:
 					for v =  usedVerts.count to 1 by -1 do deleteVert newObject usedVerts[v]
 					--assign wirecolor depending on the option
 					newObject.wirecolor = if rancolor_chk.state then random black white else obj.wirecolor
 				 )
 				if del_bot.checked do delete obj --if requested, delete the original
 				delete theClone --delete the temp. clone
 			)--end obj loop
 		)--end undo
 	)--end on
 	
 	on name_rd changed val do --enable/disable controls depending on radio buttons
 		name_edt.enabled = val == 2
 
 	on detachByID_Rollout open do name_rd.changed 1
 )
 
 if detachByID_Floater != undefined do closeRolloutFloater detachByID_Floater
 detachByID_Floater = newRolloutFloater "Detacher" 140 140
 addRollout detachByID_Rollout detachByID_Floater
  
 -- script request by Eye of Hawk (CGTalk)
 -- author: Galagast 05/05/24
 -- Max R3 version: Bobo 06/12/16
 
 )

😮
Hey Bobo, you did it again! It works like charm! Exactly what’s been needed!:bounce:

And “again” was because you were the one who originally did the “OffsetVertsByEdge” script for me:
http://forums.cgsociety.org/showthread.php?t=278342

Just so you know, these things you did (do) for me/us are still being heavily used For us – modders – these are holy tools

Thank you again, Bobo! :bowdown:

Take care! :wavey:

Cheers,
Oleg

Page 1 / 2