Control z depth of a layer with bone translation?

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

Moderators: Víctor Paredes, Belgarath, slowtiger

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

Post by heyvern »

Seems to be a bug in AS.

If I render to a movie file of any type the script doesn't work. If I render to an image sequence or do a preview animation (F5) it works fine. It seems to only happen with my "big bones" files.

http://www.lowrestv.com/moho_stuff/z-depth-bones.mov

It isn't a fantastic sample but the darn thing works! the ears are controlled by bones that swap their z-depth when they pass the center point.

-vern
User avatar
Rasheed
Posts: 2008
Joined: Tue May 17, 2005 8:30 am
Location: The Netherlands

Post by Rasheed »

I have optimized the script a bit further, and have included a new feature. If you make a layer called "Lear" a child of the bone layer, the bones called "Lear.flip1" and "Lear.flip2" form left and right boundaries for the bone called "Lear.now". The script automatically "knows" if the flip1 and flip2 bones are in the wrong position, and mirrors their positions internally. The bounderies can be moved during animation.

The now, flip, flip1 and flip2 bones should all be root bones. If it is necessary to use child bones, ask me, and I will change the script accordingly. However, because because you can easily put a constraint on the root bones from some child bone to control their horizontal positions, I didn't incorporate it.

"Lear.flip" and "Lear.now" will still work, and if both "Lear.flip" and the combination "Lear.flip1" and "Lear.flip2" are present, "Lear.flip" is used and the other two are ignored.

If you want to see what you are doing, I suggest you temporary turn on onion skinning in frame zero. This should render the current frame correctly, plus the onion skinning of frame zero.

Note that this script is supposed to be embedded while in frame zero, so the layer translation of the dynamically controlled layer can be read before it is dynamically controlled in the rest of the animation.

Download: FlipByBones.zip

Tell me if this works and if the new feature of left and right boundaries is useful.

BTW Vern, that animation looks pretty good, although the ears should be modified during the animation to reflect foreshortening. I'm sure you knew that already, and only wanted to test the script with some rough animation.
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Yeeehaaa!

If I start my renders on frame 0 it works fine.

Could this be a problem in the script? For some reason rendering to a movie with out starting on frame 0 causes the first frame layer z-depth to be "reversed" so it does the opposite of what it should.

I have a layer that is above everything but on frame 1 the bone that "lowers" it is on the opposite side. So This is how I swap the ear layers.

So, when I do a movie render starting on frame 1 it reads the value from frame 0 without applying the script to it. So that ear layer stays on top when it should be down.

Rasheed? Do you think there is a way to avoid all the keys? I tried and realized it is... like a puzzle. What I really want is just a key when the bones pass. But... since it only checks for the less than value it wouldn't key when it goes the other way. I ended up with keys on only one direction for each ear. Maybe some way to toggle the value? Create an extra field in the table of bones that indicates direction. When the direction changes a key is placed.

By the way... this is the holy grail for me. Bone controlled layer ordering???!!!! This is way cool. Imagine arms, and legs... not having to turn off duplicate layers anymore!!! Holy cow. If only you could raise a layer from inside a group to outside a group. That's the thing that doesn't work with depth ordering as far as I can tell.

This is going to work great with my face rig. I can put side hair shapes on different layers for a farther turn.

-vern
User avatar
Rasheed
Posts: 2008
Joined: Tue May 17, 2005 8:30 am
Location: The Netherlands

Post by Rasheed »

Yes, I know this is a problem. The z coordinate of the controlled layer is read from frame zero. What you really want is that when a bone crosses a boundary, it puts the layer to the back, or front, by changing the sign of the z coordinate.

The problem is that I don't know how to read a bone translation from a different frame, unless it has a key in it. There is a bone.fAnimPos:GetValue(when) to get the bone position value of a key, but if there is no key available, you cannot directly read the position of a bone, other than in the current frame. However, what you actually want to know is the position of the bone in the previous frame.

I could be recording the positions of all frames that the script encounters, but that would force the animator to go through those frames before (s)he does something in the frame where the layer ordering should change. That is a very unlikely scenario.

I guess I could investigate the possibility of estimating the bone position from the known positions of the bone in other frames, by searching for the nearest frame with a key before and after the current frame. The problem is that LM hasn't described how key interpolation works (what formulas are used), so I should have to reverse engineer that. Of course, for linear interpolation, there is no problem, but for easing interpolation (which we both know isn't very useful) it is a kind of a "black box".

If you don't mind only using linear interpolation, I can create a fix without going through the painful process of reverse engineering all possible key interpolation modes.
User avatar
Rasheed
Posts: 2008
Joined: Tue May 17, 2005 8:30 am
Location: The Netherlands

Post by Rasheed »

BTW, according to LM (see here) the key interpolation mode can't be read, only written. This means there is no direct way to know the interpolation mode. You can only infer the interpolation mode between two keys. If it's linear, for example, the ratio of the distance between the current position and the previous position in a previous keyed frame and the distance between the current position the next position in a next keyed frame should be about equal to the ratio between the number of frames between the current frame and the previous keyed frame, and the number of frames between the current frame and the next keyed frame. Of course, if the current frame has a key in it, you're out of luck, because you have no ratio to compare.

I hope that this omission of not being able to read the interpolation mode, nor the momentary bone position, angle and scale of an arbitrary frame, will be fixed in the next update.

I hope that someone will point me to another solution. (hint, hint, Ramòn)
User avatar
J. Baker
Posts: 1086
Joined: Wed Mar 23, 2005 7:22 pm
Location: USA
Contact:

Post by J. Baker »

Rasheed wrote:You need to embed the script in the bone layer (check Embed script file in the General tab of the bone layer, and select the FlipByBones.lua file in the file dialogue box that appears). Next, you need to turn on Depth Sorting in this bone layer (Depth Sort tab of the layer properties). To be sure, in the Project Setting, check Enable 3D camera and Sort layers by depth.
Yeah did all that but went ahead and tried it again. Still doesn't do anything for me. Thanks anyway.
User avatar
Rasheed
Posts: 2008
Joined: Tue May 17, 2005 8:30 am
Location: The Netherlands

Post by Rasheed »

Well, you have to name your bones properly. If the vector layer you want to control is called "ear", there should be two bones in the parent bone layer, called "ear.now" and "ear.flip".

Furthermore, you need to translate layer "ear" in the Z direction, using the Translate Layer tool. That is a lot of preparation, I know. It is still an experimental script.
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

EDIT:

J. Baker,
Make sure you have Sort Layers by Depth turned on in the bone layer properties under Depth Sort. Rasheed's sample project doesn't have this turned on by default. And don't check Sort by true distance. I have no idea what that does anyway except mess up my stuff. ;)


-------------
Rasheed this is great!

I haven't finished playing with the new version completely yet but I am excited.

Using root bones is fine for now. I can use constraints (already have) to handle movement. The only time this may cause trouble is when parenting changes translation orientation.

A bone that has a parent constrained to a bone that doesn't have a parent, or is a second level child to one with one parent will "swap" the x and y translation. This is weird and possibly a bug.

My face rig is okay because all my controls are root bones and that is what I constrain my z-depth bones to. A workaround to this issue that I use requires one or two extra bones to "reverse" the "reversal" of the translation.

I have bunches of those translation constraint "reversal" bones in my rig. Pain in the arse but it does the trick. ;) (and rotating the bone doesn't help.)

p.s. Yes, I did nothing to the ears... just wanted to see if it worked. Once the ears are "adjusted" that "pop" should practically vanish.

-vern
User avatar
Rasheed
Posts: 2008
Joined: Tue May 17, 2005 8:30 am
Location: The Netherlands

Post by Rasheed »

Well, here is the hugely improved layer script, which only puts keys in frame one, and in frames where a boundary is crossed. I think this is exactly what you wanted me to create.

Because it is such a radical change in the script, I have created a second zip archive: FlipByBones2.zip


Here is the description:

FlipByBones.lua

This script should be embedded inside a bone type layer. The bone layer should contain pairs or triplets of root bones. Each bone in such a bone pair or triplet should have the same name as one of the child layers, with either ".now", ".flip" (for a pair), ".flip1" (for a triplet), or "flip2" (for a triplet) as suffices (without the quotes). These bones should not be attached to any layer.

The dynamically controlled layer (controlled by the bone pair or bone triplet) should be offset in the z direction by layer translation in frame zero. This layer translation is copied to frame one. In all other frames, if the bone.now is left of bone.flip, the z coordinate of the layer "bone" is inverted (negative value become positive, and vice versa). Or, in case of a triplet, if bone.now is not horizontally between bone.flip1 and bone.flip2, the z coordinate of the layer "bone" is inverted.

The script will add Layer Translations keys with step interpolation to the dynamically controlled layers (in the example just layer "bone", but more controlled layers is also a possibility).

Don't forget to turn on "Depth Sorting" in the bone layer ("Depth Sort" tab of the layer properties), and, in the Project Settings, check "Enable 3D camera" and "Sort layers by depth".

The script assumes that all bone position keys in the bone layer have a linear key interpolations. If you use any other type of interpolation, the result may be unpredictable.

Have fun!
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

I wish I could do more to show my gratitude for these scripts over the last few weeks. Could I wash your car? Walk your dog? ;)

Wonderful stuff! Amazing stuff. Layer ordering with BONES! I still can't believe it.

Pretty soon there won't be anything I can't do from a bone layer. That would be the true holy grail. ;)

Oh! WOW! And that utilities script trick! That is really sweat! I plan to study that more. I really think that could be AMAZING if it could be expanded onto other scripts. Being able to access multiple scripts for a layer is incredibly powerful.

Wouldn't it be an awful shame if e-frontier put all these things in the next version? All that work wasted... ;) (I'm kidding of course).

-vern
Genete
Posts: 3483
Joined: Tue Oct 17, 2006 3:27 pm
Location: España / Spain

Post by Genete »

I haven't tested yet but this thread must be added to favourites...
User avatar
Rasheed
Posts: 2008
Joined: Tue May 17, 2005 8:30 am
Location: The Netherlands

Post by Rasheed »

I rather wait a little and write a new thread. The scripts aren't finished yet. They have to be optimized, described, and, yes, tested thoroughly by other users. Also, this thread and the thread about the real position of a child bone are too messy to be of much use for the occasional visitor of the Scripting forum. I think it may take some time before I write this thread. Writing code that works is not too difficult, writing code that is optimal is more difficult, but writing code that can be easily modified (and that should be the goal of any programmer nowadays) is a major effort.

I'm now thinking about creating a working and useful bone copy-and-paste tool. Is it possible to create a duplicate of a bone without the program crashing on you? It will also be a good exercise for me in tool script writing. I always was a bit daunted by that UI stuff in the Scripting Tutorial. Now I only have to role up my sleeves and start working on it.
User avatar
heyvern
Posts: 7042
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

There's a pretty good copy/paste bone script that I've been using for a while.

The only big trouble with it is that it doesn't copy constraints. This is probably an obvious problem due to the fact that constraints are based on bone IDs. Hard to paste back constraints for bones that don't exist yet.

It also is impossible to change some options at the bottom of the interface if the bone list is large.

I forget off hand who wrote it but here is the link to it on my site:

http://www.lowrestv.com/moho_stuff/copybones.zip

(two scripts, one for copy one for paste. Goes in the menu folder.)

What would really be cool is a tool for copying bones. For instance select the "copy bones" tool and select the bones. At the top a button that says copy and a button that says paste. Just like the style palette. Both buttons available at the same time but the paste only works if you've copied the bones first.

Just an idea.

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

Post by heyvern »

Rasheed,

I hope you don't mind. I'm giving a stab at adapting your flipbybones script so that it reverses the value of a translation constraint at the same time.

So far my attempts in a test script works great. Constraint values can be set by LUA. This would allow me to change the direction of translation constraints on a face turn as it passes the halfway point. Just like this layer z-depth script. This will cut down on the number of bones needed for my face rig by quite a bit. And also make it work a bit better. I have a problem making the eyes appear correctly on either side of a head turn.

I may be able to just stick my extra bit of code into your script since it would be activated at the same spot.

For my face rig I have bones lined up in the middle of the face to act as a switching point for the layer z-depth and the constraint reversal.
So as a bone passes this "center" point, two layers flip and the horizontal translation constraint value on another bone will be reversed. Pretty cool.

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

Post by heyvern »

Rasheed!

The new script is WONDERFUL! The new features are excellent additions.

My other addition is also working... sort of. Still some bugs to work out. I can do this stuff it just takes me longer since I have to look everything up constantly. ;)

This brings up another idea regarding this type of control...

If these elements can be controlled by a bone... ANYTHING can right? I mean, a switch layer could be activated by bone translation... anything could.

Imagine the rotation of a bone activating a hand switch, or any type of switch. The mind boggles!

-vern
Post Reply