Notifications
Clear all

[Closed] getPropNames for subobject selections

hi all

maxscript newbie warning!

i need to establish which control points are selected in a ffd modifier. Is this possible? do i use something like

getPropNames $[color=green][font=‘Courier New’]sphere01[/color].‘FFD(box) 4x4x4’ #dynamicOnly[/font]

which produces a list of the animated control points.

but instead of dynamic only is there a flag to show selected only?

cheers

paul

8 Replies

There’s no way to check whether a control point is selected or not. Also, the points can only be accessed/changed (position only) after they have been animated manually so that makes it even less useful I’m afraid

Martijn

Although ‘position only’ is correct, you can certainly animate the control points programmatically.

For the modifier variants:

animateVertex <modifier> <#all|index>

For the spacewarp variants:
http://forums.cgsociety.org/showthread.php?t=720508
( That thread also contains some useful hints for alternatives to the FFD )

here’s a function to get the currently selected control points; not sure what you want to do with it, but anyway…


 -- usage:
  -- <array>getSelectedCPs <ffdModifier>
  -- output array contains selected control points as <int>index for each CP
  
 fn getSelectedCPs FFDmod = (
 	-- defines
 	local WM_SETFOCUS = 0x007
 
 	-- back up some stuff we'll be changing
 	local oldCommandMode = toolmode.commandmode
 	local cmdPanelMode = getCommandPanelTaskMode()
 	local modPanelObj = modpanel.getCurrentObject()
 	local oldSubObjectLevel = subObjectLevel
 	local oldModEnabledInViews = FFDmod.enabledInViews
 
 	-- disable the modifier in viewports to speed up some calculations
 	FFDmod.enabledInViews = false
 
 	 -- let's collect all the control points' current positions
 	local curPositions = for prop in (getPropNames FFDmod) collect (
 		propValue = getProperty FFDmod prop
 		if (classOf propValue == point3) then ( propValue )
 		else ( dontcollect )
 	)
 	
 	-- go into modify mode
 	setCommandPanelTaskMode #modify
 
 	-- select the modifier
 	modpanel.setCurrentObject FFDmod
 
 	-- go to the control point sub-object level
 	subObjectLevel = 1
 
 	-- change to move mode
 	toolmode.commandmode = #move
 
 	-- open the transform type-in dialog
 	  max tti
 	
 	-- find the tti dialog
 	local desktopHWND = windows.getDesktopHWND()
 	  local desktopChildren = windows.getChildrenHWND desktopHWND
 	  local tti
 	  for child in desktopChildren do (
 		  if (child[5] == "Move Transform Type-In") then (
 			  tti = child
 			  exit
 		  )
 	  )
 	  if (tti == undefined) then ( return false )
   
 	  -- get the tti's handle
 	  local ttiHWND = tti[1]
 	  
 	  -- get its children
 	  local ttiChildren = windows.getChildrenHWND ttiHWND
 	  
 	-- set focus to the X Offset custedit control
 	UIAccessor.sendMessage ttiChildren[10][1] WM_SETFOCUS 0 0
 	-- change its value via the proper edit control - let's just offset by 1.0 unit
 	UIAccessor.setWindowText ttiChildren[12][1] "1.0"
 	-- now set focus to the Y offset custedit control
 	UIAccessor.sendMessage ttiChildren[13][1] WM_SETFOCUS 0 0
 
 	-- now, let's collect the new positions.
 	local newPositions = for prop in (getPropNames FFDmod) collect (
 		propValue = getProperty FFDmod prop
 		if (classOf propValue == point3) then ( propValue )
 		else ( dontcollect )
 	)
 
 	-- set focus to the X Offset custedit control
 	UIAccessor.sendMessage ttiChildren[10][1] WM_SETFOCUS 0 0
 	-- change its value via the proper edit control - move the control points back 1.0 unit
 	UIAccessor.setWindowText ttiChildren[12][1] "-1.0"
 	-- now set focus to the Y offset custedit control
 	UIAccessor.sendMessage ttiChildren[13][1] WM_SETFOCUS 0 0
 	
 	  -- close that tti dialog
 	  UIAccessor.CloseDialog ttiHWND
 
 	-- now let's figure out what the difference between the two arrays is
 	local selectedCPs = for i = 1 to curPositions.count collect (
 		if (curPositions[i] != newPositions[i]) then ( i )
 		else ( dontcollect )
 	)
 
 	-- restore stuff
 	FFDmod.enabledInViews = oldModEnabledInViews
 	setCommandPanelTaskMode cmdPanelMode
 	if (modPanelObj != undefined) then (
 		modpanel.setCurrentObject modPanelObj
 	)
 	if (oldSubObjectLevel != undefined) then (
 		subObjectLevel = oldSubObjectLevel
 	)
 	toolmode.commandmode = oldCommandMode
 	
 	selectedCPs
 )
 

Note that this uses some UI interaction methods (opening a dialog, changing a spinner value) that will briefly make the screen flicker.
In addition, due to the UI interaction, focus changes to different controls. If you are calling this from a scripted UI, make sure you use ‘setFocus <control>’ after calling the function to return focus to one of the controls in your own UI.

The script above was written for 3ds Max 2009; I’m hoping none of the spinner indices are different in older versions of 3ds Max.

If you run into any problems, just let me know.

Edit: Forgot to mention – as it has to be able to access the control points to determine whether they moved, the control points -must- be made accessible via ‘animateVertex <ffdmod> <#all|index>’ at some point before calling the function.

Or, open 3dsmax.exe in a hex editor, go to byte offset 4815162 and change the value to 42

what… you can’t present a .NET function for that?

err ok not sure i get the in jokes there…scripters humour hey!

zeeboxx thats fantastic i’ll try it thanks…geez that seems like a lot of script for something i thought would be simple…

what i want to do is offset various groups of control points in time from one another

…anyways…so how do i call the function. When i evaluate it it echos back getSelectedCPs () in the window but thats it.

cheers

paul

The basic usage example is:


animateVertex FFD_modifier #all -- to make sure all points can be accessed
selectedControlPoints = getSelectedCPs FFD_modifier

So if the modifier is the top-most modifier on your currently selected object:


animateVertex $.modifiers[1] #all -- to make sure all points can be accessed
selectedControlPoints = getSelectedCPs $.modifiers[1]

The ‘selectedControlPoints’ variable at that points contains the indices of the selected control points in an array, e.g.


#(1,2,3,4,7,8,9)

So if you want to move those control points…


for index in selectedControlPoints do (
	-- $.modifiers[1][3] = Control Points master track
	$.modifiers[1][3][index] = [x,y,z] --position
)

Note that control points are the in the FFD modifier’s local coordinate space – have a search through this forum for a few functions to get/set the control point positions in world coordinate space if that’s what you’d need

thanks Zeebox

this all makes sense thanks to your explanations.

much appreciated.

paul