Forum Replies Created

Page 1 of 277
  • It might be good to know what is the actual animation or video this needs to be overlayed upon ? Are you combining video that is changing perspective (like a point of view of someone woalking around, facing different directions) and you want the direction arrow to update using realtime data that is in sync with the video ?

    Or are we talking about something like a topdown view of a worldmap or globe, and you want a vector from different places on this map to point the Qibla direction ?

    Can you show a screenshot of what you want to add this too ?

  • Thanks Nathan.

    I did wind up adapting it to a binary search method a few years later, which is Exponentially faster (but needs 16bits per channel)

    https://creativecow.net/forums/thread/how-can-i-center-the-anchor-point-based-on-opacity-of-a-comps-contents/#post-2458578

  • Sorry, I was mistaken in the other thread; I though you were talking about this animation preset of mine: subsourcerect .

    I haven’t released the source of v2 which works with fractional frames, b it perhaps this version already works for your case

    https://imgur.com/9oRKx7R?r

  • The easiest method I can think of using only effects and not 3D-layers, while keeping it on a single layer is this:

    • Hit ctl/cmd-Shift-N to add a new mask to your layer
    • then hit ctl/cmd-Shift-M to numerically set the shape of the mask to be:
      Left= 0, Right= 50% of Source (the left page)
    • Do the same to create a second mask but make the second mask:
      Left= 50%, Right= 100% of Source (the right page)
    • Add the effect Obsolete > Basic 3D.
    • In the timeline, reveal the effect, and next to Compositing Options, hit the + sign to add an effects mask reference. (it’ll automatically select Mask 1)
    • Duplicate The Effect, and in the 2nd instance of the effect, change the effects Mask reference to “Mask 2”.
    • Animate the swivel of the first effect form -90 to 0, and the second one from 90 to 0.
    • Optionally; also animate the Distance to Image paramater.
  • Filip Vandueren

    April 25, 2024 at 11:05 am in reply to: Layer movement in expression

    OK, but there’s an important difference between spatial beziers and temporal easing.

    The spatial beziers are defining the shape of the path, and that’s not automatically the same as easing.

    That being said, if you do want to control both easing and the tangents with the same 0-100% controls, I think the ball’s position should still have the same expression, but the easing has to be done on the 0-100% end of the Trim Paths End-parameter.

    There is no built-in method in expressions to mimic keyframes’ custom easing functions with arbitrary velocity and influence, and after effects handles it in a rather quirky way that’s different than for example javascript or css animations.

    Even if we try to recreate a correct bezier-curve for the timing-parameters,
    bezier curves are evaluated in terms of t, while after effects’ easing is more like f(x) instead of f(t).

    Anyway, not to bore you with the theory; here is a hack that gives accurate results:

    – create a new shapelayer, I called it “bezier timing”.

    – add a Path to this layer, no stroke is necessary, it will need to be a hidden layer anyway.

    – the path gets this expression:

    p=createPath([[0,0],[100,100]],[[0,0],[-thisComp.layer("Controls").effect("Handle 02")("Slider").value,0]],[[thisComp.layer("Controls").effect("Handle 01")("Slider").value,0],[0,0]],false);

    – add a slider to the shapelayer, I named it “ease” and give it this expression:

    pt=content("Path 1").path;
    precision = 16;
    x=time/100;
    t=0;
    // binary search the best t-value for a given x
    for (i=0; i<precision; i++) {
    if (pt.pointOnPath(t+(0.5**i))[0]/100 <=x) {
    t+=0.5**i;
    }
    }
    // give y-value at that t
    pt.pointOnPath(t+(0.5**i))[1];

    Now we can get the correct eases via this expression:

    thisComp.layer("Bezier timing").effect("ease")("Slider").valueAtTime(value);

    where (value) is between 0 an 100.

    You could now set linear keyframes 0 to 100 on the trim Paths, and add that final expression to the trimpaths, and the actual trim and ball animation will follow the timing you want.

  • Filip Vandueren

    April 24, 2024 at 1:17 pm in reply to: Layer movement in expression

    What do you mean by “the movement information of this ball” ?

  • Filip Vandueren

    April 24, 2024 at 1:10 pm in reply to: Custom easing function using expression

    These interpolation functions are only supposed to give meaningful results between 0 and 1 (or 0 and d in this case).

    Easiest fix is to start each function with this line:

     t=clamp(t,0,d);

    for example:

    // sinusoidal easing in/out - accelerating until halfway, then decelerating
    Math.easeInOutSine = function (t, b, c, d) {
    t=clamp(t,0,d);
    return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
    };
  • Certainly, all the calculations for the bounding-box are already done, we just need a different final line.

    For a rectangle shape, we need two 2-dimensional results: the center of the rectangle, and the width and height of the rectangle.

    You could rewrite the two expressions like this:

    Size:

    // posterizeTime(0); // uncomment for still images
    includeEffects = false;
    l=thisComp.layer("transparent PNG");
    w=l.source.width;
    h=l.source.height;
    threshold = 0;
    width_bits = Math.ceil(Math.log(w)/Math.log(2));
    height_bits = Math.ceil(Math.log(h)/Math.log(2));
    left = 0; right = 0;
    for (b=width_bits-1; b>=0; b--) {
    slice_width = 2**b;
    if (l.sampleImage([left + slice_width/2, h/2], [slice_width/2, h/2],includeEffects)[3]<=threshold) {
    left+=slice_width;
    }
    if (l.sampleImage([w - (right + slice_width/2), h/2], [slice_width/2, h/2],includeEffects)[3]<=threshold) {
    right+=slice_width;
    }
    }
    right= w-right;
    top = 0; bottom = 0;
    for (b=height_bits-1; b>=0; b--) {
    slice_height = 2**b;
    if (l.sampleImage([w/2, top + slice_height/2], [w/2, slice_height/2],includeEffects)[3]<=threshold) {
    top+=slice_height;
    }
    if (l.sampleImage([w/2, h - (bottom + slice_height/2)], [w/2, slice_height/2],includeEffects)[3]<=threshold) {
    bottom+=slice_height;
    }
    }
    bottom = h-bottom;
    [right-left, bottom-top];

    Position:

    // posterizeTime(0); // uncomment for still images
    includeEffects = false;
    l=thisComp.layer("transparent PNG");
    w=l.source.width;
    h=l.source.height;
    threshold = 0;
    width_bits = Math.ceil(Math.log(w)/Math.log(2));
    height_bits = Math.ceil(Math.log(h)/Math.log(2));
    left = 0; right = 0;
    for (b=width_bits-1; b>=0; b--) {
    slice_width = 2**b;
    if (l.sampleImage([left + slice_width/2, h/2], [slice_width/2, h/2],includeEffects)[3]<=threshold) {
    left+=slice_width;
    }
    if (l.sampleImage([w - (right + slice_width/2), h/2], [slice_width/2, h/2],includeEffects)[3]<=threshold) {
    right+=slice_width;
    }
    }
    right= w-right;
    top = 0; bottom = 0;
    for (b=height_bits-1; b>=0; b--) {
    slice_height = 2**b;
    if (l.sampleImage([w/2, top + slice_height/2], [w/2, slice_height/2],includeEffects)[3]<=threshold) {
    top+=slice_height;
    }
    if (l.sampleImage([w/2, h - (bottom + slice_height/2)], [w/2, slice_height/2],includeEffects)[3]<=threshold) {
    bottom+=slice_height;
    }
    }
    bottom = h-bottom;
    fromComp([(right+left)/2, (bottom+top)/2]);

    Note that in the 2nd expression, Only the final line is different. And that in both “l” is no longer thisLayer, but is explicitly set to the layer with alpha we want to examine.

    This approach with 2 expressions on two properties means that we have to do the entire calculation with sampleImages twice, and while the binary search has made it pretty efficient, it does take twice as long.

    Whenever complex expressions need to be done in multiple places, it could be better to do the calculation just once, and then have both size and position reference the same result to get the value.

    In the case of a single value that needs to be reused, this can be done in an expression control like a slider for 1 dimension values, or a controlPoint for more dimensions, but there are about 4 or more variables resulting from the expression we might want: left, right, top, bottom, ctr, height, width,…

    A neat way to communicate complexer results is with text-layers.

    Something like this:

    A hidden text-layer named “sourceRect” gets this expression for its sourceText property:

    sourceText:

    // posterizeTime(0); // uncomment for still images
    includeEffects = false;
    l=thisComp.layer("transparent PNG");
    w=l.source.width;
    h=l.source.height;
    threshold = 0;
    width_bits = Math.ceil(Math.log(w)/Math.log(2));
    height_bits = Math.ceil(Math.log(h)/Math.log(2));
    left = 0; right = 0;
    for (b=width_bits-1; b>=0; b--) {
    slice_width = 2**b;
    if (l.sampleImage([left + slice_width/2, h/2], [slice_width/2, h/2],includeEffects)[3]<=threshold) {
    left+=slice_width;
    }
    if (l.sampleImage([w - (right + slice_width/2), h/2], [slice_width/2, h/2],includeEffects)[3]<=threshold) {
    right+=slice_width;
    }
    }
    right= w-right;
    top = 0; bottom = 0;
    for (b=height_bits-1; b>=0; b--) {
    slice_height = 2**b;
    if (l.sampleImage([w/2, top + slice_height/2], [w/2, slice_height/2],includeEffects)[3]<=threshold) {
    top+=slice_height;
    }
    if (l.sampleImage([w/2, h - (bottom + slice_height/2)], [w/2, slice_height/2],includeEffects)[3]<=threshold) {
    bottom+=slice_height;
    }
    }
    bottom = h-bottom;
    sourceRect = {left: left, right: right, top: top, bottom: bottom, width: right-left, height: bottom-top, ctr: [(left+right)/2,(top+bottom)/2]};
    JSON.stringify(sourceRect);

    if you look at the txt-layer its output will be something like:

    {
    "left": 715,
    "right": 1163,
    "top": 304,
    "bottom": 450,
    "width": 448,
    "height": 146,
    "ctr": [
    939,
    377
    ]
    }

    This has all the data we need (even more than a regular sourceRectAtTime would give) in JSON format. We can read/parse anywhere we need it in a different property’s expression like this:

    rectangle’s shape Size:

    sr = JSON.parse(thisComp.layer("sourceRect").text.sourceText);
    [sr.width, sr.height];

    rectangle’s shape position:

    sr = JSON.parse(thisComp.layer("sourceRect").text.sourceText);
    fromComp(sr.ctr);

    You can add more shapes, like a little circle on the anchor-point, or crosshairs etc. by reading out the values in the text-layers, instead of having to copy (and execute) the entire long calculation expression in each place you need the results.

    Finally a caveat:

    If you plan on scaling, rotating or moving the alpha-layer anywhere but at its default and want the rectangle shape to keep lining up:

    It’s easiest to parent the shape-layer to the alpha layer,

    Set the shape layer at scale 100% and position 0,0. (again: the position of the layer, not the position of the shape)

    And then don’t do the fromComp() in the rectangle’s shape position:

    Rectangle’s shape position:

    sr = JSON.parse(thisComp.layer("sourceRect").text.sourceText);
    sr.ctr;
  • Perhaps this one can help you:

    https://www.youtube.com/watch?v=b52jyEFPnYQ

    Some contents or functionalities here are not available due to your cookie preferences!

    This happens because the functionality/content marked as “Google Youtube” uses cookies that you choosed to keep disabled. In order to view this content or use this functionality, please enable cookies: click here to open your cookie preferences.

  • Filip Vandueren

    March 19, 2024 at 8:49 pm in reply to: Paragraph Alignment Detection

    Because it is a text-animator, not a layout setting, the textbox is ignored.

    And the tracking pushes all left-aligned text away from the left margin, or vice versa. So it turns out to be very handy for exaggerating the dimensions to do some testing.

    I tested it with 3 lines that were exactly evenly kerned so nothing visually changed when choosing different alignments, but the tracking gave the correct result, so there you go… 🙂

Page 1 of 277

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy