48 comments

[ 1.9 ms ] story [ 114 ms ] thread
After looking at the code, not sure if I would use the word 'simple'. Well done.
Crashes the whole phone if I run it under Firefox on Android. I should probably report that, any crashing bug is a potential security vulnerability.
Sorry about that. I wrote the web code quite sloppily, and it was my first time. I just wanted to port my native C++/OpenGL code to the web.
Not your fault. If it crashes the whole phone, that's a bug in Firefox and/or Android. A Web app should never be able to crash the browser, and the browser shouldn't be able to crash the phone.
Tastefully done! The one thing about motion blur I've seen is almost everyone overdoes it. You got just about the right level where it looks natural and not gaudy.
Thanks. :)

It's likely because I don't fake the motion blur effect as it is most commonly done (nothing wrong with that, I'm just describing it). Instead, I calculate what your eyes would realistically see. I render the triangle with a non-zero exposure time (the exposure time is equal to the duration of 1 frame).

There are definitely some shortcuts and approximations taken (I don't compensate for how CRT/LCD displays display images, no colour correction, etc.), but the "big picture" is 100% based on real physics.

The motion blur is calculated with the assumption you keep your eyes still. If you track the moving square, then by definition there should be zero motion blur (if your display were perfect). However, it still looks okay with motion blur even if you track the square.

> but the "big picture" is 100% based on real physics.

Having implemented motion blur numerous times, this is actually super interesting to me. However I was reading through your source-code and was having a hard time following along. Any chance you could explain what the physical models you are basing your algorithm on and how that ended up translating to code?

Thanks.

(comment deleted)
You can fake gamma correct blending quite cheaply in the fragment shader. Just square the RGB values before blending them, then sqrt the result before storing it. The visual impact is significant for fast moving items, there's a higher continuity of motion.
Looks good. Shocking amount of code to achieve that effect though.
its actually pretty "short" me thinks.
How does this work? It's way too fast for me to see anything, other than that it looks great; what is the difference between this and, say, drawing a lots of transparent rectangles lerped between current and last position?
It's simple conceptually: I just draw a quad with non-zero exposure time.

For each pixel, I calculate how much exposure it receives during the last 1/60th of a second (assuming it runs at 60 FPS). So, if a pixel is backed by the triangle for 100%, it gets the full colour. If it's only 24% of the time, then it's 24% of the full colour, etc.

That's what happens conceptually. In order for it to run faster, I have to optimize the solution and basically calculate the same result, but by drawing some triangles and calculating some distances... It's hard to explain, but it's nothing more than an optimization.

You can make it look even better by adding support for shutter (in)efficiency: http://www.dctsystems.co.uk/Text/ShutterPresentation.pdf resp. http://www.dctsystems.co.uk/Text/shutter.pdf
This is very interesting. I'm very curious how this relates to the human eye.

I remember playing around with adjusting something similar to this, but it was mostly to compensate for how monitors display images.

Shutters with an efficiency between 75% and 50% just look more natural, from my experience.

The stuff proposed in this papers made it into blockbuster VFX production renderers ca. 2005 (3Delight) and 2007 (Pixar's PhotorRealistic RenderMan).

There is no information available on what full CG features use this. However, when you look at a still frame that exhibits heavy motion blur in isolation, you can usually tell right away if a perfect of imperfect shutter model was used. The latter looks smoother/more natural.

As far as VFX in live action films go: it makes sense to match the virtual shutter to the one of the camera that was used to shoot the footage the VFX need to be integrated with.

The high end offline rendering plug-in, my company produces, has a setting for this. The default we use (and that most of our customers leave untouched, I believe) is 75% shutter efficiency.

I've written about an unexpected outcome I've learned from this demo.

http://shurcool.wordpress.com/2011/10/06/the-effect-of-motio...

It does a lot to explain the discrepancies we often see when people argue "you can't see more than 24 frames per second" vs. "I can tell 60 vs. 120 fps".

It matters how DISTINCT the frames are.

Contrast definitely matters. The highest fps experiment that I've heard of was a researcher who had people dart their eyes left and right while looking at a strobing LED. They saw separate dots instead of a continuous line at strobe rates of up to 1500-2000Hz. That's probably the top-end of visual detection for a high-contrast, high-motion video.
I was actually thinking about motion over the past few days. High frame rate does matter, but it's for a different reason. Human eyes can track objects extremely well.

Here's a simple test to do with the demo. Try tracking that motion-blurred cube on the left with your eyes - it's all blurry. Now, try tracking the one on the right - it will be sharp, but "jumpy". Now, try tracking the one on the right with your 120Hz monitor - the motion should be MUCH smoother - and that's where the need for high frame rates comes in. The higher the frame rate, the better the object will look when you're tracking it with your eyes.

Ideally, if we only account for objects travelling across the screen in 2 seconds, and a screen is ~2000 pixels wide, and we want to have an error of <=1 pixel, then theoretically, we need (2000px)/(2sec) = 1000 Hz frame rate for high motion realism. Unfortunately, I don't see it coming anytime soon...

So if the screen is really dense, say 20000px wide, you would need a 10kHz refresh rate. That contradict the contrast experiment.
In order to keep the increase in sharpness that you get from 10x the pixels - yes, you would need 10kHz, 10x the refresh rate. The moving picture would look sharper than the moving picture on the 2000px display. If you use 1000Hz refresh rate, then the crispness of moving objects on the 20,000px display would degrade to approximately the crispness of the 2,000px display. I hope that made sense.
This is a very good point, depending upon speed there's really no upper limit to the frame rate necessary for 'smooth' motion.

Also it's very, very annoying that Firefox is limited to 60Hz, that's very short sighted in my opinion.

Have you tried reducing the frame rate in the demo to see if the same effect is true for 30 fps as well?

Also, I wonder if a simple square is enough to prove the "sameness" of motion blurs across different framerates. A fast camera pan across a landscape may yield different results.

Gives an alert as soon as I run it: 0:15(87): error: Arrays cannot be out or inout parameters in GLSL 1.10

Firefox 18 on Linux, with WebGL otherwise supported.

Doesn't this only work because the square is a uniform color?
Yes, the existing code could not handle overlapping objects of different colours, nor textured objects.

However, in theory, the technique and code can be extended to handle those cases. It's just more demanding computationly-wise.

Adding overlapping objects of different colours is somewhat easier (but still hard) than adding textures.

Feels great to my eyes. The non-blurred square looks far choppier and eye-straining by comparison. Would love to be able to easily add this effect to CSS3 animations since it'll probably be awhile (3-ish years?) before WebGL is more commonplace.
I thought so too, so I wanted to experiment with applying the same type of (physically-accurate) motion blur to scrolling text.

Screenshot: https://dl.dropbox.com/u/8554242/dmitri/projects/Conception/... Source: https://github.com/shurcooL/Conception/tree/motion-blur

I've realized the effect in motion looks quite nice, but it HAS to run at full 60 FPS at all times. If there are dips in the framerate, the effect is horrible (partly because the 16.66 ms number is hardcoded rather than calculated). My implementation is very naive and not optimized, but it funs well with a dedicated card. Not so much with Intel 3000. It was just a mockup so I didn't develop it further for now.

Great demo!

This is probably obvious, but for the first time it occurs to me that motion blur is essentially the same as anti-aliasing. They are eye-tricking hacks to work around a lack of resolution in the medium -- screen resolution, in the case of pixel anti-aliasing, or "time" (framerate) resolution in the case of motion blur.

Recently I've been wondering if as very high-resolution displays become commonplace, anti-aliasing will become obsolete. If I could play an FPS video game on a 500dps monitor, would anti-aliasing make any perceptible difference? At some pixel pitch, even text anti-aliasing won't matter.

The same thing seems to apply here. If we had 5000Hz screens (and could run our animations quickly enough to keep up), would applying artificial motion blur buy you anything?

Those are some extremely insightful and promising thoughts that deserve more research. If you venture more in those explorations, I'd love to read thoughts you have :)
Disabling anti-aliasing is already recommended as a method to increase FPS on the Retina MacBook Pro for precisely that reason... unfortunately, the details still look ugly if you do that. Non-antialiased text also looks quite decent and is nice and sharp.
Could you do this with the system mouse cursor?
In an open source operating system, it could be done.
Well done and nice to see that some understood that motion blur is more important than just high fps.
If there's enough interest, I can share the original C++/OpenGL code (with Xcode project in latest version, MSVC project in older code).

The problem is that I doubt the code has much value, because the C++/GLSL code does a very poor job of communicating the higher-level abstractions that are going on, and the documentation is nonexistent because I was just doing it as a demo.

In other words, it's not very reusable nor is it easy to learn from. :( Its main value is the running demo.

This problem is one of the things that inspired me to work on my current project which tries to make code/functionality/value more reusable by default (i.e. with less extra effort on your part).

On MBP i5 works in Firefox but shows white screen with no console errors in Chrome.
That's strange, I developed it by testing in Chrome first, Firefox second. It has always worked for me in Chrome on all computers I've tried. Which version of Chrome do you have?
Chrome 24.0.1312.57 on OSX 10.6.8 MBP i5.

I've had crashes and blank screens running some ROME demos in Chrome here. Pretty sure it's the fancy shader use.

That's the exact same version of Chrome I have running on my 2011 MBP with 10.8.2. Either there's something up with your video card, Chrome install, or maybe Snow Leopard is to blame (no idea why).