Follow Curve - maintain joint volume - layer script WIP

Moho allows users to write new tools and plugins. Discuss scripting ideas and problems here.

Moderators: Víctor Paredes, Belgarath, slowtiger

chucky
Posts: 4650
Joined: Sun Jan 28, 2007 4:24 am

Post by chucky »

Awesome, you cracked it so quickly.
We are not worthy.
So this means our shape fills can have continuous shape effects too I guess.
I have a question regarding the crease lines, are they separate line shapes?
The multiple group/path thingo is also magic Vern, congrats.8)
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

The crease line is part of the arm shape not a separate shape. It is the forearm shape overlapping the bicep. Because I "peak" the point you get a nice sharp point at the joint pivot instead of the "loop" you would normally get. My next trick will be to do the same with line width so you can "point" the stroke shape as well as peak it as the joint bends. This will be really cool for turning heads. Being able to reduce the stroke width as it turns to hide and show lines. I would think to at the point where the line width is close to 0 I could just "hide" the stroke as well but I need to play with that a bit.

As for circular "360" rotations... that will be tricky because of the "winding". A bone can have any amount of rotation even like 700 degrees... it just keeps going around and around. It doesn't go back to zero when it gets around to the other side. I would have to do tricky calculations to figure out what the percentages would be. When it gets to the top it would "jump" to the end of the other side... it is possible and you are right it probably will be needed I just need to figure out the math.

EDIT: Circular path! Of course you said it Synth. Just one circular path for the whole thing. Make the transition point at the top and bottom segments. This might require a separate modification just for joints... hmmm... that's a good idea.

-vern
User avatar
synthsin75
Posts: 10280
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Post by synthsin75 »

I'm glad that was a good idea. I wasn't at all sure since I have no real idea how you're accomplishing this. Can't wait to see the code. :D
User avatar
DK
Posts: 2896
Joined: Mon Aug 09, 2004 6:06 am
Location: Australia

Post by DK »

Just thinking....Verns script can be used to do layered eyeblinks using actions rather than switch layers. One eye open shape at the bottom layer then a closed eye shape that would consist of two points that travel along a curved vector motion path on each side of the eye to open and shut. This is fantastic as it cuts out using a switch layer altogether.

Also, it may be even possble to design a layered mouth that could cover nearly all mouth shapes.

D.K
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

I know what I did wrong here.

We definately need this to work with circular continuous rotations described by Synth. this is a MUST. I was basing movement on changes from the original rotation of the bone from frame 0. WRONG. It works fine but it's limited. What I need to do is base movement along the path on the angle between the two bones. As the angle decreases and increases that is what should drive the motion.

Uh... er... help please? I will look into this but it sounds like a math thingy which I'm not so good with.

The info I need is how to determine the angular relationship of the two bending bones. The "actual" angle not the "real" angle. Does this make sense? There must be a formula for determining the angle without taking into account say, a 895 degree rotation of one of the two bones.

-vern
User avatar
synthsin75
Posts: 10280
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Post by synthsin75 »

Just thinking out loud here, as I'm no pro with math either.

The rotation of a bone is given as radians in the parent bone's local coordinate system, right? So the rotating bone's angle is already relative to its parent bone. Sounds like all you need to do is compensate for multiples of complete circles and, perhaps, negative values.

I'm not sure what the radians would be, but maybe those can be converted in the script?

If so, then any value that is greater than a multiple of 360 degrees just needs to have 360 times that multiple subtracted from it. Say you have a rotation of 540 degrees. 540 divided by 360 equals 1 point something. So 540 minus (1 times 360) equals 180, which is the basic angle between those bones.

You should be able to substring out the integer from any decimal received.

I have no idea what that'd be in radians. :roll: :wink:
Genete
Posts: 3483
Joined: Tue Oct 17, 2006 3:27 pm
Location: España / Spain

Post by Genete »

What I need to do is base movement along the path on the angle between the two bones. As the angle decreases and increases that is what should drive the motion.
I always believed that the bone's angle is the angle between the bone and its parent so it is the angle between the two bones.
The info I need is how to determine the angular relationship of the two bending bones. The "actual" angle not the "real" angle. Does this make sense? There must be a formula for determining the angle without taking into account say, a 895 degree rotation of one of the two bones.
let's study this hierarchy:

bone1: parent
bone2: child

The angle of bone2 is the angle between bone1 and bone2. Two segments have two angles between them: Alpha and Alpha+180. Is important which of them are you using? I think it is just an offset.

Regarding to the 360:
Just convert the bone2 angle to a 360 modulus.

Code: Select all

mod_360(Alpha)
  do
    if(Alpha >180)
      Alpha = Alpha -360
    if(Alpha<-180)
      Alpha=Alpha+360
  while (Alpha >180 or Alpha <-180)
return Alpha
and use that angle for calculations
As for circular "360" rotations... that will be tricky because of the "winding". A bone can have any amount of rotation even like 700 degrees... it just keeps going around and around. It doesn't go back to zero when it gets around to the other side. I would have to do tricky calculations to figure out what the percentages would be. When it gets to the top it would "jump" to the end of the other side... it is possible and you are right it probably will be needed I just need to figure out the math.

EDIT: Circular path! Of course you said it Synth. Just one circular path for the whole thing. Make the transition point at the top and bottom segments. This might require a separate modification just for joints... hmmm... that's a good idea.
With that you probably need to calculate the resulting percentage to a 100% modulus (or better to a [0,1] range. How did you called the amount value the is used to this function?:
LM_Vector2 PointOnSegment(segID, percent)

Returns the location of a point on a segment.
Return value (LM_Vector2): a point located on the segment segID (int): a segment of the curve (starting with 0) percent (float): where on the segment to locate the point (from 0 to 1)

Code: Select all

mod_1(perc)
 do
    if(perc >1)
      perc = perc -1
    if(perc<0)
      perc=perc+1
  while (perc >1 or perc <0)
return perc
Looking to the code would allow us help you more, unless you want to keep all the glory ;)

-G
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Well, here's the code. I'm always a bit self conscious about my code. It's like taking off your clothes in front... of a pretty lady for the first time. You never want anyone to laugh. :oops:

I think the performance problems are due to the code running on frame 0 to build the table. Sometimes scrolling really fast "breaks" the table and you have to go to frame 0 again. But if the table is constantly being built from scratch on each frame it's slow.

There is variable called "doitb" that is just a test for moving a bone along the path. If you follow my previous instructions you can create a file. I'm having serious internet upload problems right now. Difficult to upload files. It is very very very slow. When I get that fixed I will upload a zip with project file and script on my site.

Code: Select all

function LayerScript(moho)
    local layer = moho.layer
	local mesh = moho:Mesh()
	local skel = moho:ParentSkeleton()
    local grpCnt = mesh:CountGroups()
	if (mesh == nil) then
		return
	end
    if(grpCnt == 0) then
        return
    end
    if (skel == nil) then
		return
	end
    local doitb = skel:Bone(0)
    if(moho.frame == 0) then
    --print("360 = "..math.rad(360))
    --print("180 = "..math.rad(180))
        layer.bpGroups = {}
        local bone
        local rBone
        local boneCount = skel:CountBones()
        for i = 0, boneCount -1 do
            local b = skel:Bone(i)
            local name = b:Name()
            local pName = string.find(name, '.path')
            if (pName) then
                pName = string.sub(name, 1, -6)
                rBone = b
                layer.bpGroups[pName] = {}
                layer.bpGroups[pName].bone = b
            end
        end
        local tmpCrv
        for i=0, grpCnt -1 do
            local group = mesh:Group(i)
            local pt = group:Point(0)
            local selSeg = pt:Curve(0, 0)
            local name = group:Name()
            local subNamePath = string.sub(name, -5)
            local subNamePoint = string.sub(name, -6)
            local reverse = string.find(name, "reverse")
            if (subNamePath == ".path") then
                local tName = string.sub(name, 1, -6)
                if(reverse) then
                    tName = string.sub(tName, 1, -9)
                    layer.bpGroups[tName].reverse = true
                    layer.bpGroups[tName].rCurve = selSeg
                else
                    layer.bpGroups[tName].reverse = false
                    layer.bpGroups[tName].curve = selSeg
                end
--                local pt = group:Point(0)
--                local selSeg = pt:Curve(0, 0)
--                layer.bpGroups[tName].curve = selSeg
            end
            if (subNamePoint == ".point") then
                --local reverse = string.find(tName, "reverse")
                local tName = string.sub(name, 1, -7)
                local mvPt = group:Point(0)
                if(reverse) then
                    tName = string.sub(tName, 1, -9)
                    layer.bpGroups[tName].rPoint = mvPt
                else
                    layer.bpGroups[tName].point = mvPt                
                end
                --local mvPt = group:Point(0)
                --local tName = string.sub(name, 1, -7)
            end
        end
    end
        ----
    if(moho.frame > 0) then
        for name in layer.bpGroups do
            local rev = layer.bpGroups[name].reverse
            local mvPt = layer.bpGroups[name].point
            local selSeg = layer.bpGroups[name].curve
            local segCnt = selSeg:CountSegments()
            local bone = layer.bpGroups[name].bone
            local rotation = (bone.fAnimAngle:GetValue(moho.frame)) / math.rad(180)
            if(rev == true) then
                if(rotation <0) then
                    mvPt = layer.bpGroups[name].rPoint
                    selSeg = layer.bpGroups[name].rCurve
                    segCnt = selSeg:CountSegments()
                    rotation = rotation * -1
                    --pt = selSeg:PointOnSegment(0, rotation*segCnt)
                end
            else
                if(rotation > 0) then
                    rotation = (bone.fAnimAngle:GetValue(moho.frame)) / math.rad(180)
                    --pt = selSeg:PointOnSegment(0, rotation*segCnt)
                end
            end
            local pt = selSeg:PointOnSegment(0, rotation*segCnt)
            local tmpCrv = 0.3 - (0.3*rotation)
            mvPt:SetCurvature(tmpCrv, 1)
            for i = 1, segCnt do
                local sp = i-1
                if(rotation > i/segCnt) then
                    pt = selSeg:PointOnSegment(i, (rotation*segCnt)-i)
                end
            end
            mvPt.fPos = pt
            doitb.fPos = pt
            skel:UpdateBoneMatrix()
        end
    end

end
-vern
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Genete, having trouble with your "Modulus" example. I get no results. Is this lua code? I had to modify it to work with lua it may be I got it wrong.

Alpha is never > 180 or <-180. Should that be Alpha >180 or Alpha < 180 or maybe < 0?

-vern
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

I think I got it. Lua has a "mod" math function.

Is this correct?

Code: Select all

math.mod(Alpha, 360)
It seems to work. It gives the angle between the two bones even if the one bone has been spun around 50 bazillion times. ;)

-vern
User avatar
synthsin75
Posts: 10280
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Post by synthsin75 »

OH MY GOD! That is just fun to play with. I kind of like how it will run off the ends of the 'path'.

There seem to be two ways that this will work right now. You can get it to have the bone you rotate follow the curve or a bone being driven by another one's rotation. The control bone following the path would let you seem to rotate it from its tip instead of its base (with the right path curve). The follow bone being controlled by another could do a nice aim effect.

Not to mention the joint volume. It's too late tonight, but I'll look at the code more carefully tomorrow.

Awesome work Vern! :D
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Thanks for the comments Synthsin. I'm glad you made it work just from the instructions. That means it isn't too hard to figure out ;).

-------

Genete, my dear dear friend and math guru, you are a genius. You make my brain work. ;) It's like you kick me in the head and the gears start to turn.

Based on your input I created this function that takes the rotation of the bone and converts it to a percentage value 0.0 to 1.0 for a 360 degree rotation. 0% (0.0) is always at the top and 100% (1.0) is always at the bottom no matter how many times the bone "spins" around. Works perfectly. This will totally solve the "spinning" joint issue.

Code: Select all

    function mod_360(Alpha)
        Alpha = math.deg(Alpha)
        local pcnt = 1/180
        if (Alpha < -180) then
            Alpha = Alpha + 360
        elseif (Alpha > 180) then
            Alpha = Alpha - 360
        end
        Alpha = math.mod(Alpha, 180)
        Alpha = Alpha * pcnt
        if (Alpha < 0) then
            Alpha = Alpha * -1
        end
        return Alpha
    end
-vern
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Dagnabbit. Spoke too soon. If I spin the bone around TWICE the top and bottom "reverse" so if I spin the bone around in the positive direction past the start to the top again when it goes past that top point it "jumps" to 0% instead of reversing down.

My thought might be you wouldn't want to spin the bone around that many times right? Dang... I'll try to fix it. ;)

-vern
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

I added in point width:

http://www.lowrestv.com/anime_studio/sc ... curve4.swf

This will need more "tricky" coding. "Point" width is not based on a relative value. The width can't be "set" as you might think. For instance in the example above the line with in the style is set to 6. To match that style the points width must be set to 6. If the stroke style is changed to 2 the point's width will be to thick.

What I need to do is get the style associated with that shape, determine the style's stroke width and then apply that to the point width. A point width also must be "set". You can't just change it by percentage unless it's been keyed. Also it must be a key frame so I will be changing it the same as the point curvature by setting a key on frame 1.

Other than that ;) it works great!

I'm so flipping out that I can get these great joints with just the regular two bones. It's so sweeeet! I can't wait to get this thing really working and try it out on a whole character.

-vern
chucky
Posts: 4650
Joined: Sun Jan 28, 2007 4:24 am

Post by chucky »

It is really cool Vern,
I have been playing with it and it is wicked.
You might want to have a look at if you get a crash from moving the path point keys.
I also had some points jumping out of frame, I am sure you will be ironing it all out , I'm definitely not being a critic.. code is beyond me. :roll:
Post Reply