PDA

View Full Version : getPropNames for subobject selections


pgill
02-13-2009, 11:55 PM
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 $sphere01.'FFD(box) 4x4x4' #dynamicOnly

which produces a list of the animated control points.

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

cheers

paul

magicm
02-14-2009, 01:03 AM
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

ZeBoxx2
02-14-2009, 01:05 AM
Also, the points can only be accessed/changed (position only) after they have been animated manually
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 )

ZeBoxx2
02-14-2009, 03:05 AM
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.

magicm
02-14-2009, 12:33 PM
Or, open 3dsmax.exe in a hex editor, go to byte offset 4815162 and change the value to 42 :)

ZeBoxx2
02-14-2009, 01:57 PM
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? ;)

pgill
02-16-2009, 09:45 PM
err ok not sure i get the in jokes there...scripters humour hey!:D

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

ZeBoxx2
02-16-2009, 11:33 PM
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 :)

pgill
02-17-2009, 12:18 AM
thanks Zeebox

this all makes sense thanks to your explanations.

much appreciated.

paul

CGTalk Moderation
02-17-2009, 12:18 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.