Home Coding, Scripting, Shaders

[3DS Max] Save Poses

polycounter lvl 7
Offline / Send Message
dg3duy polycounter lvl 7
Any kind of example to be able to save a couple of poses of a single object and have the possibility to load the poses, any maxscript code you can share on this topic?

Replies

  • poopipe
    Offline / Send Message
    poopipe grand marshal polycounter
    Which bit are you struggling with ? 

    copying a transform is simply a case of assigning a node's transform to a variable (t = node.transform)
    applying a stored transform is simply a matter of assigning a variable to a node's transform (node.transform = t)

    if you work in a rollout, anything you store will persist as long as the rollout is open so you can happily store multiple transforms without fannying around with persistent stuff at scene level.

    the UI is the where it might get a bit tedious
  • dg3duy
    Offline / Send Message
    dg3duy polycounter lvl 7
    poopipe said:
    Which bit are you struggling with ? 

    copying a transform is simply a case of assigning a node's transform to a variable (t = node.transform)
    applying a stored transform is simply a matter of assigning a variable to a node's transform (node.transform = t)

    if you work in a rollout, anything you store will persist as long as the rollout is open so you can happily store multiple transforms without fannying around with persistent stuff at scene level.

    the UI is the where it might get a bit tedious

    I mean something like this type of script, the problem is that you have to add a parameter block and attribute holder to keep the information in the scene, which I don't know how to do it.

    https://forums.cgsociety.org/t/saving-character-poses-on-custom-rigs/880779/5


    ------copy pose

    1.  
    2. MyLatestPose = #() --empty container
    3. Obj = selection as array --current selection
    4. for i = 1 to Obj.count do
    5. (
    6. o = Obj[i]
    7. t = Obj[i].transform.controller.value --get the local value of the controller
    8. append MyLatestPose #(o,t)
    9. )

    ---- to paste

    1.  
    2. if MyLatestPose != undefined then --<span>simple test to make sure a pose has been copyed
    3. (<span>
    4. for i = 1 to MyLatestPose.count do
    5. (
    6. objTranAr = MyLatestPose[i]
    7. o = objTranAr[1] -- get transform data
    8. t = objTranAr[2] -- get the object it belongs too
    9. o.transform.controller.value = t
    10. </span>)
    11. )</span>
  • poopipe
    Offline / Send Message
    poopipe grand marshal polycounter
    that's the fannying around I was talking about. It's definitely in the docs but it's been 10 years since I last did anything that needed it. 

    I imagine Monster will be along with an answer at some point.  might be worth changing the thread title to indicate you need help storing persistent data  
  • dg3duy
    Offline / Send Message
    dg3duy polycounter lvl 7
    poopipe said:
    that's the fannying around I was talking about. It's definitely in the docs but it's been 10 years since I last did anything that needed it. 

    I imagine Monster will be along with an answer at some point.  might be worth changing the thread title to indicate you need help storing persistent data  
    I know that monster is one of the few who are still active in answering users' questions. He also has an incredible knowledge of the whole program, I hope he can answer this question and help some "new" users.
  • monster
    Offline / Send Message
    monster polycounter
    We're dealing with some major weather issues down in Texas! But I managed to whip up this example with some pseudo code in the rollout section.

    Things to note:
    • In General, as poopipe mentioned, you operate with the poses stored in the rollout. You only access a custom attribute when opening and closing (loading and saving) the rollout.
    • I don't use Attribute Holder because they can only be accessed when an object is selected.
    • Instead I save directly to the RootNode. Think of that as the object all unparented object are parented to. :D
    • For the CA value types, I use #stringTab, instead of #maxObjectTab because if an object is deleted it really freaks out that there is a reference to a deleted object in the Custom Attribute.
    • Also, #stringTab has maximum compatibility. #paramBlock2 was added in 2018 and I still have people using Max 2009 and such.
    • I guess you can use #matrix3Tab for the Transform Array, but i already typed it all out.
    1. global PoseTools
    2.  
    3. struct PoseToolStruct
    4. (
    5. poseCA = attributes poseLibrary
    6. (
    7. parameters pose_params
    8. (
    9. 'poseNameArray' type:#stringtab tabSize:0 tabSizeVariable:true
    10. 'objectArray' type:#stringtab tabSize:0 tabSizeVariable:true
    11. 'transformArray' type:#stringtab tabSize:0 tabSizeVariable:true
    12. )
    13. ),
    14.  
    15. PoseToolRollout = rollout PoseToolRollout "Pose Tool" width:#cmdPanel
    16. (
    17. --UI CODE
    18.  
    19. --STRUCT TO STORE A POSE IN THE ROLLOUT
    20. struct Pose
    21. (
    22. poseName = "",
    23. objectArray = #(),
    24. transformArray = #()
    25. )
    26.  
    27. --ARRAY OF CURRENT POSES FOR THE ROLLOUT
    28. local PoseArray = #()
    29.  
    30. --FUNCTION TO ADD A CA TO THE MAX FILE
    31. fn addPoseCAToRootNode =
    32. (
    33. if not isProperty rootnode #poseLibrary do
    34. (
    35. format "Adding poseLibrary to the rootnode.\n"
    36. custAttributes.add rootnode PoseToolStruct.poseCA
    37. )
    38. )
    39.  
    40. --LOAD THE POSES STORED IN THE MAX FILE
    41. fn LoadPosesFromCustomAttribute =
    42. (
    43. --ENSURE A CA HAS BEEN ADDED TO THE FILE
    44. addPoseCAToRootNode()
    45.  
    46. --CLEAR THE POSE ARRAY AND GET THE NUMBER OF STORED POSES
    47. PoseArray = #()
    48. pCount = rootnode.poseNameArray.count
    49.  
    50. --FOR EACH STORED POSE
    51. for i = 1 to pCount do
    52. (
    53. NewPose = Pose poseName:(rootnode.poseNameArray[i]) objectArray:(execute(rootnode.objectArray[i])) transformArray:(execute(rootnode.transformArray[i]))
    54. append PoseArray NewPose
    55. )
    56. )
    57.  
    58. --FILL THE CA WITH THE CURRENT POSE ARRAY
    59. fn SavePosesToCustomAttribute =
    60. (
    61. --ENSURE A CA HAS BEEN ADDED TO THE FILE
    62. addPoseCAToRootNode()
    63.  
    64. --SET THE VALUES FOR THE CA
    65. with printAllElements on
    66. (
    67. rootnode.poseNameArray = for p in PoseArray Collect p.poseName
    68. rootnode.objArray = for p in PoseArray Collect (p.objectArray as string)
    69. rootnode.transArray = for p in PoseArray Collect (p.transformArray as string)
    70. )
    71. )
    72.  
    73. --HANDLE ROLLOUT OPENING
    74. on PoseToolRollout open do
    75. (
    76. LoadPosesFromCustomAttribute()
    77. )
    78.  
    79. --HANDLE ROLLOUT CLOSING
    80. on PoseToolRollout close do
    81. (
    82. SavePosesToCustomAttribute()
    83. )
    84.  
    85. --COPY FUNCTION ADDS A NEW POSE (STRUCT) TO THE POSE ARRAY
    86. --PASTE FUNCTION APPLIES A POSE FROM THE POSE ARRAY TO OBJECTS
    87. )
    88.  
    89. )
    90.  
    91. PoseTools = PoseToolStruct()

  • dg3duy
    Offline / Send Message
    dg3duy polycounter lvl 7
    Wowww! This is a great example of what I was looking for! thanks so much for sharing!
Sign In or Register to comment.