i have a script request! (Poses)

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

Moderators: Víctor Paredes, Belgarath, slowtiger

PocketGoat
Posts: 45
Joined: Mon Jun 11, 2007 9:02 am

Post by PocketGoat »

Every time the script runs in each frame it starts from scratch, right? So all the stored variables are lost. How do I go about storing values between runs of the script? I see there's the ScriptPrefs class, which could do it, but it wouldn't be efficient to convert the point positions into integers to be stored by ScriptPrefs and then converted back again every run of the script.
Is there another way?
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

I think I see the problem. I separated out the spot that might be the issue. This is a snippet from the code where the points get moved:

Code: Select all

---------------------------------------------POINT MOTION
   local fc3=mesh:CountPoints()-1  -- added to speed up loops
   for i=0, fc3 do --- move the points.

---------------------------------------------
      pimoved:Set(mesh:Point(i).fPos)
---------------------------------------------

....
"fPos" is the absolute position of the point on the frame. If you set the point to be the "fPos" and change the "fPos" you are incrementing it exponentially each time around.

The "normal" script is only working on "Static" values of the poses. The current frame position values are never considered. They aren't part of the calculation. Once you add in that constantly changing value of the current point position on each frame you run into the issue of what is the "actual" value. How can you determine what the point position is really suppose to be? You would have to have a key on every frame before adding the script to the layer. Then the "fPos" value would "over ride" the key frame value but that value would be stored.

I hate to say it but I think this is impossible to accomplish. I just don't see any way to separate the position value of the key frame from the position value that the script is adding in.

I would be very happy to be proven wrong.

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

Post by heyvern »

HAHAHAHA!!!! I FIXED IT I FIXED IT!

I've decided to leave my last post up for the humorous aspect. Of course it's impossible until 30 seconds later I find the solution.

I will post the code shortly I need to test it a bit more. Very simple. Two lines one word.... ha hah hahaha! I'm in code mode again! ;)

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

Post by heyvern »

Here's the scoop...

fPos is the ABSOLUTE value. This value includes ALL motion applied to the point location.

fAnimePos is just the "animated" position defined by AS. It doesn't include "scripted" motion. Cool beans. Easy fix.

Code: Select all

--Embed this script into all the vector layers that want to copy poses from frames 1,2,3,4, ..., maxposes
--it must be under a bone type layer and the following ROOT named bones MUST exists:

-- posek (with k form 1 to maxposes)
-- bonelesector

-- Copyright 2008 Genete
-- Released for free.
-- Thanks to Selgin for that great idea.
-- It can be extended for other animated values (curvatures, widths, shape fill colors, shape outline color, etc.)
-- (curvature done!)
-- Also weights w[k] can be overweigthed by the pose bone legth. It would allow some sort of variable action weights...
-- Under development...
-- Modififed June 5th, 2008:
-- Tim Fischer:  Added local variables to speed up looping (interpreted languages recalculate every iteration so a variable can be much faster)
-- Added garbage collection routine to free memory (Auto GC doesn't appear to work).  This fixes hanging, etc

--Genete 2008 july, 27th
---I've added some testing to speed up the positioning on the poses. You can edit the poses freely staying at its own frame but
---if you modify a pose then you have to go to frame 0 to store the modifications on the pose array. Frame 0 is slow!!!
---Now the pose bone legth has influence on the final weight of the poses. So you can control the interpolated pose with the poses lengths.
---Added the Curvature channel. Now the curvature is stored and is interpolated between poses. It produces automatically a keyframe on each frame
---There is NO WAY to solve this because the curvature channel has not a fCurvature variable to set like the one for the points.
---Added the functionality of an external variable: GE_ToggleKeyframePoses.Status
---You have to run the ge_toggle_keyframe_poses.lua script by the menu or button script to modify the variable Status form false (default value)
---to True and viceversa. When this variable is set to true the inrterpolated point motion is stored in a keyframe. This is useful to
---store all the animation in its own keyframes and be able to remove the embedde scripts. Also useful when used on single frames to key all the
---point motions for all layers where the script is embedded.
---Added the ability to avoid interpolate or set again an existing keyframe. This allows the user to insert a keyframe in any moment of the
---interpolation and manually modify the interpolated values. This solves the situation where the interpolated poses produces a bad value
---difficult to solve by modifying the poses thenselves.

---Added interpolation for style shape fill and line color. I've tried Line Widht but it seems not to work.

--PocketGoat 2009, 15th May.
--Added ability to use other types of animation in conjunction with poses.


--Heyvern 2009, 14th May? (Hey PocketGoat... how are you a day ahead of me?
--Small teeny tiny miniscule edit to fix PocketGoat's revision. Lines 177-179

poses = {}

maxposes = 4

bone = {}
boneselector = nil

function LayerScript(moho)
   local w = {}
   local distance
   local posk
   local pos_selector
   local r
   local length

   local k,i,l
   local layer = moho.layer
   local frame = moho.frame
   local pimoved =LM.Vector2:new_local()
   local pi

   local skel = moho:ParentSkeleton()
   if (skel == nil) then
      print ("No parent skeleton found in layer:".. layer:Name())
      return
   end

   local mesh = moho:Mesh()
   
   if (mesh==nil) then
      print ("No mesh found in layer:".. layer:Name())
      return
   end   
   if (frame <=maxposes and frame > 0) then return end
   if (frame <= maxposes or boneselector == nil) then
-----------------------------------look for the bones
      for k=2, maxposes do
         bone[k] = nil
         local fc1 = skel:CountBones()-1   -- added to speed up loops
         for i=0, fc1 do
            local bonei = skel:Bone(i)
            local bonek = "pose" .. tostring(k)
            if (bonei:Name() == bonek) then
               bone[k]=bonei
            elseif (bonei:Name() == "boneselector") then
               boneselector=bonei
            end
         end   
         if (bone[k] == nil) then
            print("bone "..k.." is missing")
            return
         end
      end
      if boneselector == nil then
         print("boneselector is missing")
         return
      end
---------------------------------
--------------------------------- creates a new array for the layer
      poses[layer]={}
      poses[layer]["points"]={} -- this is the array for the point motion
      for k=1, maxposes do
         poses[layer]["points"][k]={}
         local fc2 = mesh:CountPoints()-1   -- added to speed up loops
       if k == 1 then
         for i=0, fc2 do
            poses[layer]["points"][k][i]=mesh:Point(i).fAnimPos:GetValue(k) --store all the points/pose/positions for neutral layer 1
         end
       else
         for i=0, fc2 do
            poses[layer]["points"][k][i]=mesh:Point(i).fAnimPos:GetValue(k) - poses[layer]["points"][1][i] --store point differences for other layers
         end
       end
         collectgarbage(fc2)
      end
      poses[layer]["curvature"]={} -- this is the array for the curvatures
      for k=2, maxposes do
         poses[layer]["curvature"][k]={}
         local fc3 = mesh:CountCurves()-1
         for i=0, fc3 do
            poses[layer]["curvature"][k][i]={}
            local curvei = mesh:Curve(i)
            local fc4 = curvei:CountPoints()-1
            for l=0, fc4 do
               poses[layer]["curvature"][k][i][l]=curvei:GetCurvature(l,k)--store all the point of curves/pose /curvature
            end
            collectgarbage(fc4)
         end
         collectgarbage(fc3)
      end
      poses[layer]["fillcolor"]={}
      poses[layer]["linecolor"]={}
      poses[layer]["linewidth"]={}
      for k=2, maxposes do
         poses[layer]["fillcolor"][k]={}
         poses[layer]["linecolor"][k]={}
         poses[layer]["linewidth"][k]={}
         
         local fc5=mesh:CountShapes()-1
         for i=0, fc5 do
            local shapei=mesh:Shape(i)
            poses[layer]["fillcolor"][k][i]=shapei.fMyStyle.fFillCol:GetValue(k)
            poses[layer]["linecolor"][k][i]=shapei.fMyStyle.fLineCol:GetValue(k)
            poses[layer]["linewidth"][k][i]=shapei.fMyStyle.fLineWidth
         end
      end
     
      return
   end -- end of frame < maxposes or boneselector == nil
   
   pos_selector = boneselector.fPos --position of the selector bone.   
--   length = boneselector.fLength*boneselector.fAnimScale:GetValue(moho.frame) --current length of the boneselector
   length = boneselector.fLength*boneselector.fScale --current length of the boneselector

-- Calculate the distance form the boneselector to all the pose bones and calculate its "weight" influence
   for k=2, maxposes do
      w[k]=0
      posk = bone[k].fPos
      distance = posk - pos_selector
      r = distance:Mag()
      w[k]=weight(r, length)*bone[k].fScale --***THE SCALE OF THE POSE BONE CREATE INFLUENCE ON THE POSE!***
   end
   
   local wtot=0.0 --total weight initially = 0.0
   for k=2, maxposes do
      wtot =wtot +w[k]
   end
   if (wtot == 0.0) then  return  end
   for k=2, maxposes do
      w[k]=w[k]/wtot -- normalize the weights.
   end
   
---------------------------------------------POINT MOTION
   local fc3=mesh:CountPoints()-1  -- added to speed up loops
   for i=0, fc3 do --- move the points.
--      pimoved:Set(mesh:Point(i).fPos) -- heyvern edit- I removed this. Wrong thing (fPos) and in the wrong spot
      pi= mesh:Point(i)
      --- heyvern edit - I changed this to fAnimPos. This is ANIMATED position... not the "real" position defined by fPos
      pimoved=pi.fAnimPos:GetValue(frame)
      ---if (pi.fAnimPos:HasKey(frame)) then break end -- if there is a keyframe then don't overrride it. Not needed anymore.
      for k=2, maxposes do
         pimoved = pimoved + (poses[layer]["points"][k][i]*w[k])/2
      end
      if(GE_ToggleKeyframePoses.Status==false) then
         mesh:Point(i).fPos:Set(pimoved) --move the point
      else
         pi.fAnimPos.value=pimoved -- move the point
         pi.fAnimPos:StoreValue()--this produces a keyframe and stores its valule
         moho.document:SetDirty()
      end
   end
---------------------------------------------END POINT MOTION   
---------------------------------------------CURVATURE
   fc3 = mesh:CountCurves()-1
   for i=0, fc3 do
      local curvei = mesh:Curve(i)
      local fc4 = curvei:CountPoints()-1
      for l=0, fc4 do
         local currentcurvature = 0.0
         for k=2, maxposes do
            currentcurvature=currentcurvature + poses[layer]["curvature"][k][i][l]*w[k]
            curvei:SetCurvature(l,currentcurvature,frame)
         end
      end
   end

---------------------------------------------END CURVATURE
---------------------------------------------STYLE

   fc3 = mesh:CountShapes()-1
   for i=0, fc3 do
      local shapei = mesh:Shape(i)
         local currentfillcol = LM.ColorVector:new_local()
         local currentlinecol = LM.ColorVector:new_local()
         local currentlinewidth = 0.0
         currentfillcol:Set(0.0,0.0,0.0)
         currentlinecol:Set(0.0,0.0,0.0)
         for k=2, maxposes do
            currentfillcol=currentfillcol+poses[layer]["fillcolor"][k][i]*w[k]
            currentlinecol=currentlinecol+poses[layer]["linecolor"][k][i]*w[k]
            currentlinewidth=currentlinewidth+poses[layer]["linewidth"][k][i]*w[k]
            --if(shapei.fMyStyle.fDefineFillCol) then
             shapei.fMyStyle.fFillCol:SetValue(frame,currentfillcol) --end
            --if(shapei.fMyStyle.fDefineLinecol) then
            shapei.fMyStyle.fLineCol:SetValue(frame,currentlinecol) --end
            --if(shapei.fMyStyle.fDefineLineWidth) then
            shapei.fMyStyle.fLineWidth=currentlinewidth --end
         end
   end
--------------------------------------------- END STYLE


   collectgarbage (fc3)

end ---FUNCTION END


function weight (r, l)
   if (r <= l) then
   local w =1-r/l
      return w
   else
      return 0.0
   end
end 
-vern
User avatar
Víctor Paredes
Site Admin
Posts: 5815
Joined: Wed Jan 26, 2005 12:18 am
Location: Barcelona/Chile
Contact:

Post by Víctor Paredes »

In vern we trust.

edit: wow!, the code is already uploaded, let's play!
PocketGoat
Posts: 45
Joined: Mon Jun 11, 2007 9:02 am

Post by PocketGoat »

I'm ahead of you because I'm in New Zealand. It's currently 4:14 pm on the 15th of May. I wrote it after midnight last night, hence 15th May :P
Thanks for fixing that. Now I just have to fix the problem with storing the difference between points. Need to dust off my high school trignometry skills.
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

I was wrong.

My fix doesn't seem to work correctly.


-vern
PocketGoat
Posts: 45
Joined: Mon Jun 11, 2007 9:02 am

Post by PocketGoat »

Hmm. Something else is going wrong now. It's ignoring other bone's influence.

Back to the drawing board.
User avatar
Víctor Paredes
Site Admin
Posts: 5815
Joined: Wed Jan 26, 2005 12:18 am
Location: Barcelona/Chile
Contact:

Post by Víctor Paredes »

It jumps from one position to a new distortioned one. I tested it in my spaceship and didn't work well.
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Hah! Another break through.

The reason it doesn't work correctly using "fAnimPos".... is... because... think about it... wait for it... you see the problem?

Hah! It's using the LAST POSE! When you add keys it's based on the last pose.... D'oh! I need to change the code to get the point positions from FRAME 0 not the current frame.

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

Post by heyvern »

There's another problem... the keys for the poses.

This is why the points won't move correctly. No matter what you do those keys for the poses have an adverse effect. Keying points keys relative the last key frame which is always the last pose.

I'm going to try making the last pose an "extra" pose that is identical to frame 0.

-vern
PocketGoat
Posts: 45
Joined: Mon Jun 11, 2007 9:02 am

Post by PocketGoat »

I'm working on my own solution. We'll see who gets there first :P
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Just so you know there was a change you made in Genete's latest version.

You changed the max pose variable loop in some spots from:

Code: Select all

for k=1, maxposes do
to:

Code: Select all

for k=2, maxposes do
All I did was to add the other minor changes you made in the "move points" section in the original script and it works "better". Keying points on the vector layer worked almost as expected. Those changes you made to the loop seemed to be for something else you planned to do? Anyway it messed things up.

It still isn't right though. The point motion is still "expanded" on the frame. Apparently there is a "double" hit on the motion of the fAnimPos. I think I need to subtract one of those values.

-vern
PocketGoat
Posts: 45
Joined: Mon Jun 11, 2007 9:02 am

Post by PocketGoat »

I did that to ignore frame one except as a comparison as the neutral pose. If you wanted to include it as a normal pose you'd need to make another variable and store the neutral pose in there instead of with all the others. It was more work than just cutting it out.
Heh, if it's doing something else clearly I'm confused as to how the loops were working.
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

This is the only change I made to Genete's original script. If you replace this in Genete's original script it works pretty well. However there is still that bizarre weird shifting of the points when you move them on a frame. It's difficult to do precise edits. I don't know exactly what is causing this.

Code: Select all

---------------------------------------------POINT MOTION
   local fc3=mesh:CountPoints()-1  -- added to speed up loops
   for i=0, fc3 do --- move the points.
      pimoved:Set(0,0)
      pi= mesh:Point(i)

      ---------------- Begin HV Change
      pimoved=pi.fAnimPos:GetValue(frame)
      pimoved=pimoved-pi.fAnimPos:GetValue(0)

      --if (pi.fAnimPos:HasKey(frame)) then break end -- if there is a keyframe then don't overrride it.
      ---------------- End HV Change

      for k=1, maxposes do
         pimoved = pimoved + poses[layer]["points"][k][i]*w[k]
      end
      if(GE_ToggleKeyframePoses.Status==false) then
         mesh:Point(i).fPos:Set(pimoved) --move the point
      else
         pi.fAnimPos.value=pimoved -- move the point
         pi.fAnimPos:StoreValue()--this produces a keyframe and stores its valule
         moho.document:SetDirty()
      end
   end
---------------------------------------------END POINT MOTION   

Post Reply