Page 1 of 3

Can ASP control a switch, based on its bone angle?

Posted: Mon Apr 20, 2009 3:18 am
by ruibjr
The reason I ask this is because it would make things much easier to animate, if one could setup a set of switch options for, say, the lower arm and let ASP decide which option to select, based on the angle.

Animating arms and legs would be so much easier then.
One could simply draw a set of lower arms and let ASP select the one that looks better for that specific angle range (say, 20 to 25 degress, etc...).

If there is no such thing, can it be done in Lua scripting?

Cheers,

Rui

Posted: Mon Apr 20, 2009 4:32 am
by synthsin75
Check out our discussion of this in this thread:
viewtopic.php?t=12376

It is possible with scripting, but the few of us who do script for AS all seem to have huge lists of things we're wanting to script. Check out that thread for at least one alternate solution for this.

:wink:

Posted: Mon Apr 20, 2009 8:26 am
by heyvern
I have a test version that "works". I can't figure out how to make rotation "ranges" on the bone to match the switches though. It works.. .but... not accurately. You almost have to type in exact rotations of the bone which kind of defeats the purpose of "making it easier" than right clicking the switch.

What happens is that the bone over rotates depending on the space between keys... over shoots the "range" marker and "skips" a switch layer. It might work better with "Step" keys but... once again that adds more work to the process and it should work with any type of key dagnabbit.

I've had to put a lot of my scripts "on hold" for the moment for various reasons.

-vern

Posted: Mon Apr 20, 2009 2:44 pm
by ruibjr
Thanks for the replies guys.

I took a look at the selection script and it looks really good.

I wonder if these would be the steps to modify it:

1. Get the bone itself, not an external control bone, to make make the decisions;
2. Get the angle relative to the parent bone;
3. Divide the angle by, say, 20, resulting in up to 18 positions for a complete 360 degrees rotation;
4. Acivate the switch option that was computed by the division above;

I see a few problems here:

1. Can we select switch option via script?
Yes, Vern was able to do it.
2. How would we define the starting and ending angles?
The interface doesn't seem to provide a place for inputing that kind of data.
The alternative would be that the switch would have to implement all 18 options, despite some of them would be empty or replicated.

I am just thinking about it.
And I see that it would be very difficult to do, specily the part where we can not specify the angle ranges.

Hm... I wonder if there are plans to implement this in a forthcoming version of ASP?

P.S.: The angle range could be limited to, say, 120 degrees, with a 15 degrees precision, resulting in 8 options for the switch, instead of 18.

Posted: Mon Apr 20, 2009 7:25 pm
by heyvern
In my script I divided "360" by the number of layers in the switch. The main issue is radians. AS uses radians not degrees internally so the code is not... simple. It's been a while since I looked at that script but I think I made the performace sacrifice and just converted the angles in lua to degrees.

The next step was when to "switch" the layer. You have to switch when the angle is "within" that range. Because each switch can have any number of layers the angle range can be... anything. The code has to check if the angle is above one value AND below another value.

Another problem is when the bone rotatates through those ranges. There was no way to "skip over" other switches. The bone rotated through all of them causing all the switches to be selected as it moved back and forth.

I then wanted to try and script a "lock" on the bone rotation. So the bone could not rotate at all and would "snap" only to those angles defined by the number of switch layers....

...

After a while I just got bored with the whole thing and set switches by hand. ;)

-vern

Posted: Mon Apr 20, 2009 10:01 pm
by ruibjr
Hm. Dividing the 360 degrees by the number of options was was very clever.
By doing that you don't need to store the extra information.

Animation would make so much more sense if we had that tool.

I mean, we could easily create the animations 100% hand-drawn, if we wanted to. And, still, we would be able to use the bones appproach for actualy using them.

I am not complaining - I love ASP, so far.
But that tool alone, would make me feel much more comfortable about what can be done and what has to be done.

Cheers,

Rui

Posted: Mon Apr 20, 2009 10:07 pm
by synthsin75
I've been thinking lately that many of our layer scripts would actually be more useful, performance-wise, as tools. Granted as tools you'd have to delete keyframes manually, but the performance of an OnMouseUp beats the hell out of running three times per frame.

So this would be a rotate bone tool that checks the bone's name (for an extension). OnMouseUp it would do as your layer script does. Divide the degrees by the number of layers in a specifically named switch layer.

This is just off the top of my head, so there may be issues I haven't imagined.

:wink:

p.s. Perhaps it could even delete keys on the switch from frames that have no key on the bone.

Posted: Mon Apr 20, 2009 10:15 pm
by Genete
heyvern wrote:I have a test version that "works". I can't figure out how to make rotation "ranges" on the bone to match the switches though. It works.. .but... not accurately. You almost have to type in exact rotations of the bone which kind of defeats the purpose of "making it easier" than right clicking the switch.

What happens is that the bone over rotates depending on the space between keys... over shoots the "range" marker and "skips" a switch layer. It might work better with "Step" keys but... once again that adds more work to the process and it should work with any type of key dagnabbit.

I've had to put a lot of my scripts "on hold" for the moment for various reasons.

-vern
Vern,
can I have a copy of your test version? Maybe I can fix the "radian problem" and add some of the features that have been commented here.
Cheers
-G

Posted: Mon Apr 20, 2009 10:24 pm
by ruibjr
Yes. That would be sweeeet.

One would be able to rotate the bone and as he/she did it, it would be possible to see the different results.
That is, the drawing (shape) would change as we rotate the angle.

Animations could be done on a frame-by-frame basis, hand-drawn, if we wanted to.
But we would still use bones to animate the characters.

Posted: Mon Apr 20, 2009 11:40 pm
by heyvern
Here it is...

http://www.lowrestv.com/anime_studio/sc ... -scrpt.zip

It was created a long time ago as you will note by the extension (.moho) but I think I played with it recently. The script is useless for much except testing. It works on one bone (bone 0) and one switch layer. I've included the test file.

It adds and removes key frames from the switch layer based on the rotation of the bone and the bones keys. That much works well. If you move the bone keys and play or rescrub the time line it will remove and add the new keys. This means you don't need the script after the switch has been keyed. Those keys are still in the switch layer. Just like the "slave switch" scripts.

-vern

Posted: Tue Apr 21, 2009 1:16 am
by ruibjr
Thanks a lot, Vern.

I really appreciated it.

I looked into the script and made this small change:

Right after:

keySwitch = crtlBone.fAngle

I have added this:

keySwitch = math.mod(keySwitch, math.rad(360))
if (keySwitch < 0) then
keySwitch = keySwitch + math.rad(360)
end

So that no matter how many complete loops around the bone's pivot, the angle is alwas right (0 to 2 PI radians).

I loved your scrit and am hoping to be able to make it work the way I expect.
Unfortunalely, I am not used to the moho API, so it may tke a looong time before I can actualy adapt t to my needs.

Thanks again.

Thanks, again...

Posted: Tue Apr 21, 2009 4:01 am
by heyvern
No need to do much work on it.

If I can get past that rotation "range" issue (with Genete's help) I will gladly make it better. Right now it is a teeny tiny test script with no options.

-vern

Posted: Tue Apr 21, 2009 3:06 pm
by ruibjr
I think I managed to fix the range problem.
Here is the modified version:

Code: Select all

function LayerScript(moho)

    local layer = moho.layer
    if ( not layer:IsBoneType() ) then
        return
    end
    
    local group = moho:LayerAsGroup(layer)
    local layerCount = group:CountLayers()
    if ( layerCount == 0 ) then
        return
    end
    local skel = moho:Skeleton()
    local boneCount = skel:CountBones()
    if ( boneCount == 0) then
        return
    end
    local ctrlLayer = nil
    local crtlBone = skel:Bone(0)
    local keySwitch = nil 
    local Lcount = nil
    local SWunits = nil
    local keySwitch = nil
    local tUnit = math.rad(360)
    local bob = {}
    if ( moho.frame > 0 ) then
        local subSwitch = nil   

        if ( crtlBone.fAnimAngle:HasKey(moho.frame) ) then
            keySwitch = crtlBone.fAngle * 10000 -- for using INT math
            keySwitch = math.mod(keySwitch, 62831) -- locks to 0-360
            if (keySwitch < 0) then -- If negative, add one complete lap
                keySwitch = keySwitch + 62831
            end
            keySwitch = keySwitch / 10000  -- back to floating point
            keySwitch = keySwitch + tUnit -- Make it 360 to 720
-- 360 to 720 to make sure it is always progressive,
-- otherwise, we would have to check the lst select differently
        end
        
        for i = 0, layerCount - 1 do
            local testlayer = group:Layer(i)                
            if (testlayer:LayerType() == MOHO.LT_SWITCH) then
                group2 = moho:LayerAsGroup(testlayer)
                subSwitch = moho:LayerAsSwitch(testlayer)
                Lcount = group2:CountLayers()
                SWunits = tUnit / (Lcount)
--                SWunits = math.rad(360)/Lcount
            end
        end
        --[[
        print(math.rad(60))
        print(math.rad(120))
        print(math.rad(180))
        print(math.rad(240))
        print(tUnit/6)
        print(math.deg(1))
        print("----------")
        --]]
--[[
L=360/N (converted to radians of course). L is an angle value

x0 = x0 + 0*SWunits
x1 = x0 + 1*SWunits
x2 = x0 + 2*SWunits
--]]

        for b = 0, Lcount - 1 do
--        print(b-1)
            local swLayers = group2:Layer(b)
            local SWname = swLayers:Name()
            local swUnit = tUnit + (b * SWunits)  -- tUnit, to make it 360-720
            local swUnitB = swUnit + SWunits
            if ( keySwitch ~= nil) then
                if (keySwitch <= swUnitB and keySwitch >= swUnit) then
                    subSwitch:SwitchValues():SetValue(moho.frame, SWname)
--                    print(SWname)
--                    print(math.deg(swUnitB))
--        moho:Skeleton():UpdateBoneMatrix()
                end
            elseif ( keySwitch == nil) then
                    subSwitch:SwitchValues():DeleteKey(moho.frame)
--        moho:Skeleton():UpdateBoneMatrix()
            end
        end
    end
end	
	

It looks like it works every tme.
I will test it some more and, if it does woe]rk fine, then I am going to start using it right away.

Thanks so much for your valuable help.

Posted: Tue Apr 21, 2009 3:36 pm
by ruibjr
Almost there.
The things missing are:

1. As it is, it always uses bone 0 as the control bone;
2. The switched shape does not rotate with the control bone.

Posted: Tue Apr 21, 2009 3:54 pm
by Genete

Code: Select all

function LayerScript(moho)
    local layer = moho.layer
    if ( not layer:IsBoneType() ) then
        return
    end
    local group = moho:LayerAsGroup(layer)
    local layerCount = group:CountLayers()
    if ( layerCount == 0 ) then
        return
    end
    local skel = moho:Skeleton()
    local boneCount = skel:CountBones()
    if ( boneCount == 0) then
        return
    end
    local ctrlLayer = nil
    local crtlBone = skel:Bone(0)
    local keySwitch = nil
    local group2 = nil
    local Lcount = nil
    local SWunits = nil
    local keySwitch = nil
    local tUnit = math.rad(360)
    local bob = {}

    if ( moho.frame > 0 ) then
        local subSwitch = nil
        if ( crtlBone.fAnimAngle:HasKey(moho.frame) ) then
            keySwitch = math.mod(crtlBone.fAngle,tUnit)
        end

        for i = 0, layerCount - 1 do
            local testlayer = group:Layer(i)
            if (testlayer:LayerType() == MOHO.LT_SWITCH) then
                group2 = moho:LayerAsGroup(testlayer)
                subSwitch = moho:LayerAsSwitch(testlayer)
                Lcount = group2:CountLayers()
                SWunits = tUnit / Lcount
            end
        end

        for b = 0, Lcount-1 do
            local swLayers = group2:Layer(b)
            local SWname = swLayers:Name()
            local swUnit = b * SWunits
            local swUnitB = swUnit + SWunits
            if ( keySwitch ~= nil) then
                if (keySwitch <= swUnitB and keySwitch >= swUnit) then
                   subSwitch:SwitchValues():SetValue(moho.frame, SWname)
                end
            elseif ( keySwitch == nil) then
                  subSwitch:SwitchValues():DeleteKey(moho.frame)
            end
        end
    end
end
This is a cleaned version that uses math.mod

Code: Select all

keySwitch = math.mod(crtlBone.fAngle,tUnit) 
Also I've fixed a problem that makes not appear the switch layer number one.

Code: Select all

local swUnit = b * SWunits
local swUnitB = swUnit + SWunits
The usage of any other bone than number 0 as controller one is pending.

-G