Open jetrotal opened 5 years ago
Hi, and sorry to reply late!
There are very interesting ideas in this way of organizing the effect which may be clearer. But one thing I don't like is that it makes it more complicated for simple stuff (just colored and tapered strokes); one would prefer to have the more useful and usual values directly accessible at the top like in the previous version, to create "basic" strokes very quickly. That's why I think I prefer a basic/advanced controls organization, but I believe these two approaches can be combined.
Why not even propose two different effects, one version simple for "just" tapered strokes with a few other options, and another one with the whole thing like this?
I did not have time these latest week to work more on DuStroke (I had to finish a lot of things for Duik); right now I'm taking some vacation, I'll be back in mid-august, and then Dustroke is on my top priority list, I'll make my homework at that time and build a first version of the script part, and try to see how we can arrange this new pseudo effect ;)
Thanks again for all your work and ideas!
I got what you are saying.
I tried to Mimic the v2.0.1's Basic Values inside the "Setup" Group, and isolate these complex settings by putting them inside a "Settings" group for each property.
I felt that i had to move the "Advanced" size settings near to the "Basic" taper setup after finding myself going up and down a lot through their tabs:
Maybe we can remove this "Setup" Group, and put all these initial setup properties outside any group.
I also felt that the current approach wasn't very friendly to invert properties in "Triangle" or "Round" Modes.
That said, i coded an different approach to invert these properties along the stroke, by affecting the Amount property of a selector, instead of changing the Animated property itself :
Considering that the "Amount" property goes from "-100%" to "100%". I had to make the animated Scale property "10000", and divided the "Amount" property by 100.
I removed the "Invert" checkbox that i suggested earlier, because the same result can be reached by changing the Start/End values in this approach.
I uploaded these tests here: https://github.com/Rainbox-dev/DuStroke/tree/master/Pseudo%20Effects/DuStroke%20PrototypeTest
So you can test them, and see what is useful on these suggestions
No worries about the time you take to work on this, man... We are working on this in our free time, and since i'm an workaholic and an unemployed, i have a lot of free time to fiddle with these stuff.
Take your time and enjoy the vacation, you have been working hard on tons of good tools for our comunity :}
Reworked the Randomize Order code. It now shuffles the text order, instead of randomly changing their values.
Users can now choose if they want to reorder<br>
and <tab>
tags too:
Here's the code:
function randomizeOrder(e) {
seedRandom(seed, true);
var i = e.length;
var j = 0;
var tab = '\u0009';
var br = '\u000A';
if (DuStroke(238).value == 1){
tab = 'LULA__LIVRE';
br = 'LULA__LIVRE';
}
var temp = "";
var arr = [];
var output = "";
for (var i = 0; i < e.length; i++) {
//generates an array containing each character from the TextController.
arr.push(e[i]);
}
for (var i = 0; i < e.length; i++) {
j = Math.floor(random() * (i + 1));
if(arr[i] != tab){ if(arr[j] != tab){ if(arr[i] != br){ if(arr[j] != br){
// swaps randomly chosen character with current character when it's not TAB or BR.
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}}}}}
for (var i = 0; i < e.length; i++) {
output += arr[i];
}
return output;
}
Probably there's a more effective way to do this shuffle without that many FORs and IFs.
I just found an old Script that works in a similar way that DuStroke does, but focusing on Glyphs for motion graphics instead of Brushes and Strokes.
It's the MoGlyph FX: https://aescripts.com/moglyph-fx/
The main difference between DuStroke and MoGlyph FX is that they generate one PseudoEffect for each new item inside the text layer (both when adding a new character or an animated property).
MoGlyph FX has some creative Controllers solutions too, called "Effectors".
These Effectors and Character Controllers are all driven by their script panel, in order to keep the TextLayer free from tons of Animators and heavy Expressions.
Here's a video, where the author shows some advanced features from his tool: https://www.youtube.com/watch?v=sLdZ7BqdCSM
Maybe we can learn a thing or two about optmizing TextLayers performance.
I know the developper of this script (and I'm actually teaching him development ;) ) It's a good idea to split the pseudo effect (and the text animations) into several smaller ones, which could be added only when needed...
What a small world... I've seen you both are from france, but had no idea about you knowing each other.
I liked the multiple pseudo effects approach too, but part of me preffer the TextController solution to customize the characters. It looks a cleaner solution instead of multiple pseudo effects for each character.
Splitting the pseudo effect can be useful though. Like: One effect for the color, One effect for the brush, One effect fot the taper, Etc.
This way it makes the effect smaller, and quicker to use if what you want is only a taper and not color ramps, etc. (and there would be less text animations, only the ones needed, which should improve performance)
The script would be there to add only what the user needs (and remove corresponding effects and text animations too)
Yes, I Aggree on that point. That could work with your suggestion of creating a "basic main PseudoEffect" with taper and color, and other custom PseudoEffects to fully customize the brush settings.
With that in mind, is possible increase the customization possibilities, like rotating a single character 90º while randomly rotating every other character, in order to create an arrow that points somewhere.
Hey @Nico-Duduf, I Found an interesting approach to drive Animators inside a Text Layer, from a developer who hated fiddling with numbers inside AE.
The method is based on animating the properties from a Layer, and making the text animators mimic These properties.
It works like a simpler version of our Curve Controller, but with the liberty to change any property on the go, like Position, rotation etc...
I added some kind of Connector to the CurveController that helps defining the Start, the Middle and End Values of our stroke by hand, instead of navigating through tons of panels inside the Effect: https://github.com/Rainbox-dev/DuStroke/blob/master/Pseudo%20Effects/CurveController/DuStroke_AdvCurveController_test.aep
http://www.2deadfrog.com/how-to-create-text-animation-in-after-effect/?fbclid=IwAR1ohEEPkG7gaieeewVcgMiY27t_HK5hOXlX3c2hSkg6qElRfAOxFp_KHBU (The idea came from a discussion about the problems and solutions of animating text layers, now in english).
Personnaly I don't really like havong too many controls in the viewport. It's something we do a lot in 3D, but in 3D softwares, viewports are infinite ^^ A stroke tool is still something quite "secondary", and is going to be used with many other stuff in the comp, so this could be too much. And it's quite easy if you'd like to use Duik or Joystick and Sliders to create these kind of controls for Dustroke.
Yeah, i agree with you... I'm not 100% sure that this version of the Curve controller is useful at all, But i tested some workarounds to improve the performance and clean the timeline...
This is how i tackled some issues you pointed out:
Usually, someone would cycle trough all characters using an expression selector, like this:
try {
var ccLayer = "CC | Dustroke 01 | Taper";
percent = linear(textIndex, 0,textTotal, 0,1)
val = -thisComp.layer(ccLayer).content("CurveController").content("Path").path.pointOnPath(percentage = percent, t = time)[1];
100 - Math.abs(val);
} catch (err) {
0
};
Since the code is too heavy to deal with a 150+ characters in a text, i hardcoded 9 selectors in "Triangle" Shape Mode, that cycles from 0% to 100% of the characters natively, speeding up the layer:
Only the "CC Setup" Animator deals with the Curve Controller, to avoid multiple interactions with a bezier curve.
The "CC A", "CC B" and "CC C" only applies the Transform from the "A", "B" and "C" shapes in relation to the result produced by the "CC Setup".
In total, only 27 Selectors are visible in the timeline (+ 9 from the "CC Setup" that are hidden). I'm not having performance issues with a Basic Stroke that has 150 characters (I need to stress out the tool to see how it goes in other scenarios)...
To Deal with stacking too much layers , i condensed "A","B", "C" shapes inside a single shape layer:
Then, i grouped each shape to give Transform Controls to them:
To edit these Transform Properties, the User must double click the shape Layer in the ViewPort, it will select automatically a group in the shape layer and it's properties.
It works, and i could even put the A B C shapes inside the Bezier Layer to have less layers stacking in the main timeline.
Well, I know this method gets kinda confusing when someone wants to add keyframes or deal with specific values, since the keyboard shortcuts to Transform Properties won't work with groups inside shape layers.
Maybe the overall workflow can get pretty abstract with a controller like this, IDK...
I can see some potential on it to animate things Like Smear Effects, or body shapes that deforms in specific conditions, like the Muscles of an arm or the Torso of a character.
My main motivation on trying to figure out an organic workflow to this, came after reading about the dificulties that people have when dealing with multiples Animators stacked over a text layer...
Even though we eased the process a lot through DuStroke, We are still stacking technical stuff inside PseudoEffects.
I also have been reading some amazing insights from people who are trying to bring handmade workflow to their motion design tools:
https://www.justtodosomethingbad.com/blog/2019/4/8/why-keyframes-are-bad Like this guy, who is creating an entire Riggin System in maya that brings traditional character animation to his workflow.
https://www.youtube.com/watch?v=P1zBbOowyTE Or Disney's Research Hub, that is creating some inovative Rigs to handle 3D Character animation.
(Sorry if i got too Off Topic here :p )
Is there a way to cycle a character's position on an open path?
When i did the Fire animation, i based myself on this Approach from a Game Maker engine:
The problem is that i can only loop the Stroke Offset of a character when i have it attatched to a Closed Path , like this:
It worked as intended, but i felt restricted to the center of the "Red Layer".
If i wanted to have more control over the shape of the fire or if i wanted to use the same workflow to animate river/waterfall/speed lines details, i would have to improvise with precomposes, mesh warp, etc...
There's a way that may help us with this, through a code made by Mikey Borup: https://twitter.com/longlivemikey/status/1085914784686530563
He wrote a Selector that creates a percentage of where the point is on the canvas, and applies that percentage to the full width and full height position:
Based on that, we can check if a character's position is before or after the last point of a path, then send it back to the first point if it's after.
I don't know if this approach would slow down the entire Project performance, what do you think @Nico-Duduf ?
Merge Multiple paths inside a single DuStroke Layer (Mikey Borup's Solution could help us on this one too).
The problem with this Girl Demo, is that it has tons and tons of repeated DuStroke Layers, making the project convoluted and slow.
To solve that, i tried to code a path that merges multiples other paths:
var srcLayer = thisComp.layer("Shape Layer 1");
var pA = srcLayer.content("Ellipse 1").content("Path 1").path;
var pB = srcLayer.content("Polystar 1").content("Path 1").path;
var arrayPath = [];
var arrayInTangents = [];
var arrayOutTangents = [];
function getValues(e){
var tempArray = []
var srcPath =
pA[e]().toString() +","+
pA[e]()[0].toString() +","+
pB[e]().toString() +","+
pB[e]()[0].toString();
var splitPath = srcPath.split(",");
for (var i = 0; i <= (splitPath.length+10); i = i +2){
var temp = [];
try{
temp.push(splitPath[i]);
temp.push(splitPath[i+1]);
tempArray.push(temp);
} catch (err) {
}
}
return tempArray;
}
arrayPath = getValues("points");
arrayInTangents = getValues("inTangents");
arrayOutTangents = getValues("outTangents");
createPath(arrayPath,arrayInTangents,arrayOutTangents,false);
I used this one to make the Nose + Head strokes of the girl, with some issues when connecting them:
On the Girl example, i masked the stroke between the Two paths easily.
I still needed to repeat this "Shape Merging" more often, to cleanup my timeline, and i just gave up due to all the masking i would have to repeat over and over again.
Again, Mikey's code could help us with this, If we make DuStroke's Scale or Alpha = 0, whenever its between last Point of Shape A and First Point of Shape B.
Reverse Path Orientation Sometimes reversing the orientation of a path is needed to archieve the right look of a Stroke:
There's a free script that does that at: https://aescripts.com/reversemaskpath/ We could adapt it to detect when it's Mask Path and when it's Shape Layer Path.
Fill Mode What about a Script to make DuStroke work as a fill? I used it tons of times on the Girl and the Plant Demo:
The Ideal Solution would be to spiral in the Original Path. But that could be heavy to calculate.
Maybe, would be better if we duplicate the Original Path multiple times, reducing its proportion at each duplicated shape:
I was testing the Ouroboros free Script, it has some interesting quirks https://aescripts.com/ouroboros-2/
It can Grey-out every property on it's Pseudo Effect that isn't applied from the script. This is different from the MoGlyphFX script, that keeps every property on its pseudo effect active, even when the property isn't linked to nothing...
How was this done? Does Ouroboros generate a different Pseudo Effect from every possible property combination?
It has some convenience buttons, that change the randomSeed of any selected property on its pseudo effect, or apply keyframes to a custom Module.
Hum, interesting. I don't know if I prefer this approach which makes each section easily discoverable, or adding a new pseudo effect to activate each section, which looks cleaner but doesn't show the actual capabilities... Anyway, ouroboros is open source so we can have a look at how it does that. It has to replace the pseudo effect each time the combination is changed, that's for sure, so either it stores all combinations possible or it generates (or modifies) the pseudo effect on the fly...
Well, at first, Ouroboros seemed counter-intuitive and overwhelming for me. I had to watch the plugin's tutorial series to undersand the weird looking approach they used on it.
It uses some clever and unique ideas on its UX, but i don't think it causes a good first impression to anyone that expects it to work as a common after effects interface...
It would work, if we figure out a way to orient the user on how to activate an "Module/Modifier" on the go.
Wait a minute... Have you ever tested fiddling with the "Invisible" property from the Pseudo Effect Maker?
It looks like it doesn't change the PropertyDepth and PropertyIndex from an effect property at all:
Maybe that could be a good way of Turning On/Off itens from a single pseudo effect, without showing them all as grayed-out all the time.
The are still some specific cases, where the user would need to add more Pseudo-Effects, for duplicated properties, like a single Rotation + Scale Modifier to give an Arrow Head at the end cap of a stroke.
But this solution could prevent some problems, like one trying to remove a modifier by simply Deleting it, and breaking the TextLayer's Animator.
Removing an effect is not necessarily an issue, as the expression can check if there is the effect and just do nothing if not found. This way, one can add or remove effects without any issue. Maybe all the animators could even already be there, waiting for their effects ;) This is a bit simpler to develop script-side. I use this trick in Duik for a few effects which can be duplicated at will.
The thing with hiding properties in pseudo effects is that you need as many pseudo effects as possible combinations, I don't like that (pseudo effects can't be modified on the fly)
Hey @Nico-Duduf! Are you still working on DuStroke/ DuShape?
I found this seamless way to repeat string values through string.repeat();
phrase = text.sourceText;
num = 5;
phrase.repeat(num)
I hope that helps.
Cheers!
I'm currently working a lot on Duik, as there is a new version I have to release next week ;)
But dustroke is next in line. Thanks for this method I did not know it. It's neat! I'll test if it's faster than a loop just to be sure.
thanks!
After Effects 2020 gives full control over Text Properties through expressions
It also let us create custom DropDown menus:
Full Review: https://www.youtube.com/watch?v=vufghNC9hGw
Yes that may be interesting, but it's not "per character" yet, it changes the properties for the whole text. That said, we can now change the font without using the script, directly from the pseudo effect, which is veeeery nice!
hm... On the review video is told that the expression reads the Style Values from the first character. Maybe we can change the style from single characters, through souceText[n].style.setFont("FONT")
EDIT Not possible, is only possible to GET values from single characters, not SET.
Hey @Nico-Duduf , I gave some thought about the DuStroke Pseudo Effect and uploaded a custom version of it, feel free to use or discard any ideas from it.
This is how it looks:
https://github.com/Rainbox-dev/DuStroke/tree/master/Pseudo%20Effects/DuStroke%20PrototypeTest
Setup Tab
I added a "Brush" Tab, just to suggest for the user to check the ScriptUi instead of the Font Pannel. Don't know if is it useful at all.
I removed the "as is/ repeat / randomize" from the brush Density, since we will work with the Text Controller and "As is" vs "repeat" options are the same as "Density = 1" vs more Density. The Randomize option should respect the Caps from the Text Controller.
Maybe the Start Size / End Size Values should work as absolute values, instead of that Taper setting from the current version. That way will be easier to invert values and remember all other settings that are named "Start __" or "End __" equally.
The "Start Locator" and "End Locator" are the old "Start" and "End" Properties. I had to give this name to them because i started repeating "Start" and "End" through other properties.
"Path Offset" and "Path Alignment" are the same as the older version. The difference is that the frontend of the "Path Alignment" works better as "0" instead of "-18" or any property we setup as the font needs. We should leave this Alignment Setup hidden from the Effect Tab.
.
Setup Tab / Color Settings
For the colors i added a Settings Tab, it works as the older color Tab, with the Invert option added and a "Curve Controller" Selector. The "Controller Density" determines how precise the Curve Controller is.
Dynamics Tab
I removed the "Dynamic Blur" and the "Blending Opacity" properties. We can get the same result through the "Transform Tab -> Opacity Settings -> Mode: Absolute" property.
"Dynamic Spacing" will change the white space between characters, giving more space to the bigger and less space to the smaller characters.
"Flip Mode" and "Mirror Mode" will control the Flip and the Flop from each character. .
Blending Tab
I put a "Blend Mode" visualizer to incentive the User to test out the script possibilites. Not sure if is it useful at all.
Changed the "Random Color" to "Tint" too. It probably will share the same code as the Flip property + the "Color Influence" controller, aka "Random Color" from the Current version.
Transform Tab
I Tried to cover all the properties that were used with the current DuStroke. Probably there are more properties that can be animated in a Text Layer, but the controller is at it's limit. every time i try to add more properties it glitches.
Should we create a "Selector/Animator Controller" to help people that want to stack more properties like this?
.
Transform Tab / Scale Settings
Every property inside the Transform Tab work the same way. That's why all the "Settings" tabs are pretty much the same.
I removed the "Enabled" checkbox, and used "Mode: Absolute" Setting Instead, it could consider the "Invert" Checkbox only, to determine wich value to pickup.
I Also Included the "Randomizer Influence" and "Randomizer Mode" to the main Settings. When the "Influence" is 0, the randomizer should be "Off".
I also added and a "Curve Controller" Selector. The "Controller Density" determines how precise the Curve Controller is.
Options and Text Controller Tabs
The options Tab have the Randomizer Settings. And the Text Controller Tab, is there so people can select a Controller from another Layer.
I even tried to move those Settings from the main Text Controller to the DuStroke, but the Pseudo Effect Maker glitches with more properties, and they should be contained inside the Controller Itself, to work through different layers.