SourceRectAtTime expression causing major performance issues with motionblur
Copy link to clipboard
Copied
Hello,
I'm was looking into why my expression-heavy After Effects Comp grinds to a halt whenever I active motion blur. I use it to auto scale a textbox. Since I use multiple of them in one comp, I can't avoid calling sourceRectAtTime(0) for each text. I'm fairly certain it is this text, since I made an optimization to disable the call, when the text is unused and the render time goes down.
I've already tried the suggestions made by Dacia Saenz (https://adobe-video.uservoice.com/forums/911311-after-effects/suggestions/43383660-what-kind-of-expr...).
I haven't tried to offload sourceRectAtTime() to an external extendscript, since I'm not sure yet how to best do this.
I also tried:
// cacheCompareSamplesPerSecond 0
This didn't improve the performance.
I tried to "cache" the results in a point effect and call it with valueAtTime(0) but it still evaluates for every motionblur sample, thus slowing down my render.
Is there something else can can be done to definitively cache these values? They only have to be called once, since I don't need scaling of the textbox within the animation.
Thanks!
Copy link to clipboard
Copied
The Transform Motion Blur feature calculates Motion Blur on every frame - this is required, by default. If it doesn't calculate on every frame then the Motion Blur effect wouldn't work.
Copy link to clipboard
Copied
Yes, not only does it calculate 1 time per Frame (which would be fine) but reevaluate the expressions for every motionblur sample (16 in my case), so far my terrible understanding of the After Effects render pipeline goes. Reducing the motionblur samples improves the performance, with a big cost in quality, in my opinion.
I won't deny that this is a good thing for animations, but when you link "static" values, it becomes an issue. The sourceRectAtTime(0) already disables change over time. But the method itself is still invoked for every frame and sample and thus slowing down the render.
Copy link to clipboard
Copied
You mentioned Render Pipeline in your first paragraph. If you continue along this path, you will appreciate that Time Dependent effects override a 'static' Expression Method. Either way you go, there will be an issue – either the 'static' Expression Method gets overridden or the Motion Blur.
The decision seems dependent on AE having a preference for quality over time which seems to be what the vast majority of users want in such an application.
You will also want to take note that should sourceRectAtTime(0) is followed with an Expression Method which requires calculations on every frame, then every frame will be calculated; again a case of a time dependent effect/Expression Method overriding one which is 'static'. HTH
Copy link to clipboard
Copied
Ah, well that's the answer i feared getting.
I noticed in my tests that even when not matter how deep in the expression chain this method is located it makes, no difference here.
I tried mirroring the text (one with, one without motion blur) and it seems to render faster if I link the bounding box from the one without. But I can't really tell for certain.
Since the expression are used in a layer with blur enabled. This should mean, that it still loads the values as often as there samples, right?
Could it be that sourceRectAtTime() is slower for text layers with motion blur enabled?
Thanks for your help so far.
Copy link to clipboard
Copied
sourceRectAtTime() is not inherently slow. Motion Blur is inherently slow.
You can offer a user the option to choose a Motion Blur version versus one without. Then set up the Comp/Project Hierarchy to allow for this. This way, you allow the user to select/accept the performance hit that comes with selecting the Motion Blur option. HTH
Copy link to clipboard
Copied
I think I've found a solution that works better now.
Since I don't need to keep the vector-layers intact, I used the blur function of the transform effect (with 180° shutter) instead.
As a precomp it renders about 5-10x times faster then before now, even after reseting the cache.
Thanks for leading me in the right direction.
Copy link to clipboard
Copied
Have you tried putting
posterizeTime(0);
at the top of your expression?
Copy link to clipboard
Copied
Yes it helps. I completely forgot about this function.
What I forgot to mention in my inital post is, that I'm using Essential Graphics Variables, to make it more customizeable, and then after it is precomped it seems to ignore posterizeTime() in the Expressions and the render times stay the same. Inside the comp it makes it render super fast with even with motion blur.
Copy link to clipboard
Copied
Maybe the essential properties render pipeline re-instantiates the nested comp at each frame, making caching impossible? Or maybe it's just a bug.
Copy link to clipboard
Copied
Thats a good question. It could also be deliberate so you can't accidentally disable the changes from essential properties?
I know that I hit that issue, several times since I used essential properties.
Essential graphics still feels a bit rough around the edges. At least it doesn#t crash After Effects anymore when you copy a Comp with more then a few linked properties.
Copy link to clipboard
Copied
If you just need a simple auto-scale textbox, maybe you do it without any expressions at all?
See the method I describe here in the section "Simple Text Boxes" of my free motion graphics eBook:
https://mamoworld.com/motion-graphics-ebook/content47.html
Copy link to clipboard
Copied
Thanks, I'm aware of this. I didn't use this variant because mine can deal with special characters like ÄÖÜ or normal lowercase text, without changing the height of the boxes.
Copy link to clipboard
Copied
Are you doing it implicitly or are you setting explicit values for things like the cap height? I've been using a method where I use a Character Value animator to change all the characters to uppercase E's before time=0 and sample the sourceRect at a negative time. This allows me to see the cap of the top line and the baseline of the last line of text. I'd be curious if anyone has found other methods.
Copy link to clipboard
Copied
Yours seems more intelligent.
I've taken an expclipit approach.
Since I set the font height via Essential Graphics, I know the size of the font and then I calculated a conversion value (pt to px of a capital letter) for the font I'm using (by hand). And I use this factor to set the base height of the textboxes. So my height vlaue is independing from sourceRectAtTime(), but it has some rounding errors.
Thinking about it now I could easily convert this into an implicit version, by applying the font size and font face to a hidden text with a single capital letter and get the bounding box from there.

