Select by name filter, update and Matte material global override

Hello everyone :)
I'm relatively new to Max scripting so I have few problems to solve which I didn't found on help or other forums.

I want my script to, when selecting geometry, filter only geometry when selecting by name (multiple objects - only Geometry - no helpers, cameras, shapes or so), the same thing with cameras. Also, to check those, I want them to print in the text box under the buttons and connect selected camera to render button.
Then, when my objects are selected and printed, on "Update" button, next to render button, I want to apply a Global MATTE material override to selected geometry (mental ray) on chosen radio button "Front" - when "Front" is chosen - it should apply MATTE to previously selected geometry MESH objects and when Back is selected to do vice versa, to apply on objects that are not selected and printed in the box - I don't know how to do that so I'm asking someone to help and I would really appreciate it.

The script is in the attachment. Thanks in advance.

AttachmentSize
scriptproblem_02.ms2.52 KB

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Freak's picture

select camera without target

hello :) I have just one more problem to solve but can't figure it out so If somebody can help me with just one more line of code.
I want script to collect Camera (without target) when opening. It can be selected by select by name that is filtered in class of cameras ("isKindOf") and it's working but I can't add that filter when opening and collecting camera automatically. In my every scene the camera has the same name "CAM_2_Front" and script, when is collecting, it grabs target object with camera too. I tried to filter it in some other way but it's not working, I got "call needs function or class, got: $Target_Camera:CAM_2_Front @ [-1.777199,-434.206512,187.059662]" problem. Few days of trying and still can't figure it out. Here's the code:

try destroydialog ::AutoCamera catch()
 
Rollout AutoCamera "AutoCamera" width:155
(
 
	button bt_SelectCamera "Select Camera"   align:#left  height:30 width:130
	listbox list_cameras "" align:#left height:5 width:130
	button bt_render "Render" border:false align:#center width:206 height:256
 
 
	local theCameras = #()
 
 
	----FUNCTIONS----
	fn FilterCameras  obj = isKindOf obj camera
 
	fn selectCameras =
	(
		selCam = selectByName title:"Pick Camera" filter:FilterCameras showHidden:true
		if selCam != undefined then
		(
			theCameras = selCam
			list_cameras.items = for c in theCameras collect c.name
			)else(
			list_cameras.items = #()
			theCameras = #()
		)
	)--end fn selectCameras
 
 
	----EVENTS----	
	on AutoCamera open do
	(
		camName = $CAM_2_Front 
		for i in camName do 
			(
				if camName isKindOf i camera do 
					(
						camName2
					)
			)
		openSelCam = camName2
		if openSelCam != undefined then
		(
			theCameras = openSelCam
			list_cameras.items = for c in theCameras collect c.name
			)else(
			list_cameras.items = #()
			theCameras = #()
		)
	)--end onOpen
 
	on bt_SelectCamera pressed do
	(
		if theCameras != undefined then selectCameras ()
 
	)--end bt_SelectCamera
 
 
	on bt_Render pressed do
	(
		cam = theCameras[list_cameras.selection]
		fnRender = render camera:cam vfb:false outputwidth:128 outputheight:256
		bt_Render.images = #(fnRender, undefined, 1,1,1,1,1 )
		fnRender
		)
 
)--END ROLLOUT
 
createdialog AutoCamera
 
 
<mxs>
AttachmentSize
camprob.jpg 11.84 KB
miauu's picture

.

The same as in CGTalk:

camsARr = for o in cameras where classof o != targetobject collect o
Freak's picture

Thank you again :)

Kostadin, thank you, again, and here on scriptspot!

Cheers ;)

Freak's picture

removed space on the end

Thank you, Pixamoon. Worked like a charm.
I just had to use rendName = substring rendName 1 (rendName.count - 1) to make it work. I know that this was very simple problem but, for a newbie like me it took few hours to figure out where to put this line of code X) I will study your method for materials, thank you for sharing.

Cheers

pixamoon's picture

`

cool, yes, just remove b.selected and previous line with b and u ready:

viewNode = sme.GetView (sme.activeView)
smeViewMats = #()
for n = 1 to trackViewNodes[#sme][(sme.activeView)].numSubs do (
m = trackViewNodes[#sme][(sme.activeView)][n].reference
if superclassof m == material do append smeViewMats m
)
 
print smeViewMats
Freak's picture

Thank you! :D

You are genius and thank you for help :) Now I have 99% of script settled. Only I have one more issue to solve and still can't figure it out.. I want my sp_Material spinner to instantly change and assign those materials (which are collected from scene and in array and listed) to selected mesh or, if it is possible, let Max to found mesh in which has a name in it ("Head" in "MESH_Head_01" - that would be fantastic) and make that as a selection (just to avoid manually selecting in scene) I tried to access the material index via spinner.value but i got "--No ""get"" function for undefined" error. Here is the code and screenshot is in the attachment.

try destroydialog ::CRM catch()
 
Rollout CRM "CRM" width:225
(
	group "Character Def"
		(
		spinner sp_Pose "Pose" type:#integer range:[0,200,currentTime] align:#left across:2 width:100 height:20
		spinner sp_Material "Material" type:#integer range:[0,20,1] align:#right width:100 height:20
 
		edittext tx_Pose readOnly:true align:#left across:2 offset:[0,-5] width:100 height:18
		edittext tx_Material readOnly:true align:#right offset:[0,-5] width:100 height:18
		)
	group "Select and Location"
		(
		button bt_selectFolder "..." tooltip:"Pick path for render" align:#left width:30 offset: [0,0] across:2 height:18
		edittext tx_folder "" readonly:true align:#right height:18 width:165
 
		button bt_SelectGeometry "Select Geometry" align:#right height:30 width:97 across:2
		button bt_SelectCamera "Select Camera"   align:#left  height:30 width:97
		listbox list_geometry "" align:#left  height:5 width:97 across:2 readOnly:true enabled:true
		listbox list_cameras "" align:#right height:5 width:97
		button bt_SelectText "Select MaxText" align:#left height:30 width:97 across:2
		button bt_SelectMaterials "Collect Materials" align:#right height:30 width:97
		listbox list_text "" align:#left  height:5 width:97 readOnly:true across:2 enabled:true 	
		listbox list_materials "" align:#right height:5 width:97 readonly:true enabled:true
 
		label rend_option "Render:" align:#left across:2
		radiobuttons rad_options "" labels:#("Pose","FaceExpression") align:#left offsets:#([-50,0],[-40,0])
		)
	group "Update - Render"
		(
		--button bt_update "Update" align:#left across:2 width: 97 height:30
		button bt_render "Render" border:false align:#center width:206 height:256
		)
 
	local matteMaterial
	local theObjects = #()
	local theCameras = #()
	local outputFolder = undefined
 
	local tpose = "t-pose"
 
	on CRM open do
	(
		matteMaterial = Matte_Shadow_Reflection__mi catch_shadows:false ao_on:false catch_reflections:false
 
		tx_Pose.text = tpose
		tx_Material.text = "undefined"
	)
 
	fn FilterGeometry obj = isKindOf obj geometryClass and not isKindOf obj Targetobject --<<<it should list only geometry objects but it also lists bones in selectByName window for some reason
	fn FilterCameras  obj = isKindOf obj camera
	fn FilterShapes obj = isKindOf obj shape	
 
	on sp_Pose changed ttime do
	(
 
	sliderTime = ttime
 
	if ttime > 0 then 
	(
		tx_Pose.text = if list_text.items[ ttime+1 ] != undefined then list_text.items[ttime+1] else ""
	) 
	else if ttime == 0 then 
	(
		tx_Pose.text = "t-pose"		
	)
	)
 
 
	on sp_Material changed FEx do
	(
		if sp_Material.value > 0 then (
		tx_Material.text = if list_materials.items[sp_Material.value] != undefined then list_materials.items[sp_Material.value] else ""
	) else (
		tx_Material.text = ""		
	)
 
	FEx = theMaterials[sp_Material.value]
	face = $
	face.material = FEx showInViewport:true
 
	)
 
 
	on bt_SelectGeometry pressed do
	(
		sel = selectByName title:"Pick" filter:FilterGeometry showHidden:true
		if sel != undefined then
		(
			theObjects = sel
			list_geometry.items = for j in theObjects collect j.name
		)else(
			list_geometry.items = #()
			theObjects = #()
		)
	)
 
	on bt_SelectCamera pressed do
	(
		sel = selectByName title:"Pick" filter:FilterCameras showHidden:true
		if sel != undefined then
		(
			theCameras = sel
			list_cameras.items = for c in theCameras collect c.name
		)else(
			list_cameras.items = #()
			theCameras = #()
		)
	)
 
 
 
	on bt_SelectText pressed do
	(
		sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
		if sel != undefined then
		(
			theObjects = sel
 
			local arr = #()
			for s in theObjects do (
 
				for w in filterstring s.text "\n" do append arr (substring w 4 (w.count - 2))
 
			)
			list_text.items = arr
 
		)
	)		
 
 
 
	on bt_selectFolder pressed do
	(
		outputFolder = getSavePath()
		if outputFolder != undefined then tx_folder.text = outputFolder else tx_folder.text = "undefined"
	)
 
 
 
	local theMaterials = #()
	on bt_SelectMaterials pressed do
	(
		viewNode = sme.GetView (sme.activeView)
		smeViewMats = #()
		for n = 1 to trackViewNodes[#sme][(sme.activeView)].numSubs do 
		(
			m = trackViewNodes[#sme][(sme.activeView)][n].reference
			if superclassof m == material do append smeViewMats m
		)
 
		local selMats = smeViewMats
		if selMats != undefined then
		(
			theMaterials = selMats
			list_materials.items = for m in theMaterials collect m.name
 
		)
		else
		(
			list_materials.items = #()
			theMaterials = #()
		)
 
	)
 
 
 
 
	on bt_render pressed do 
	(
		if outputFolder == undefined do return messagebox "No Output Folder Selected"
		if theObjects.count == 0 do return messagebox "No Geometry Selected"
		if theCameras.count == 0 do return messagebox "No Camera Selected"
 
		setwaitcursor()
 
 
	cam = theCameras[list_cameras.selection]
 
	rendName = tx_Pose.text as string
	local poseName = rendName = substring rendName 1 (rendName.count - 1) 
 
 
		case rad_options.state of
		(
			1:
			(					
				matteObjects = theObjects
				filename = outputFolder + "\\" + poseName + ".png"
			)
			2:
			(
				matteObjects = for j in geometry where finditem theObjects j == 0 collect j
				filename = outputFolder + "\\" + poseName + "-" + "material_name" + ".png"
			)
		)
 
 
		oldMaterials = for j in matteObjects collect #(j, j.material)
 
		matteObjects.material = matteMaterial
 
		fnRender = render camera:cam vfb:false outputwidth:128 outputheight:256 outputfile:filename
		bt_Render.images = #(fnRender, undefined, 1,1,1,1,1 )
		fnRender
 
		for j in oldMaterials do j[1].material = j[2]
 
		--messagebox ("Image Rendered to:\n" + filename)
 
		setarrowcursor()
	)
)
 
createdialog CRM<mxs>
AttachmentSize
mat_problem.jpg 79.31 KB
pixamoon's picture

`

:) you're welcome

didn't have time to check a code but u can simply add

if classof x == Array then ......

it will skip all non array values

or

if x != undefined then ......

but in your case it can't get indexed value in array, so first one is better

cheers,
Pixamoon

Freak's picture

select camera without target

hello :)
Just so you know the script is working great and big thanks for your help. I've been learning MaxScript and modified my script just like I wanted and it's very addicting thing to learn in Max.
Only I have just one more problem to solve but can't figure it out so If you can help me with just one more line of code.
I want script to collect Camera (without target) when opening. It can be selected by select by name that is filtered in class of cameras ("isKindOf") and it's working but I can't add that filter when opening and collecting camera automatically. In my every scene the camera has the same name "CAM_2_Front" and script, when is collecting, it grabs target object with camera too. I tried to filter it in some other way but it's not working, I got "call needs function or class, got: $Target_Camera:CAM_2_Front @ [-1.777199,-434.206512,187.059662]" problem. Few days of trying and still can't figure it out. Here's the code:

try destroydialog ::AutoCamera catch()
 
Rollout AutoCamera "AutoCamera" width:155
(
 
	button bt_SelectCamera "Select Camera"   align:#left  height:30 width:130
	listbox list_cameras "" align:#left height:5 width:130
	button bt_render "Render" border:false align:#center width:206 height:256
 
 
	local theCameras = #()
 
 
	----FUNCTIONS----
	fn FilterCameras  obj = isKindOf obj camera
 
	fn selectCameras =
	(
		selCam = selectByName title:"Pick Camera" filter:FilterCameras showHidden:true
		if selCam != undefined then
		(
			theCameras = selCam
			list_cameras.items = for c in theCameras collect c.name
			)else(
			list_cameras.items = #()
			theCameras = #()
		)
	)--end fn selectCameras
 
 
	----EVENTS----	
	on AutoCamera open do
	(
		x = $CAM_2_Front
		onlyCam = if classof x == Targetcamera and not classof x == TargetObject then x onlyCam
		openSelCam = onlyCam
		if openSelCam != undefined then
		(
			theCameras = openSelCam
			list_cameras.items = for c in theCameras collect c.name
			)else(
			list_cameras.items = #()
			theCameras = #()
		)
	)--end onOpen
 
	on bt_SelectCamera pressed do
	(
		if theCameras != undefined then selectCameras ()
 
	)--end bt_SelectCamera
 
 
	on bt_Render pressed do
	(
		cam = theCameras[list_cameras.selection]
		fnRender = render camera:cam vfb:false outputwidth:128 outputheight:256
		bt_Render.images = #(fnRender, undefined, 1,1,1,1,1 )
		fnRender
		)
 
)--END ROLLOUT
 
createdialog AutoCamera
 
<mxs>
AttachmentSize
camprob.jpg 11.84 KB
Freak's picture

thank you for response, pixamoon

I figured it out some other similar way. I've already settled script 90% but still have few problems to solve.
First problem looks very simple but still can't figure it out. When rendering to a image it appears to be a "space" between pose name and extension ".png" I've tried trimRight, replace, and token commands on it but none of that is working... The screenshot is below in the attachment.
Second problem is that I want to connect material spinner to cycle through materials somehow. Problem is that Compact Material Editor has 24 free slots to fill with materials but I need 40+. I was wondering is there a way to connect Materials in Slate Editor to a spinner in script to cycle through materials.

Here I will post whole script and describe problem as close as I can.

I'm doing still poses (with biped) for a character with switchable face expressions and render them as separate: Head and body - on the same pose i can switch and render facial expressions defined by a diffuse map in separate material (number of facial expressions = standard materials in scene). This is for a game and those rendered images (body and few different expressions) are merged to a complete character. Later on, this will be animated with switchable faces with dialog text above and so on..
Scene is made from biped (and mesh skinned to it) MaxText with predefined poses for character formatted as ("pose number", "(space)", "pose name") for example "04 welcoming" - pose number is also timeslider number in Max just to found specified poses more easily (it can be to 200 poses). Materials are node-based in SME (because compact ME contains only 24 free slots to stock materials and I need 40+) - standard, selfillumination:100, diffuse map (face expression). It can be more than 40 different expressions to switch on a face mesh so I want that to be automated with spinner somehow too. Temporarily I have setup for expressions using state sets (each set is different material) and it can be easily changed in between.

I've written a script with big help from Jorge Rodríguez on forum "CGsociety" Everything works perfectly, just as I wanted. Only thing that I want to do to finish the script is to add a function to this spinner on top right of the script - material change. It should be a switchable materials in array with named materials in edittext - the same thing with rendering - only this time, in name of .png of expressions, it is named "pose name", "-" "facial expression(material) name" for example "welcoming-happy.png" Also, the diffuse map name is the same name as it is material for example: happy.jpg as a diffuse map to a happy.material.

All that I want is to connect pose spinner to a variable strings by changing time/poses and material spinner to expressions/materials. Sry for bad English, I'm trying to explain this as clear as possible. The code for whole script is below. Thank you in advance and I hope that there must be some kind of solution for that situation.

try destroydialog ::CRM catch()
 
Rollout CRM "CRM" width:225
(
	group "Character Def"
		(
		spinner sp_Pose "Pose" type:#integer range:[0,200,currentTime] align:#left across:2 width:100 height:20
		spinner sp_Material "Material" type:#integer range:[0,20,1] align:#right width:100 height:20
 
		edittext tx_Pose readOnly:true align:#left across:2 offset:[0,-5] width:100 height:18
		edittext tx_Material readOnly:true align:#right offset:[0,-5] width:100 height:18
		)
	group "Select and Location"
		(
		button bt_selectFolder "..." tooltip:"Pick path for render" align:#left width:30 offset: [0,0] across:2 height:18
		edittext tx_folder "" readonly:true align:#right height:18 width:165
 
		button bt_SelectGeometry "Select Geometry" align:#right height:30 width:97 across:2
		button bt_SelectCamera "Select Camera"   align:#left  height:30 width:97
		listbox list_geometry "" align:#left  height:5 width:97 across:2 readOnly:true enabled:true
		listbox list_cameras "" align:#right height:5 width:97
		button bt_SelectText "Select MaxText" align:#left height:30 width:97
		listbox list_text "" align:#left  height:5 width:97 readOnly:true enabled:true	
 
		label rend_option "Render:" align:#left across:2
		radiobuttons rad_options "" labels:#("Pose","FaceExpression") align:#left offsets:#([-50,0],[-40,0])
		)
	group "Update - Render"
		(
		button bt_update "Update" align:#left across:2 width: 97 height:30
		button bt_render "Render" align:#right width:97 height:30
		)
 
	local matteMaterial
	local theObjects = #()
	local theCameras = #()
	local outputFolder = undefined
 
	local tpose = "t-pose"
 
	on CRM open do
	(
		matteMaterial = Matte_Shadow_Reflection__mi catch_shadows:false ao_on:false catch_reflections:false
 
		tx_Pose.text = tpose
		tx_Material.text = "undefined"
	)
 
	fn FilterGeometry obj = isKindOf obj geometryClass and not isKindOf obj Targetobject --<<<it should list only geometry objects but it also lists bones in selectByName window for some reason
	fn FilterCameras  obj = isKindOf obj camera
	fn FilterShapes obj = isKindOf obj shape	
 
	on sp_Pose changed ttime do
(
	sliderTime = ttime
 
		if ttime > 0 then (
			tx_Pose.text = if list_text.items[ ttime+1 ] != undefined then list_text.items[ttime+1] else ""
		) else (
			tx_Pose.text = ""		
		)
 
)
 
 
	on bt_SelectGeometry pressed do
	(
		sel = selectByName title:"Pick" filter:FilterGeometry showHidden:true
		if sel != undefined then
		(
			theObjects = sel
			list_geometry.items = for j in theObjects collect j.name
		)else(
			list_geometry.items = #()
			theObjects = #()
		)
	)
 
	on bt_SelectCamera pressed do
	(
		sel = selectByName title:"Pick" filter:FilterCameras showHidden:true
		if sel != undefined then
		(
			theCameras = sel
			list_cameras.items = for j in theCameras collect j.name
		)else(
			list_cameras.items = #()
			theCameras = #()
		)
	)
 
 
 
	on bt_SelectText pressed do
	(
		sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
		if sel != undefined then
		(
			theObjects = sel
 
			local arr = #()
			for s in theObjects do (
 
				for w in filterstring s.text "\n" do append arr (substring w 4 (w.count - 2))
 
			)
			list_text.items = arr
 
		)
	)		
 
 
 
	on bt_selectFolder pressed do
	(
		outputFolder = getSavePath()
		if outputFolder != undefined then tx_folder.text = outputFolder else tx_folder.text = "undefined"
	)
 
	on bt_render pressed do 
	(
		if outputFolder == undefined do return messagebox "No Output Folder Selected"
		if theObjects.count == 0 do return messagebox "No Geometry Selected"
		if theCameras.count == 0 do return messagebox "No Camera Selected"
 
		setwaitcursor()
 
 
		cam = theCameras[list_cameras.selection]
		rendName = tx_Pose.text
 
		case rad_options.state of
		(
			1:
			(
				matteObjects = theObjects
				filename = outputFolder + "\\" + rendName + ".png"
			)
			2:
			(
				matteObjects = for j in geometry where finditem theObjects j == 0 collect j
				filename = outputFolder + "\\" + rendName + "-" + "material_name" + ".png"
			)
		)
 
 
		oldMaterials = for j in matteObjects collect #(j, j.material)
 
		matteObjects.material = matteMaterial
 
		render camera:cam vfb:false outputwidth:128 outputheight:256 outputfile:filename
 
		for j in oldMaterials do j[1].material = j[2]
 
		--messagebox ("Image Rendered to:\n" + filename)
 
		setarrowcursor()
	)
)
 
createdialog CRM
AttachmentSize
space_problem.jpg 16.06 KB
screenshot_script.jpg 121.31 KB
pixamoon's picture

`

bit busy today, but to get materials from SME take a look on my method here:
http://www.scriptspot.com/3ds-max/scripts/sme-get-selected-materials

it's getting only selected but it is easy to create new view in SME and just get all materials from there

to remove space on the end:

if rendName[rendName.count] == " " then rendName = substring rendName 1 (rendName.count - 1)

cheers,
pixamoon

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.