Announcement

Collapse
No announcement yet.

rigging control help

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • rigging control help

    well its not help on the actual rigging but on the controls im using. basically ive got a character for which i learnt how to create some controls for it using models and this is what i came up with



    i would actually rather have a floating panel with numerical inputs and a little x under each numerical input for deleting the keyframe thats under that particular input. when i was playing with the demo of automatron i loved the control panel. and would rather make a panel for my characters that looked something like this.


    does anyone know where i can get a tutorial on doing something like this?

    ---------------------------------------------------
    MSN addresses are not for newbies or warez users to contact the pros and bug them with
    stupid questions the forum can answer.

  • #2
    Have you gone throug the help for the Attribute Holder/Parameter Editor? It won't give you a floater, but you can make it so anytime you select a certain object you will have sliders in the control panel. The Parameter Collector could also come in handy as well.
    - Geoff

    Comment


    • #3
      actually i fought all day with the maxscript help which isnt written too well and FINALLY after hours figured out how to get a floating window with a rollout. the one you see about is photoshop at its finest lol
      Last edited by Da_elf; 12-12-2007, 10:11 PM.

      ---------------------------------------------------
      MSN addresses are not for newbies or warez users to contact the pros and bug them with
      stupid questions the forum can answer.

      Comment


      • #4
        Glad you're making progress.

        You should also take a look at this awesome Chuggnut script: http://www.chuggnut.com/scripts/anipose/anipose.htm
        - Geoff

        Comment


        • #5
          To get a rollout floater (like the photoshop you showed above is simple with maxscript)

          Code:
          rollout rlt_Mouth "Mouth" (
              spinner spn_oo "OO " fieldWidth:40 range:[0,100,100] align:#left offset:[0,5]
          	spinner spn_mc "MC " fieldWidth:40 range:[0,100,100] align:#left offset:[80,-21]
          	spinner spn_ah "AH " fieldWidth:40 range:[0,100,100] align:#left offset:[160,-21]
          	spinner spn_fv "FV " fieldWidth:40 range:[0,100,100] align:#left offset:[240,-21]
          	spinner spn_mm "MM " fieldWidth:40 range:[0,100,100] align:#left offset:[320,-21]
          	button btn_oo_x "X" align:#left offset:[30,0]
          	button btn_mc_x "X" align:#left offset:[110,-26]
          	button btn_ah_x "X" align:#left offset:[190,-26]
          	button btn_fv_x "X" align:#left offset:[270,-26]
          	button btn_mm_x "X" align:#left offset:[350,-26]
          	
          	on spn_oo changed val do (
          		print val
          	)
          	on btn_oo_x pressed do (
          		messageBox "You pressed the X button below OO"
          	)
          	
          )
          
          rollout rlt_Eyes "Eyes" (
          	-- Add eye controls
          )
          
          rollout rlt_Arms "Arms" (
          	-- Add arm controls
          )
          
          rf = newRolloutFloater "Animation Controls" 450 150	-- Creates the Rollout Floater
          addRollout rlt_Mouth rf	-- Adds the rollout rlt_Mouth to the rollout floater
          addRollout rlt_Eyes rf rolledUp:true	-- Adds the rollout rlt_Eyes to the rollout floater
          addRollout rlt_Arms rf rolledUp:true	-- Adds the rollout rlt_Arms to the rollout floater
          Last edited by MoonDoggie; 13-12-2007, 09:02 AM.
          Colin Senner

          Comment


          • #6
            please may a masxscript god help me. where am i going wrong here

            Code:
            rollout Eyes "Eyes" width:512 height:300
            (
            	spinner Channel_one "Channel One" range:[0,1000,1] type:#float controller:(WM3_MC_GetValue $Box01.modifiers[#Colonel_Face_Morpher] 1)
            )
            
            Anim_Controls = newRolloutFloater "Animation Controls" 560 460
            addRollout Eyes Anim_Controls
            i keep getting an error . for example if the morph target in slot 1 was set to 63 it would say
            " -- Unable to convert: 63.0 to type: Controller "

            when i type in ......
            Code:
            WM3_MC_GetValue $Box01.modifiers[#Colonel_Face_Morpher] 1
            .... into the listener i get a return of 63.0 so somethings working in that piece of code

            even if i change the morph for...
            Code:
            $Box03.modifiers[#Bend].BendAngle
            i get the same error. it cant seem to change whatever number is in either the morph amount or the number in the bend angle to be able to show up as a number the spinner can understand

            when i use
            Code:
            controller:($ball.radius.controller)
            it works great to control the radius of a sphere but the stupid morph thing wont work. even when i add .controller after the 1
            Last edited by Da_elf; 13-12-2007, 11:28 AM.

            ---------------------------------------------------
            MSN addresses are not for newbies or warez users to contact the pros and bug them with
            stupid questions the forum can answer.

            Comment


            • #7
              No fear.

              Check this out. I haven't worked with this exactly, but firstly your problem is a simple logical error.

              You are saying with this line
              spinner Channel_one "Channel One" range:[0,1000,1] type:#float controllerWM3_MC_GetValue $Box01.modifiers[#Colonel_Face_Morpher] 1)
              1. create a spinner
              2. set it's min value to 0, max to 1000, default to 1
              3. set it's type to float
              -> 4. set it's controller value to (WM3_MC_GetValue $Box01.modifiers[#Colonel_Face_Morpher] 1)

              So I reference the maxscript help file and check the topic "spinner", it reads this

              spinner <name> [ <caption> ] [ range:[min,max,val] ] [type:<name>] [scale:<float>] [ fieldWidth:<integer>] [indeterminate:<boolean>] [controller<controller>)]
              Ah-ha! That's the problem. you are passing an integer as a (<controller>), which the script doesn't like! You need to pass the actual controller instead of it's value (63) to the controller property of your spinner.

              It's like me asking you to give me an actual apple and you say outloud "apple"... While I was asking for the object apple, and you gave me the word.
              Last edited by MoonDoggie; 13-12-2007, 04:24 PM.
              Colin Senner

              Comment


              • #8
                So....here is what you are looking for I believe.

                Code:
                rollout Eyes "Eyes" width:512 height:300
                (
                	spinner Channel_one "Channel One" range:[0,1000,1] type:#float
                	
                	on Channel_one changed val do (  -- the variable val holds the value of the spinner
                		WM3_MC_SetValue $Box01.modifiers[#Colonel_Face_Morpher] 1 val  -- sets the morph target in slot index 1 to the value of the spinner (val)
                	)
                )
                
                rf = newRolloutFloater "Animation Controls" 560 460
                addRollout Eyes rf
                Very simple. Callbacks would work too though.
                Last edited by MoonDoggie; 13-12-2007, 04:25 PM.
                Colin Senner

                Comment


                • #9
                  wow. that worked. now let me figure out how to have the figure in the morpher reflect the figure in the roolout and vice versa. make a change to one and the change happens to the other immediately.

                  why wouldnt
                  Code:
                  spinner Channel_one "Channel One" range:[0,100,1] type:#float controller: (WM3_MC_GetValue $Box01.modifiers[#Colonel_Face_Morpher] 1 val)
                  work if this works
                  Code:
                  spinner Channel_one "Channel One" range:[0,100,1] type:#float controller: ($ball.radius.controller)
                  when you said im passing an integer as a controller it doesnt make sence. an integer is a whole number and the value in the morpher isnt a whole number (eg 82.7) therefore the value in the morpher isnt an integer
                  Last edited by Da_elf; 13-12-2007, 04:52 PM.

                  ---------------------------------------------------
                  MSN addresses are not for newbies or warez users to contact the pros and bug them with
                  stupid questions the forum can answer.

                  Comment


                  • #10
                    this is more or less where im at now

                    Code:
                    rollout Facial "Controls" width:512 height:434
                    (		
                    	button Ra_Delete "X" pos:[62,54] width:13 height:15
                    	spinner Ra "Ra" pos:[38,30] width:62 height:16 range:[0,1000,1] type:#worldunits controller: ($Sphere01.radius.controller) --works as expected where the spinner controls the radius
                    	spinner MM "MM" pos:[118,30] width:62 height:16 range:[0,100,0] type:#float controller: (WM3_MC_GetValue $Box01.modifiers[#Colonel_Face_Morpher] 1)--does not work to have the spinner control slot1 in the morpher modifier.
                    	button MM_Delete "X" pos:[142,54] width:13 height:15
                    	GroupBox Mouth_G "Mouth" pos:[7,11] width:495 height:155	
                    	
                    	on Ra_Delete pressed do 
                    	(
                    	selecetKeys $Sphere01.radius.controller [time ((currentTime as integer)/TicksPerFrame)]--doesnt work, need to be able to select the radius keys at the current time (would also like to have a check to see if there are indeed keys at that time and do nothing if not)
                    	deleteKeys $Sphere01.radius.controller #selection--this would work if the line above worked
                    	)
                    	
                    	on MM_Delete pressed do --nothing in here works since the morpher spinner above doesnt work either
                    	(
                    	selecetKeys $Box01.modifiers[#Colonel_Face_Morpher] 1 [time ((currentTime as integer)/TicksPerFrame)]
                    	deleteKeys $Box01.modifiers[#Colonel_Face_Morpher] 1 #selection
                    	)
                    )
                    
                    Anim_Controls = newRolloutFloater "Animation Controls" 560 490
                    addRollout Facial Anim_Controls
                    im giving up for tonight. back at it tomorow

                    ---------------------------------------------------
                    MSN addresses are not for newbies or warez users to contact the pros and bug them with
                    stupid questions the forum can answer.

                    Comment


                    • #11
                      LONG: but read me
                      The comments in this reply are going to more directed at good coding practices and less at your immediate problem, keep these practices in mind and you'll save yourself some hassle troubleshooting/error checking later.

                      Also: Bare with me, I'm not exactly clear on what you want to do. I'll do my best

                      deleteKeys $Sphere01.radius.controller #selection--this would work if the line above worked
                      Using syntax like this for accessing your sphere can be very troublesome, for instance if the sphere which is being controlled, changes names or doesn't exist, this line will throw an error.

                      A better way to do this, would be to store the object your controlling in a variable which will contain a reference to the node so that if the name get changed or anything, it will still reflect the correct node.

                      You can do this two ways depending on what you need.

                      The best way would be to actually create the sphere and assign it to a variable when you create it:

                      Code:
                      mySphere = sphere()
                      or if you know the height and position of the sphere you could go ahead and assign it at creation as well. Sphere in this case because it has no additional arguments needs brackets () around it, if it has additional arguments passed, it doesn't need them like below:

                      Code:
                      mySphere = sphere name:"Sphere01" radius:2 pos:[10,10,0]
                      Now the variable "mySphere" holds your instance of the sphere you created, so changing the name to "RiggingSphere" will not change what sphere we're referring to

                      Code:
                      mySphere.name = "RiggingSphere"
                      If this is not an option, perhaps you need a special sphere to control or whatever, another option would be to use the method "getNodeByName <string>", which will get the node by the name "<string>". Note this method requires you know the name at some point.

                      Code:
                      mySphere = getNodeByName "Sphere01"
                      Now you are free to change the name or whatever of mySphere, without worry that you won't be able to access it later.

                      You can use the rollout event handler "on <rollout> open do <exp>" to store these variables when the rollout is created.

                      so in the above example below "on MM_Delete pressed do ( <code> )" you could add

                      Code:
                      on Facial open do
                      (
                           mySphere = getNodeByName "Sphere01"
                      )
                      now anywhere in your code you can refer to mySphere and it will be the correct sphere for instance changing it's radius etc

                      Code:
                      deleteKeys mySphere.radius.controller #selection
                      Just some food for thought.

                      A cosmetic thing to do, which can get aggrivating when trying to code is everytime you run your script, you'll notice if you don't start closing the other windows, they'll pile up. You can alleviate this by adding a simple line of code with some error checking try()catch() to try to destroy old instances of your windows before creating it again, add this at the beginning to do that.

                      Code:
                      try ( closeRolloutFloater Anim_Controls ) catch ()
                      Now for the harder stuff.
                      -Colin
                      Colin Senner

                      Comment


                      • #12
                        Alrighty, now that the stuff is fixed, we end up at this code (simplified from yours)

                        Code:
                        try ( closeRolloutFloater Anim_Controls ) catch ()
                        
                        rollout Facial "Controls" width:512 height:434
                        (		
                        	Group "Mouth"
                        	(
                        		spinner Ra "Ra" fieldWidth:40 range:[0,1000,1] type:#float align:#center
                        		button Ra_Delete "X" width:13 height:15 align:#center
                        	)
                        	
                        	on Facial open do (
                        		-- Setup some global variables to use in other event handlers
                        		mySphere = getNodeByName "Sphere01"			-- Saves the sphere node reference in the variable mySphere
                        
                        		-- This for loop will loop through all the modifiers on the object mySphere ("Sphere01") and will find the morpher mod
                        		--    whatever it's called, in my case "Morpher", in yours since it's renamed "Colonel_Face_Morph"
                        		for m in mySphere.modifiers where classof m == Morpher do	-- This for statement doesn't need ( ) brackets, because there is only one line that needs to be executed after it
                        			morpherMod = m
                        	)
                        	
                        	on ra changed val do (
                        		-- Sets the value of the morpher to whatever the spinner changed to
                        		WM3_MC_SetValue morpherMod 1 (val as float)
                        	)	
                        )
                        Anim_Controls = newRolloutFloater "Animation Controls" 200 110
                        addRollout Facial Anim_Controls
                        Now, that works! However we can add some error checking to make sure that our variables are getting the correct things in them

                        Code:
                        try ( closeRolloutFloater Anim_Controls ) catch ()
                        
                        rollout Facial "Controls" width:512 height:434
                        (		
                        	Group "Mouth"
                        	(
                        		spinner Ra "Ra" fieldWidth:40 range:[0,1000,1] type:#float align:#center
                        		button Ra_Delete "X" width:13 height:15 align:#center
                        	)
                        	
                        	on Facial open do (
                        		-- Setup some global variables to use in other event handlers
                        		mySphere = getNodeByName "Sphere01"			-- Saves the sphere node reference in the variable mySphere
                        		morpherMod = undefined						-- set it as undefined from the start or "null" in other languages
                        		
                        		-- if getNodeByName cannot find an object named "Sphere01" it will return the value undefined, we'll see if it found it, by making sure that mySphere does not equal undefined
                        		if mySphere != undefined then (
                        			-- This for loop will loop through all the modifiers on the object mySphere ("Sphere01") and will find the morpher mod
                        			--    whatever it's called, in my case "Morpher", in yours since it's renamed "Colonel_Face_Morph"
                        			for m in mySphere.modifiers where classof m == Morpher do	-- This for statement doesn't need ( ) brackets, because there is only one line that needs to be executed after it
                        				morpherMod = m
                        			
                        			if morpherMod != undefined then (	-- if the morpher mod wasn't found, then the line "morpherMod = m" will never be executed, meaning it will still equal undefined like we set it to at the beginning
                        				-- Execute something!		
                        			)
                        			else 
                        				messageBox ("Could not locate the morpher modifier on the object " + mySphere.name)
                        		)
                        		else (
                        			messageBox "mySphere was not able to be found!"  
                        			closeRolloutFloater Anim_Controls	-- Destroy the rollout floater
                        		)
                        	)
                        	
                        	on ra changed val do (
                        		-- Sets the value of the morpher to whatever the spinner changed to
                        		WM3_MC_SetValue morpherMod 1 (val as float)
                        	)	
                        )
                        Anim_Controls = newRolloutFloater "Animation Controls" 200 110
                        addRollout Facial Anim_Controls
                        These error checks will make sure that
                        1. the sphere exists by the name "Sphere01"
                        2. that the sphere which it found by the name "Sphere01" does indeed contain a morpher modifier

                        If either of these don't work, the script will clearly not do anything. For highly specialized cases where the rig is very controlled, you will already have thought through these and things will be named correctly and under control so they may not be necessary.

                        Now, this works fine and dandy, but we have run into a problem...The sphere updates correctly, if we use the spinner, but what if we change the actual morpher modifier influence via the modify panel...It doesn't update the spinner.

                        So replace the line "-- Execute something" with this

                        Code:
                        when parameters morpherMod changes HandleAt:#RedrawViews id:#morpher_mod_id do updateSpinners()
                        What that does is basically a wire parameters from the morpher modifier to a function called "updateSpinners()" which we'll write to update the values of the spinners in the rollout floater.

                        Breaking that line down a bit more
                        Code:
                        when parameters morpherMod
                        when any parameter of the morpherModifier changes

                        Code:
                        HandleAt:#RedrawViews
                        when to update it

                        Code:
                        id:#morpher_mod_id
                        registers the callback with an id named #morpher_mod_id, this is important because when we close the rollout, we need to unregister the parameter which will persist until max gets closed if we don't, and could cause other problems, and to unregister a parameter it needs a unique id, which we called #morpher_mod_id

                        now, after "on ra changed val do (" we need to have it unregister the callback on the rollout close, add this after the end of that event handler

                        Code:
                        	on Facial close do (	-- When the rollout is closed
                        		deleteAllChangeHandlers id:#morpher_mod_id
                        	)
                        Now, we need to write the function updateSpinners() to tell it what to do when the morpher Modifier is changed, above "on Facial open do (" add this function

                        Code:
                        	fn updateSpinners = (
                        		Ra.value = (WM3_MC_GetValue morpherMod 1) as float
                        	)
                        Now anytime we call updateSpinners() it will change the value of the spinner Ra to whatever value the morpher is set at...

                        So the final code will be this:

                        Code:
                        try ( closeRolloutFloater Anim_Controls ) catch ()
                        
                        rollout Facial "Controls" width:512 height:434
                        (		
                        	Group "Mouth"
                        	(
                        		spinner Ra "Ra" fieldWidth:40 range:[0,1000,1] type:#float align:#center
                        		button Ra_Delete "X" width:13 height:15 align:#center
                        	)
                        	
                        	fn updateSpinners = (
                        		Ra.value = (WM3_MC_GetValue morpherMod 1) as float
                        	)
                        	
                        	on Facial open do (		-- When the rollout is opened on creation
                        		-- Setup some global variables to use in other event handlers
                        		mySphere = getNodeByName "Sphere01"			-- Saves the sphere node reference in the variable mySphere
                        		morpherMod = undefined						-- set it as undefined from the start or "null" in other languages
                        		
                        		-- if getNodeByName cannot find an object named "Sphere01" it will return the value undefined, we'll see if it found it, by making sure that mySphere does not equal undefined
                        		if mySphere != undefined then (
                        			-- This for loop will loop through all the modifiers on the object mySphere ("Sphere01") and will find the morpher mod
                        			--    whatever it's called, in my case "Morpher", in yours since it's renamed "Colonel_Face_Morph"
                        			for m in mySphere.modifiers where classof m == Morpher do	-- This for statement doesn't need ( ) brackets, because there is only one line that needs to be executed after it
                        				morpherMod = m
                        			
                        			if morpherMod != undefined then (	-- if the morpher mod wasn't found, then the line "morpherMod = m" will never be executed, meaning it will still equal undefined like we set it to at the beginning
                        				when parameters morpherMod changes HandleAt:#RedrawViews id:#morpher_mod_id do updateSpinners()
                        			)
                        			else 
                        				messageBox ("Could not locate the morpher modifier on the object " + mySphere.name)
                        		)
                        		else (
                        			messageBox "mySphere was not able to be found!"  
                        			closeRolloutFloater Anim_Controls	-- Destroy the rollout floater
                        		)
                        		
                        		-- Now we need to set the initial value of the spinner to whatever the value of the Morpher mod is at, we'll call the function we wrote updateSpinners to update all the spinners with the correct values
                        		updateSpinners()
                        	)
                        		
                        	on ra changed val do (	-- whenever the spinner ra is changed
                        		-- Sets the value of the morpher to whatever the spinner changed to
                        		WM3_MC_SetValue morpherMod 1 (val as float)
                        	)	
                        	
                        	on Facial close do (	-- When the rollout is closed
                        		deleteAllChangeHandlers id:#morpher_mod_id
                        	)
                        )
                        Anim_Controls = newRolloutFloater "Animation Controls" 200 110
                        addRollout Facial Anim_Controls
                        WHEW, is that all?
                        Colin
                        Colin Senner

                        Comment


                        • #13
                          thanks for the time put in. im understanding a bit more but ive still got some issues which i dont quite get.

                          ::1st thing is ill describe my "test scene"::

                          ive got 3 object in the scene. there is Sphere01, there is Box01 and Box02
                          Sphere01 is just a normal sphere
                          Box01 has been converted to an editable mesh and same with Box02(after i bent it)
                          Box02 is the morph target in slot1 of the Morph modifier applied to Box01
                          There is also a meshsmooth on Box01.

                          ::My Code::

                          i started my tests on something simple...the sphere01. i just wanted to see if i could change a value on an object through a script and i chose the radius of the sphere as the value to change. the spinner Ra was for Radius and the code i used had the spinner controlling the radius as well as the radius spinner in the modifier panel controlling my spinner. When i did keyframing of the radius the arrors on my spinner would have the redbrackets on them to signify the keyframe. the X button under the spinner i want to delete the keyframe for the above spinner (i could only get it to work to delete all keyframes or to delete the keyframe at the time only if i manually select the keyframe (i wanted it to automatically select keyframes at that timeslider frame im on 10 for example))
                          So more or less i got my sphere working (except for the delete keyframe part) and the whole sphere stuff worked off of one simple line of code and i never needed to use the "if spinner changes do" type of stuff. This one solitary line of code did it all. (strange thing though is that its not working this morning. I got that code straight from the help file under the spinner section.)
                          Code:
                          spinner Ra "Ra" pos:[38,30] width:62 height:16 range:[0,1000,1] type:#worldunits controller: ($Sphere01.radius.controller)
                          now that was just for the fun of trying to control an object. the 2nd spinner was more of a practical test since ill have a character with morph targets for facial animation. So i setup the boxes as my test. This is where things got complex. I was hoping i could do it with one line. Basically i didnt need the error checking since i knew that in my scene would be Colonel_Head and on him would be Colonel_Face_Morph. The only check i would have needed would be to do with the X button for the face morph spinners. there were going to be other spinners to deal with the weights in a rotational orientation constraint and a possition constraint. Anyhow. i tried out your code and this is what happened. (note i changed the name of the box01 to sphere01 and the morpher i called morpher just to satisfy your code



                          i just put this together in maxscript. its non-functional but its what i want in the end.
                          Last edited by Da_elf; 14-12-2007, 08:41 AM.

                          ---------------------------------------------------
                          MSN addresses are not for newbies or warez users to contact the pros and bug them with
                          stupid questions the forum can answer.

                          Comment


                          • #14
                            The only thing you should have needed to change is the name of the sphere

                            Code:
                            		-- This for loop will loop through all the modifiers on the object mySphere ("Sphere01") and will find the morpher mod
                            		--    whatever it's called, in my case "Morpher", in yours since it's renamed "Colonel_Face_Morph"
                            		for m in mySphere.modifiers where classof m == Morpher do	-- This for statement doesn't need ( ) brackets, because there is only one line that needs to be executed after it
                            			morpherMod = m
                            This line actually finds the morpherMod no matter what name it goes by. It does this by checking the modifiers on the object and finding something with the "classof m == Morpher". So renaming that won't change what it finds.

                            Do me a favor and find the line that it is having a problem with and I'll check in it a little bit. The code executed fine on my machine with a some simple sphere morphs.

                            The thing is to do it with one line, you'd have to create a custom controller and store the value of the morph target somewhere in the controller.

                            I'll explain why passing a number to the controller: parameter doesn't work.

                            Simply it doesn't work because the number you were passing "63" is not a controller, it's an integer. Check by executing this line of code with a sphere name sphere01 in the scene

                            Code:
                            $Sphere01.radius
                            It returns 10 for me, or the radius of my sphere. Now try plugging in that into a spinners controller value ($Sphere01.radius)

                            Code:
                            spinner spn_Test "Test:" controller:$Sphere01.radius
                            And you get "Unable to convert 10 to type: Controller" error...it is trying to convert the number 10 to a controller, which it isn't. It's an integer.

                            BUT if you plugin the actual controller for the radius value which is $Sphere01.radius.controller (which you can tell exists by typing "$Sphere01.controller")

                            You starting to get it? The way I did it works great, The process to do what you want via a controller, is going to be more difficult than the solution I did with when parameter change.

                            You could create an empty controller, assign the controller to the setvalue of the wm3_mc interface and control it that way, but I think that's more complicated for the same payoff.
                            Colin Senner

                            Comment


                            • #15
                              Post the test file, and I'll run that script and see what the problem is. I didn't have any problems on my machine with a simple test with some spheres.
                              Colin Senner

                              Comment

                              Working...
                              X