alexk111 / SVG-Morpheus

JavaScript library enabling SVG icons to morph from one to the other. It implements Material Design's Delightful Details transitions. (THIS PROJECT IS NOT MAINTAINED ANYMORE)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Why the morphing is so ugly?

Emasoft opened this issue · comments

Why the morphing/tweening is so ugly?
For a better morphing algorithm you should check this article:
http://tympanus.net/Development/AnimatedSVGIcons/

It uses Snap.svg with the following code:

myIconName : { 
    url : 'svgs/myIconName.svg',
    animation : [
        { 
            el : 'path:nth-child(5)', 
            animProperties : { 
                from : { val : '{"path" : "m 61.693118,24.434001 -59.386236,0 29.692524,19.897984 z"}', animAfter : '{"stroke" : "#000"}' }, 
                to : { val : '{"path" : "m 61.693118,24.434001 -59.386236,0 29.692524,-19.7269617 z"}', animAfter : '{"stroke" : "#444"}' }
                } 
        },
        { 
            el : 'rect:nth-child(3)', 
            animProperties : { 
                from : { val : '{"transform" : "t0 0"}', after : '{ "opacity" : 0 }' }, 
                to : { val : '{"transform" : "t-10 -10"}', before : '{ "opacity" : 1 }' }
            } 
        }
]
}

The "path" element that you see in the above code is just the content of the svg file, as explained in the text of the article:
http://tympanus.net/codrops/2013/11/05/animated-svg-icons-with-snap-svg/

Why does your library seem to interpolate the shapes incorrectly?

@Emasoft Thank you for the question and the example. SVG Morpheus does interpolate shapes the same way as snap.svg . The only difference is the paths from the example above were specially prepared for morphing between each other. SVG Morpheus demo uses paths as-is from icons not optimized for that purpose. I'm going to make an optimized icon set soon, for a perfect morphing demo :)

I'd use the icons.
I don't understand what's uncool about standard icon libraries, I see it done all of the time.

@Emasoft I am sorry but I think your point of view does not represent everybody else's. Nevertheless, algorithms you've provided seems to work well with similarly formed shapes, but there is no information how well they perform if the shapes differ significantly. I think that every morphing algorithm has it's weaknesses.

@alexk111 maybe it is a good idea though to provide users with multiple morphing algorithms? Or - even better - a convenient way to extend library with new ones? I believe it would involve moving morphing algorithm to separate function and providing config option to extend/change/overwrite it?

I've contacted an expert on the field of shape morphing, Uddipan Mukherjee.

Uddipan Mukherjee
University of California, Irvine, CA
email: umukherj@ics.uci.edu

His paper presents one of the most advanced morphing algorithm, because it can morph even self-overlapping curves:

http://www.ics.uci.edu/~gopi/SamplePubs/Tweening.pdf

Here are some videos of the morphing algorithm at work:
http://youtu.be/EHBdTD5EA6M
http://youtu.be/0DDC3fbwtIw

If he answers my email maybe he will help us improve the algorithm.

I am not very familiar with svg, but is there a1-1 correspondence between the 'from' and 'to' curves ?
I understand, right now it is a simple interpolation between the two path specifications, but do these paths have same #points?

Welcome Uddipan! Thank you for being here!
The svg paths can have a different number of points, and even being a different kind of bezier curves, specifically:

  • Cubic Bézier (C, c, S and s)
  • Quadratic Bézier (Q, q, T and t)
  • Elliptical Arc (A and a)
  • Straight Lines (The M indicates a moveto, the Ls indicate linetos, and the z indicates a closepath).
    See: http://www.w3.org/TR/SVG/paths.html#PathData

@Emasoft thank you for contacting Uddipan!

@uddipan Hi Uddipan. Thank you for joining!
Currently it normalizes all paths by turning them into Cubic Bezier and making the # of points equal between the 'from' and 'to' curves. After that it just simply interpolates the points' x1, y1, x2, y2, x, y values.
Also a single path element may contain several sub-paths and it will render shapes depending on the fill-rule parameter (http://www.w3.org/TR/SVG/painting.html#FillRuleProperty). For example: http://jsfiddle.net/alexk111/f2ex69za/2/

If you interpolate the curves only, it will give rise to unwanted intersections and produce an unintuitive tween for closed shapes. A better approach is to find a correspondence between the interiors of the shapes and interpolate that. e.g. if you consider the two shapes as piecewise linear, you can triangulate both and find a correspondence b/w the triangles and eventually interpolate the triangles. Can something similar be done here?

@uddipan Sure it can be done if you help us with the algorithm. How can we triangulate a bezier curve into a piecewise linear and interpolate the triangles? Even if you quickly sketch us some lines of pseudocode it would be of great help.

You can try adding points at close intervals on the curve to make it 'almost' piecewise linear. Then any standard triangulation algorithm can be applied to the enhanced set of points

@uddipan What triangulation algorithm you suggest for the best results? Results in your paper shows that your novel triangulation algorithm quantitatively produces a much better morph when compared to the those produced by an arbitrary triangulation. Can you sketch us your triangulation algorithm in pseudocode?

for best results you can use Constrained Delaunay triangulation, or sorted ear clipping (details can be found here http://www.cosy.sbg.ac.at/~held/projects/triang/triang.html). The latter is faster and easier to implement. The idea is to choose the best possible triangle (the one whose angles are not differing much) at each step.

@uddipan What do you mean by "constrained"? What are our constrains? Consider that we need to morph not only closed paths, but also open paths.

For example: is the following a good implementation of the delaunay triangulation?
https://github.com/ironwallaby/delaunay
Or we need something different?
Here is a svg triangulation js library with another implementation:
https://github.com/mattdesl/svg-path-contours
Are those two constrained or ear clipped?
The ones explicitly labeled as constrained are those:
https://github.com/r3mi/poly2tri.js
https://github.com/jahting/pnltri.js
But I can't tell if they use the ear clipping method.

In simple terms constrained means not allowing certain edges as they intersect the original triangulation.
This may be helpful
http://www.geom.uiuc.edu/~samuelp/del_project.html
I am not sure what the links you provided do, some pictures would certainly help.
Also, note that for open paths, triangulation is not even defined, you may need to think of something else in those cases.
This paper may help your case too....you can go through this
http://ftp.cs.arizona.edu/~kobourov/gmorph.pdf

This is still an issue. During the morphing the vertices should not intersect with the segments when moving to a new position.

@uddipan Is this triangulation algorithm the right one?
https://github.com/mattdesl/svg-mesh-3d
Watch the demo here: http://mattdesl.github.io/svg-mesh-3d/

Morphing is going to be BIG very soon. Greensock has in beta a morphing plugin, but I don't think the algorithm is capable to avoid self-intersections of the shapes yet.
Video: https://t.co/ndOAjLLd82
@alexk111 : You should take the lead with SVG-Morpheus!

looks correct. How is this different from shape tweening used in Adobe Flash ?

SVGMorpheus just as Snap SVG / Raphael works great if your paths are handmade prepared for tween animation, or else the animation seems 'unnatural'.

However there is only one script to do that, and that is GSAP morphSVG plugin, it can even shift the bezier to your heart's desire with it's shapeIndex feature.

I also managed to get the cross-path processing to the point where animation happens without any error, but I haven't found yet a way to eliminate the ugly factor.