I am looking into these scripts and therefore I have posted a little website on my .Mac account, so everyone can inspect the scripts with color coding. I have found some quirks and odd behaviors, will see if I can explain them through the code, and possibly find some fixes for the bugs.
I have not fully analyzed these two scripts, but I have a couple of things I was wondering:
Would it be possible to put all of this in one script and do the scanning of the bone layers by iterating through all bone layers in the project file? I think this would remove the need to click on the timeline to see the effects on the control bones when you change properties of the master bones. You would only have to include the script in bone layers containing the master bones.
Would it be possible to use the extension (now ".mcb") to determine the master set? This would mean that you could use several sets of master bones controlling several sets of control bones across all bone layers in a Moho document. There would also be no conflict between master sets, and the interaction could be set up without programming (just by naming the bones appropriately). A possible way to distinguish between master and control bones is a ".m" and ".c". The characters following ".m" and ".c" would determine the specific master/control set. Because the master bone has to be named uniquely, this should be checked and an error message issued if a conflict occurs. For instance, you could issue a message "There are two master bones with the same extension .mXXXX in layers YYYY and ZZZZ" (replace XXXX, YYYY and ZZZZ with the specific information).
Edit: Regarding (2). An easier way would be a scheme in which every named bone on a layer which is scripted with the master control bone script is a master bone and that every bone that has the same name, but is outside the scripted layer is automatically its control bone. There would be no need for special naming conventions, other than that the names of master bone and control bone(s) are identical.
Besides that, the Bone Lock should be controlled as well, because it is also an animateable bone feature.
Edit2: Although it is possible to sense on which layer a layer script is active--by temporarily adding something (e.g. a bone on a bone layer) to the layer defined in moho.layer--it is such a hassle, that I don't want to be going in that direction. Let's stick with the .mXXXX and .cXXXX conventions for now.
Last edited by Rasheed on Mon Nov 27, 2006 4:13 pm, edited 1 time in total.
I have heard from several scripters in this forum that this COULD be done with one script.
I have tried to do this myself on several occasions but I don't have the LUA expertise to pull it off.
I have seen the light at the end of the tunnel... but my flashlight isn't bright enough to keep me from tripping on things as I try to get there.
I also have ran into that terrible slow down issue. Also if I scrub too quickly the script "breaks" and I have to go to frame 0 to reset it.
I still use the scripts but lately have been trying to keep its use very simple to avoid performance issues.
I know for a fact that this thing could be done much better and I welcome anyone to do whatever they like with it. I am not much of a programmer and I am shocked it works at all to be honest. I have backed off lately on LUA programming for AS due to other things that take as much time but are a bit more fun.
Vern, I have written a piece of code to add all the layers in a document to an array (see here).
Although the code I have written to put the layer structure into an array is not yet optimized, it works. I can always optimize it later and replace the code.
If you don't mind, I want to combine this code with your code to create a single file script, that has to be added to one of the layers of a document. The master control functionality would then work on the basis of the names of the bones.
A simple setup could be that XXXX.mstr controls XXXX.ctrl across all layers (XXXX is a variable part of the bone name, mstr and ctrl are fixed parts).
I just had a thought. You can synchronize more objects than just bones, using the master-control principle. In fact, you can synchronize every object that can be named, as long as there are animation channels available, and the named objects are accessible through Lua:
Bones
Bone Angle
Bone Translation
Bone Scale
Bone Lock
Point Groups
Point Motion
Point Curvature
Layers
Layer Translation
Layer Scale
Layer Z Rotation
Layer Y Rotation
Layer X Rotation
Layer Horizontal Flip
Layer Vertical Flip
Layer Shear
Layer Visibility
Layer Blur
Layer Opacity
Layer Shadow
Layer Shading
Layer Motion Blur
Unfortunately, styles and shapes cannot be animated this way, because there is no Name() member function for these objects, only a fName member variable, which needs a LM_String structure value assigned to, which cannot be read or written from within Lua (see this message by Mike, the developer of AS). Luckily, the bone, point group, and layer objects have member functions to access their names.
Of course, I will create the master-control script for bones first (because I really need it for one of my projects), and perhaps expand it into point groups and layers after the project is done (project deadline is December 15, 2006).
1. Is the Lock Bone-feature supported by this script?
I tried locking bones in the example file (bone_master.moho), but locking
only seem to respond on the master-skeleton.
2. I haven't been able to test the script on my own rigs due to a strange
problem:
I have created a "Bone"-directory in the moho\scripts\menu folder and
copied bone_master_v1.lua and bone_control_v1.lua to this directory.
However, in the Moho menu bar, what shows up are two "Torus" choices!?
Are there other ways to assign the script to the skeletons?
One of the things I could never get to work was bone locking with my original script. I got the keys in but it kept putting bone lock keys of every key and it just didn't work properly.
It was like the bone lock aspect is "different" from the other bone aspects.
Thanks Rasheed for taking this on!!! I think what I did was... uh... usable enough for small simple stuff... it got me excited... but when I pushed it just a little too far it breaks horribly. It needed some work that I just don't have the time or skills to pull off.
Feel free to do whatever you want to the script. No worries. Just as long as I get a copy.
You know, Vern, this is really, really though. I had to use all my wits and I have still a lot to do.
I have a single test layer script that is able to put the layer, bone name and bone ID into an array. I have two arrays, one with bones, which names end with ".mstr", and one with bones, which names end with ".ctrl".
This means I know exactly which bones in my document are masters and which are controlled bones, and I have full access to these bones, by their layer and Bone ID. I also know what they are called, so I can match up each master with its controlled bones. I will not check for the uniqueness of the master bone names, so it will be possible to have two master bones control the same set of control bones. This will enable you to use fancy master-control setups.
I now will have to add the Bone Angle, Bone Translation, Bone Scale, and Bone Lock of frame 0 into the array, so I can start controlling some bones, based on the animation parameters of the master bones in the current frame. I don't know how difficult it will be, but I'm very confident that I will pull it off.
BTW a single layer script is much more complicated than one master layer script and several control scripts. However, I think it is much more flexible, because you can change the control simply by changing the bone names, and you only have to embed a single script in the entire document, instead of a script for every controlled layer.
The drawback is that once you have loaded the single layer script, and you change something to the bone setup, you have to unload the layer script, reload the scripting engine (Ctrl F5, or Command F5 in Macs), and embed the layer script in another layer. This is because the bones are scanned only once, when the script is run for the very first time. If I wouldn't have done this, the bone scan function would interfere with the selected layer, because it needs to select each layer to access a possible skeleton object, and its possible bones. Of course, I keep resetting the selected layer to the layer that was selected by the user, but if the scan keeps being redone, it will mostly be at the highest bone type layer that contains either master or controlled bones. Every time you select another layer, a continuously scan routine will be selecting that bone layer I mentioned.
A non-dynamic solution isn't as flexible as a dynamic one, but it was the only solution I could come up with that actually worked. If someone has a tip how to do a continuous scan for all the skeleton objects within a document without effecting the layer selection in the Layers Window, I'm all eyes and ears...
Anyway, this shouldn't be much of a problem, because most users will probably not change anything in the master-control setup in frame zero, but rather animate using the existing bones. And they can always save the document, restart AS and reload the saved document.
Edit: Oh wow, another stroke of genius. Simply do the scan once outside layer zero, by creating a global layer variable holding a scan flag. Delete the scan flag when you're in frame zero. This means you can change whatever you want in frame zero, once you're in frame one or higher, the document is scanned and the fun can begin...
Hey guys, any chance to get it working on 6.1?
I'm working on a project and really need this good script, it would be great if some caritative scripter could help me.
Thanks
Ooouhf, the old controlled bones embedded script , that was when all the bad started to me...
Well, I've added the (¡Atieeende!) "ipairs" thing at "for ... in ... do" loop lines where lua console gave me the typical table error (as well as I've done in many other scripts) and now it seems to work just fine to me (as well as many other scripts! ) Although, of course... I'd love to know why?
--****************************************************************
bone_master_v1.lua CODE
function LayerScript(moho)
if (moho:CountBones() < 1) then
return false
end
local skel = moho:Skeleton()
-------------------------------------------------------------
--Find the Master Bones - only on frame zero
-------------------------------------------------------------
if (moho.frame == 0) then
-----------------------------------------------------
-- "mstrb" This is the array variable for the master bones list.
-- For more than one "set" of master/control bones
-- you need to duplicate both the master and control
-- scripts and change this variable name in both
-- otherwise they conflict
-- If you have more than one bone layer that needs to be mastered
-- you need another set of scripts that "match"
--
-- I would strongly reccomend
-- using a text editor with search and replace to make
-- this change. There are 18 occurences of this variable
-- that need to be changed.
-----------------------------------------------------
mstrb = {} -- change this variable on copies of script
-----------------------------------------------------
cnt=1 -- linear ID for table starting with 1
local layer = moho.layer
for count = 0, (skel:CountBones() - 1) do
local mBone = skel:Bone(count)
local name = mBone:Name()
-- this finds all the master bones based on
-- the .mcb suffix
if (string.find(name, "%.mcb")) then
local nsfx = string.sub(name, 1, string.find(name, "%.")-1)
mstrb[cnt] = {skel:BoneID(mBone), mBone}
--this one having trouble with... but it works
--puts the bone name in the array for matching
--the controlled bone
mstrb[cnt]["mnm"] = nsfx
cnt = cnt + 1
end
end
--This gets all the frame 0 stuff and adds to the array for use later
for k in ipairs(mstrb) do
local animAngle = mstrb[k][2].fAnimAngle:GetValue(0)
local animPos = mstrb[k][2].fAnimPos:GetValue(0)
local animScale = mstrb[k][2].fAnimScale:GetValue(0)
mstrb[k][3] = animAngle
mstrb[k][4] = animPos
mstrb[k][5] = animScale
end
end
----------------------------------------------------------------------------
--Set up the position. modifies and creates new entries in the array
--this should be simplified. I don't think the previous array entries above
--need to be stored after this point... will play with this.
----------------------------------------------------------------------------
for k in ipairs(mstrb) do
local masterbone = skel:Bone(mstrb[k][1])
mstrb[k][6] = masterbone.fAnimAngle:GetValue(moho.frame)- mstrb[k][3]
mstrb[k][7] = masterbone.fAnimPos:GetValue(moho.frame)- mstrb[k][4]
mstrb[k][8] = masterbone.fAnimScale:GetValue(moho.frame)- mstrb[k][5]
moho:Skeleton():UpdateBoneMatrix()
end
end
--****************************************************************
--bone_control_v1.lua CODE
function LayerScript(moho)
if (moho:CountBones() < 1) then
return false
end
local skel = moho:Skeleton()
-------------------------------------------------------------
--Find the Controlled Bone - only frame 0
-------------------------------------------------------------
if (moho.frame == 0) then
-------------------------------------------------------------
-- ctrb is the array variable for the control bones
-- it is unique for each layer this script is used
-------------------------------------------------------------
moho.layer.ctrb = {}
-------------------------------------------------------------
cnt=1 -- linear ID for table starting with 1.
-- Find a better way let me know.
local layer = moho.layer
for count = 0, (skel:CountBones() - 1) do
local cBone = skel:Bone(count)
local name = cBone:Name()
--Tricky spot again. Gets all the stuff into the array
--must be a better way... keep working on it.
--bone names MUST end with ".mcb" (master control bone)
--even the master bones can have the same name.
--It is the arrays and the rest of the script that determines
--the master/control relationship using this name.
if (string.find(name, "%.mcb")) then
local nsfx = string.sub(name, 1, string.find(name, "%.")-1)
moho.layer.ctrb[cnt] = {skel:BoneID(cBone), cBone}
moho.layer.ctrb[cnt]["mnm"] = nsfx
cnt = cnt + 1
end
end
--more array stuff for use later.All the angles, scale etc.
for k in ipairs(moho.layer.ctrb) do
local animAngle = moho.layer.ctrb[k][2].fAnimAngle:GetValue(0)
local animPos = moho.layer.ctrb[k][2].fAnimPos:GetValue(0)
local animScale = moho.layer.ctrb[k][2].fAnimScale:GetValue(0)
moho.layer.ctrb[k][3] = animAngle
moho.layer.ctrb[k][4] = animPos
moho.layer.ctrb[k][5] = animScale
end
end
----------------------------------------------------------------
--Control it. This does all the magic using the array built from
--the master script. This is cool.
----------------------------------------------------------------
if (moho.frame ~= 0) then
--I don't like this part. Two loops nested. It seems icky.
--and probably will slow down things with a lot of bones.
--Have to compare the master to the control arrays to match them
--up properly
if moho.layer.ctrb ~= nil then
for k in ipairs(moho.layer.ctrb) do
local cx = moho.layer.ctrb[k].mnm
local controlledbone = skel:Bone(moho.layer.ctrb[k][1])
----------------------------------------------------------------
-- For each "set" of master/control bones you need to duplicate
-- both master and control scripts and change the "mstrb" variable
-- in both scripts to match.
----------------------------------------------------------------
for i in ipairs(mstrb) do
local mx = mstrb[i].mnm
if (tostring(mx) == tostring(cx)) then
controlledbone.fAngle = moho.layer.ctrb[k][3] + mstrb[i][6]
controlledbone.fPos = moho.layer.ctrb[k][4] + mstrb[i][7]
controlledbone.fScale = moho.layer.ctrb[k][5] + mstrb[i][8]
end
end
end
end
moho:Skeleton():UpdateBoneMatrix()
end
end
Test it carefullydosamente! Cause I'm not totally sure yet what exactly consist that I have done...
Hey Ramón! I didn't see you had replied my ask. Thanks!!
Right now I can try it, but tomorrow in the morning. thanks, Ramón, it's always nice to have you back
You're welcoOome! As I said, I've only encountered this "ipairs" issue in the other scripts that I've tried to update, so I start to wonder if won't be the only syntax LUA change respect the previous AS versions... In that case, all the scripts would be relatively easy & quick to update! And that would be "stupendly" , although surely it won't be so...
Hello Sir,
I just want to ask if this script is working in AS 7. I tried loading this in AS 7 and it prompted a Lua console.
Thanks,
Gilbert L. Concepcion
heyvern wrote:These scripts have been completely changed. If you were using the old ones... your file won't work the same.
Just some small modifications will make it work again though.
I rewrote this set of scripts to allow controlling multiple bones on different layers from one master bone layer. You can download the zip file that includes a demonstration project. You may have to relink the scripts to the layers.
If you have more questions just post them here.
Here is a quick description of how it works:
Name the bones any dang thing you want. Just make sure each master and control bone have the same name and end with .mcb
rtthigh.mcb
On frame 0 assign the bone_master_v1.lua script to the master bone layer.
On frame 0 assign the bone_control_v1.lua script to any slave or controlled bone layers. As many as you want for that one master bone layer.
You can delete bones that aren't needed... BUT you must maintain the bone parenting up to the bone that needs to be controlled.
In the example the "blue" arms don't have leg bones or a head bone. But it needs the hip, torso and all the arm bones.
If you want multiple separate master/slave relationships you need to make a copy of each script and change the variable indicated in the comments... not that bad really. I would like just one set of scripts I just haven't figured it out yet.
IMPORTANT!!
The master bone layer must be below any controlled bone layer in the layer hierarchy!
Sorry about this... I couldn't figure out why this is so... and I have yet to find a solution. But for now the master bone layer must be last. It must be below any bone layers controlled by it.
It still works if it isn't but... there is a one frame "lag" updating the bones translation and rotation. This was the problem I have had since I started this... I only just figured out it had to do with layer order.
Known issues
Occassionally if you scrub really fast through the time line the script will sort of... break. If that happens or you get an error... just click on frame 0 again and everything will go back to normal.
When animating the master bone layer, the slave bone layers will not update immediately. You must click on the frame in the time line or scrub the time line to force the bones to update.
-------------------------
To make it easy, create the master bone layer first. Name all the bones just the way you want them and include .mcb at the end of each bone name that you want to control. You can leave the .mcb extension off of a bone and it won't be controlled.
For instance some kind of object in the hand of a character... that bone could be a child of the hand bone and controlled by the hand bone... but the object bone could be independantly translated and rotated.
After creating the master bone layer you can duplicate it... and put it anywhere in the layer structure you want.
You could for example put copies of a controlled bone layer inside different groups with masking to create complex masking that is still controlled by one bone layer.
Comments and suggestions are welcome. Any expert coders want to fix this thing and make it better... pleeeeeese.... I would be ever so greatful.
I have been using these scripts on almost all of my current projects... for masking... interacting characters... etc. I really like it and it saves time. You don't have to keep copying and pasting animated bone layers into different spots for layered effects.
The slaved bones can be anywhere in the layer hierarchy... anywhere... and they always work... they just have to be above the master layer of course.
For starters I will offer that I am new and while I find scripting appealing I know very little about it (but I REALLY want to learn how). I apologize in advance if any questions or ideas seem ignorant (because the likelihood that they are is VERY high).
Secondly, your video demonstrating your script, Vern, is amazing. This is a very powerful tool and I am only just beginning to imagine how it can be applied.
From what little understanding I have (which may be incorrect) your video demonstration employed the use of switch layers (the color changes indicate a change in active layer) and the bones in the switches were controlled by bones in a single master bone layer. My question is this: Is it possible for the master control bone to work in different switch perspectives (i.e. front, side, 3/4, and back).
A simplified example would be this: Picture a simple waving of a character's left hand. The camera capture of a frontal view, the left hand waving will be camera right in frame. The camera capture of the character's back while waving the left hand, however, would be camera left in frame.
Could the script (or a script) be tailored so that the master control bone layer could control the the bones in the differing camera views?