-
Notifications
You must be signed in to change notification settings - Fork 667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[css-animation] Motion Blur #3837
Comments
This is definitely something I've seen asked for. I've also seen it faked (for linear motion) with SVG filters (and there is a proposal to add unidirectional blur to the CSS shorthand). But it would be much better all around if the browser can calculate the amount of blur needed based on its frame rate and the motion being applied. Even better if the blur can be implemented at the GPU/compositing level. Diving into the details:
|
Hmm, I think it makes more sense as part of E.g. The motion blur effect reminds me Unity's Shutter Speed Simulation from the GPU gems article. I think if we can decide on a simple implementation like adding to the filter property, I'd be OK with this. But motion blur might not be appropriate really for digital graphics, unless we are simulating a 3D scene and attempting photorealism. Motion design artists don't actually like using motion blur, it's a common mistake by beginners. There's more to meaning in motion than blurs, read this article to understand: https://www.schoolofmotion.com/blog/motion-blur-after-effects And even for 3D scenes, there are ways of doing non-blur motion: https://twitter.com/chriswade__/status/748050910417387520 I'm a bit wary of global 'motion-rendering' thing. I am in awe the day when we will be able to do all these kinds of expressions of motion on the web: https://twitter.com/tonikopantoja/status/1075951567826644992 |
@AmeliaBR 1. Would this approach work for other types of animations (like shape morphing or color transitions) or only transformations? 1. Would the proposed shader implementation work for 3D translations, or only for flattened effects? If so, should motion-blur: blur be a flattening layer effect? 1. Is it necessary to limit it to GPU-accelerated animations? We don't have any other properties (that I know of) that reference the rendering pathway. But we do have "hint" properties (shape-rendering, text-rendering, etc.) that indicate an author preference for certain optimizations if they are available. (Maybe this could be called motion-rendering?) 1. Could we make the default auto to allow browsers to opt in to blurring by default if they discover it isn't much of a performance hit? I'm pretty sure this is an effect that you'd want most of the time, if it was available. (Of course, there should still be a none option to turn it off if the author has a reason to.) @Martin-Pitt
Disagree here, motion blur has valuable use outside of those contexts.
Disagree here, I know many artists that like motion blur, and it's not our decision to say if it's for beginners or not. That mentality would prevent lots of great things from reaching CSS. Agree there's more to motion than blurs, Disney taught us a lot about motion and perception. Motion blur is definitely a basic/essential, but that doesn't make it only a beginner tool.
Can you unpack that a bit? I don't think a global motion blur or motion-rendering declaration is great either. Though sure, someone may apply it in their CSS. The proper usage would be putting it on an element you're moving quickly, and I like the requirement of it only applying to elements already promoted to layers in the GPU due to other best practice web animation strategies. Means applying it globally would have no effect.
@AmeliaBR's suggestion of naming to
I like your idea of putting it into the filter area and taking a parameter. That would give the author the ability to control how much, similar to shutter speed, maybe even exactly like shutter speed. I also like Amelia's suggestion. Consider
same hehe 😄 I'd love to see us be able to implement all 12 Disney principles of animation with ease, that would be amazing. Hope I covered everyone's comments! Love them, keep em coming. I want to throw one more scenario out there, food for thought, which is if motion-blur was applied to an element being dragged around. It would be fun and neat, but also a great cover up. We're often super obsessed with 60 (or even 120!) fps these days because of the delays of the items attached to our finger. Motion blur would likely pacify many of those uncanny visuals since the blur can help any dropped frames or uncanny stickiness. I think there's more fun to be had with this css property than outlined in the tiny statement above, as well as more utility than is outlined. |
That's very similar to the proposal from w3c/fxtf-drafts#50. I definitely still support having the ability to specify more complex blurs in the filter property. But what is distinct about @argyleink's proposal here is that the blur would be calculated automatically based on the device's frame rate and the actual differences from one frame to the next. The author wouldn't need to figure out how to animate the amount of blur and its direction to match up with the speed of the motion. That kind of automatic calculation doesn't really make sense in
I agree with Adam, that we should probably not think of this as a "global" setting, but as an effect targeted to a specific element that represents a moving layer. In other words, the property wouldn't inherit, and it would only have an effect if the same element is moving around. …which basically answers one of my own questions: this should be solely about transform-like properties (aka, transform, the individual transform properties, SVG viewBox, and the motion path properties) and not about properties that change the paint rendering of the layer. |
@AmeliaBR What about |
Yeah, this is about movement specifically; while there are probably variants of motion blur that can do stuff with color, the traditional and widely-understood definition involves tracking how a given pixel moves between frames (calculated from the movement of the object and/or the movement of the "camera", so a pretty easy and quick bit of vector math), and then applying a blur along the direction of motion, proportional to the between-frame velocity. The only thing in CSS that gives us that sort of tracking ability is tying it to the animation of 'transform' (and its family of properties) specifically. Luckily, that's also the common way to move things around, particularly in situations where you'd want motion blur! |
What's special about |
@AmeliaBR Though I'm skeptical about css motion blur in general, I'm not sure what your response means in regards to my question "Could motion blur in some sense be tied to the frame rate alongside the speed and direction of scrolling in backdrop-filter (or elsewhere)"? |
Sorry, didn't read your comment closely enough! And I'm still not sure what you're asking about But, I do think that it's worth considering "translations caused by scroll" as one of the transformation-like motions that could trigger motion blur in the compositor, if the scroll-container has the motion blur property turned on. |
agreed, scroll blur could be pretty neat. they're translated and in motion. @jonjohnjohnson i'm also unsure of what you're asking for regarding backdrop-filter motion blur. if i'm tracking correctly, you're curious if the speed of the elements moving beneath a backdrop-filter could affect the amount of blur coming from the backdrop filter? like, you want to leverage the amount of blur coming from the speed of movement and apply it elsewhere? that makes the most sense to me, but it's not motion blur related imo. the whole point here being pixel by pixel getting a blur, not a layer getting a blur. in the rotation example above, the elements at the end get more blur than those in the middle. how would you want to use that blur mesh in backdrop filter? it's not a single value you can just apply. am i understanding correctly the ask? |
@argyleink Yep, that's exactly question was about and @AmeliaBR answered it when she spoke of "translations caused by scroll". Pixel by pixel still applies even if not rotating. Your example could just be translating in a single direction and instead of a staggering discrete paints of the same block, you'd maybe want a motion blur based upon speed, no? This is all I was asking about. Scroll related motion blur that takes into account speed, direction, and frame rate, not simply "a layer getting a blur". And since I've seen some nice effects with backdrop blurring, like I mention from the use of navigation on apple.com, I'm simply wondering peoples thoughts in being able to use that alongside motion blurring for content moving via scrolling mechanics, not just transform. |
There are many different variations of motion blur. Would the specification require everyone implement the same algorithm in all cases? Motion blur is often added for offline rendering. For real time cases, would it be acceptable to drop the frame rate in order to add motion blur? How would you specify this in CSS? |
@grorg We give implementations flexibility in picking the algorithm for simple blur, so I don't think we'd want to be any more specific for motion blur. If we approach the property as a rendering hint, rather than an explicit style rule, then implementations would be able to use their own heuristics to decide the trade-off between frame rate and blur. But maybe there could be two keywords, one for "motion blur, please, if it doesn't slow you down" (i.e., the usual request, to smooth out an animation) and one for maximum blur effect (i.e., if the blur itself is part of the design). |
I'm assuming we'd just have a "none" (the default) and a "please, if you can" value, with the latter being defined by a general description but leaving the precise details up to the browser (including "no blur" as a valid implementation of the value). |
to recap some of the conversation and attempt alignment, here's the syntax I feel we're converging on: .animated-layer {
animation: rotate-forever .5s linear infinite;
motion-rendering: blur; /* inherit | initial | auto | none | blur */
/* throwing shutter angle in, would love to have it, but feels like a complexity multiplier */
motion-shutter-angle: 180deg; /* inherit | initial | auto = 180deg | 0deg - 720deg */
}
@keyframes rotate-forever {
to {
transform: rotate(1turn);
}
} what tweaks would you like to see to the above? |
That looks good to me. Other key points from the discussion, as I understand it:
Next step would be to get feedback from implementers on how easy/hard this would be to implement & whether they're likely to do so if it gets spec'd. |
@AmeliaBR & @argyleink I know my questions about scrolling might not be about the most common cases, but here's a quick demo/gif to aid in understanding my crazy talk. From left to right, imaging the scrolling with smearing/blur based upon direction/speed.
|
The linked gpu gem uses a trick for calculating motion blur where the previous camera position is used, however the proposal here is about the element's motion which isn't global across the scene. This likely adds complexity to the implementation as we'd have to know for each pixel the motion of the object at that pixel within the scene. Scrolling motion blur might be simpler, though we still have to know which parts of the scene are elements which do not move with scrolling (i.e. |
some interesting points about motion blur and it's usefulness from Apple (starts at ~19m) https://developer.apple.com/videos/play/wwdc2018/803/
|
If we target a specific element/layer, I think we could expose a previous transform (e.g. 1/60th of a second ago) which would enable a shader to compute the previous location of that pixel and blur along that direction vector. Of course for spinning things this wouldn't quite be right (blurring across a line rather than an arc) but the error in most cases might not be too noticeable.
I suspect that we will need to force a compositor layer whenever the blur is applied. This is similar to opacity where because the shader relies on colors from the buffer it will require a rendering pass when applied to multiple layers. Right now opacity is in this strange state where we force a stacking context when it's not 1 but this is often surprising for developers as the stacking order of items changes when you start animations or change opacity. I think always flattening would be less surprising. |
No, to be clear, the proposal is that motion-blur could be ignored (no blur applied) if it's applied to an element that isn't a composited layer. |
The CSS Working Group just discussed The full IRC log of that discussion<emilio> topic: motion blur<astearns> github: https://github.com//issues/3837 <emilio> argyle: motion blur is a pretty standard animation strategy <emilio> ... it can add a nice polish, and in my experience I got requested to introduce motion blur in a bunch of places but I couldn't <emilio> ... so I wrote a spec and introduced and try to get interest <emilio> ... it'd only work on accelerated layers and the engine would track what to move and what not <emilio> ... and it's something you cannot get with other blurs and only the graphics engine can do <emilio> ??: I love this idea, go for it <emilio> argyle: (describes the syntax) <astearns> s/??/chris/ <emilio> ... we added two properties, motion-rendering (since we may want other effects in the future), and motion-shutter-angle, so avoid blurriness if stuff is moving too fast for example <emilio> AmeliaBR: we did have discussion in the issue about potential simplifications so what we have no is "you turn blur at a default value", or an explicit request of not, and one of the things that we thought would be a restruction of this it'd be that it doesn't have side effects (doesn't create stacking contexts / containing blocks) <emilio> ... another thing is that it doesn't need to be restricted to transform motion, but also scrolling and such <emilio> ... maybe we'd want to determine whether to blur one or not the other <emilio> astearns: I don't think the "doesn't force layers" is the right thing for authors <emilio> AmeliaBR: that means we can't force defaults <emilio> myles_: the UA knows what's moving <emilio> ... right now this is unimplementable on WebKit <emilio> ... if we did we'd do it in CoreAnimation <emilio> ... and it'd be a default in the platform <emilio> ... I think we all agree that motion blur is better <emilio> ... so if browsers want to implement motion-blur they should just do that <emilio> flackr: I think that not everything that moves can be blurrable, you may animate properties that depend on layout <emilio> myles_: and perf would be terrible, that's a non-starter <AmeliaBR> s/can't force defaults/can't use auto as a default, because it would also have the side effects/ <myles_> I don't understand why this has to be configurable <AmeliaBR> q? <emilio> argyle: It'd be interesting if the UA stylesheet would have it as a default, and that would require not changing side-effects <emilio> AmeliaBR: so re. whether it should be configurable, I think it may not always so performant and some things are more important to blur than others, and there may be use-cases for not having motion blur <astearns> ack dbaron <emilio> myles_: I think the engine could have different heuristics, you probably dont' want to blur scrolling with texts <emilio> dbaron: I think the point about animations that depend on layout or otherwise don't run in the compositor is interesting <emilio> dbaron: if we really are going to want interop, there's a bunch of animations which you cannot define in terms of pixel moving <emilio> ... and there's a bunch of intermediate edge-cases around <emilio> ... you may think you're moving pixels, but it may not hit the compositor in some or other browsers <emilio> ... so depending how much interop we need on this figuring out when it needs to apply may be pretty complicated <emilio> flackr: I think that's why the proposal says it's optional, we probably don't need a lot of interop here <emilio> AmeliaBR: its name matches the other -rendering properties which are just requests to the UA <emilio> ... another approach is defining it as a filter effect in which case it'd do all the compositor <emilio> myles_: a spec can't say "do motion blur if you can", what about things like WebRender? a spec _has_ to be more clear than that <emilio> AmeliaBR: I think that's why the only thing the spec says is that this property doesn't force a layer <emilio> myles_: and then authors which don't know about stacking contexts are going to be surprised when it doesn't work most of the time <emilio> myles_: right now if you put a blur on anything it works <emilio> AmeliaBR: so is the mood of the room making it work like filter? <emilio> astearns: it looks like so, but probably browsers should try to implement some sort of motion filter on their own by default, and see if the configurability is a requirement <emilio> AmeliaBR: volunteers? <emilio> ... I think then argyle is on their own to poke at the Chrome folks <emilio> majidvp: one question: can you actually blur using two subsequent frames or do you need more frames? <emilio> ... because that can have impact on implementability <emilio> myles_: the topic of motion blur is under active academic research <emilio> flackr: the proposal doesn't blur frames but blurring across the object's motion <emilio> ... as far as I know we're not doing anything like this r/n but it could be done <astearns> ack dbaron <emilio> myles_: maybe we should delay putting this in a spec until there's at least one implementor interest <emilio> dbaron: blurring something that isn't a stacking context / fixed-pos containing-block would be interesting <emilio> AmeliaBR: (repeats the two proposals (1) making it work like filter and (2) only apply the blur only if it would not require side-effects) <emilio> myles_: (2) cannot be the behavior because we can promote on demote stuff to layers however we want <emilio> myles_: we'd break websites if they could rely on that <emilio> astearns: so it'd be interesting to see which use cases can be covered with (1) <emilio> ... and see whether it'd still achieve what the author wants <emilio> iank_: one last point from our graphics engs. is that there if you're forced to promote these things to layers then running on out-of-memory is super-easy <AmeliaBR> q? <emilio> myles_: other option is "don't do the motion blur if you can't", and in that case having this in the system compositor may be the best option <AmeliaBR> scribescribe: AmeliaBR <AmeliaBR> emilio: The second proposed behavior (no side effects, only if possible) that's not enough. There are compositor layers that also have fixed pos children. But forcing a motion blur will be expensive computationally. <emilio> AmeliaBR: so I think tasks are coming with a revised proposal where it forces the same side-effects as filter and such, and maybe try to get someone from chromes compositing team and try to gather interest |
From 2015, here's a nice motion blur effect (simulated with svg filter on x) https://tympanus.net/Tutorials/MotionBlurEffect/, feels nice |
was thinking last night that a shift in the proposal syntax could help shift some of the effort and expectation from the feature. current proposal syntax: .animated-layer {
motion-rendering: blur;
motion-shutter-angle: 180deg;
} updated proposal syntax i was thinking about last night: .animated-layer {
transform-filter: motion-blur(180deg);
/* or maybe? */
transition-filter: motion-blur(180deg);
} what i like is that ambiguity is gone due to more specific syntax: |
This syntax suggests that there are other types of |
yep, from the above thread folks have expressed desire to leave the syntax open to effects other than motion blur, which influenced the syntax to its current state of another value add of this adjustment to transform-filter: motion-smear(10%) motion-blur() pixelate(50%); i'm making things up in there, but that's what's nice, future additions can show up and travel down a paved path. |
One consideration I would like to add: Shutter angle alone will make the motion blur inherently frame rate dependent and therefore potentially device specific. We know that most devices run at 60fps, but there are some 90Hz, 120Hz or even 400Hz screens out there. Just defining a shutter angle and using the device’s native frame rate will yield drastically different visuals depending on the screen they are shown on. Another side of the same coin: Motion blur is often used to achieve a certain aesthetic. For example, there is the concept of “cinematic” motion blur, which is what you get when you shoot a movie at ~25fps with a shutter angle of 180deg. That aesthetic is unachievable if you can’t define a target frame rate. I’d love for this proposal to somehow solve this. I am not sure if just defining a target “emulated” frame rate would be sufficient or if it would just make things look weirder. I do know that some modern digital cameras are able to shoot at 60fps and add “cinematic” motion blur as a post-processing step. I’d love to get some insight from someone with cinematography knowledge here. |
Couple of thoughts: What happens if a child and parent animates? Maybe If the animation loops, does the element blur from its end position to its start position? Eg:
What happens with stepped animations? Would they blur at all? |
You could deal with the looping cases by getting the developer to provide keyframes beyond the start and end of the animation: @keyframes square-spin {
-100% { transform: rotate(-0.25turn); }
from { transform: rotate(0turn); }
to { transform: rotate(0.25turn); }
200% { transform: rotate(0.5turn); }
} In this case a solid square rotates in a way that looks constant, even though it's only rotating 1/4. By providing -100% and 200% values, the blur would look convincing. Edit: If the user doesn't provide these out-of-bound values, I suppose the browser could figure it out if the easing is declarative. But it feels like there are cases where it might not be possible, eg with animation worklets, and path-based animations. |
looks like Lottie is trying to help folks get motion blur onto the web, they deliver the ux via wasm and a box blur. it's not that great of quality, and comes with some baggage, but has motion designers around me excited. |
@argyleink the Skottie implementation linked above is not based on box blur, but on frame averaging: we sample multiple frames on the timeline and compute the result my modulating/blending these frames. You can see the effect in action here: https://skottie.skia.org/718e3d0979791b0c268efe68c10056a6?h=500&w=500 This is pretty close to the physical model, and also what AE appears to be doing (there's a separate Pixel Motion Blur effect which computes inter-frame per-pixel motion vectors, but this is about the basic MB switch). This approach has a couple of nice properties:
The downside is obviously a multi-frame buffering requirement. |
pasting this here as another reference https://www.motionblurjs.com/ i particularly was interested in the distinction between motion blur vs motion fade |
here's motion blur mocked with some animated box shadow trickery https://codepen.io/michellebarker/pen/povdXRW |
Why
Professional polish of motion graphics often includes the application of motion blur. In most cases, it's a boolean toggled at the layer level, that then tells the engine to set a blur amount based on the speed of the pixels. This effect makes animations much closer to real life, among other nice benefits. CSS currently is incapable of such an effect. Instead, a strobing, ghosted type effect is often what we get instead.
Motion blur, as is found in motion graphic tooling like After Effects, is not possible with current filters because each pixel is evaluated, not the entire layer. Each pixel is evaluated for velocity and blurred contextually. CSS blur() can only apply to the entire layer.
Use Cases / Contexts/ Value Props
Example (cylindrical motion)
No motion blur (pardon 15fps gif quality..)
With motion blur
Strobing effect found on the web today: Codepen
Proposal
The text was updated successfully, but these errors were encountered: