dalboris / vpaint

Experimental vector graphics and 2D animation editor
http://www.vpaint.org
Apache License 2.0
728 stars 54 forks source link

Improve SVG import/export #9

Open Emasoft opened 8 years ago

Emasoft commented 8 years ago

Wow, this is really going to change the way vector animations are done! But please support the SVG file format instead of limiting yourself to the VEC format. You need to make your application able to communicate with the world of graphic design. All you need is to save frames as SVG files or as SVG SMIL animations and to import vector images as keyframes. The SVG file format is an open standard widely used, and the accepted standard for vector images.

We need four options:

  1. IMPORT SVG FILES: I want to create the animation keyframes in Inkscape or Adobe Illustrator, for example. And then importing them in VPaint to create the interpolation frames.
  2. EXPORT ALL FRAMES AS SVG FILES: I want to be able to use the resulting animation everywere. The file format of vpaint VEC is not supported. I need the option to save the SVG frames generated by vpaint, using a framerate and a duration of my choice.
  3. EXPORT ANIMATION AS SINGLE SVG SMIL FILE: You can also use the SMIL language included in the SVG 1.1 specifications to save the entire animation in a single SVG file, interpolating keyframe by keyframe, as you can learn from here: http://fettblog.eu/blog/2013/07/16/basic-svg-path-tweening-with-smil/
  4. LOAD BACK THE SVG SMIL FILE : I want to be able to reload and modify the SVG SMIL animation I just saved. You can also playback the SMIL file inside the editor to check if it is fine, using some SMIL player open source like this: http://ambulantplayer.org

Please add support for SVG if you want your app to become popular and used in real world applications (from websites icon animations to cartoon movies).

P.S: You can also consider the option to integrate vpaint in Inkscape as a Plugin. It would be awesome. There are already some morphing plugins, but they are so primitive to be useless. Yours, instead, will make a true revolution, and people using Inkscape will start making SVG animations immediately and making your app very popular. Here is a proposal I made some time ago for a SVG animation plugin for Inkscape: inkscape onion skin multipage feature proposal

scribblemaniac commented 8 years ago

I think files should not be saved as an svg. It would be much more limiting than the custom vec format. Since this program operates differently from most other vector based editors, it is likely that new features will be added that are not supported by traditional svg file format. Off the top of my head an example would be support for interpolation curves with the motion pasting feature (something like blender's ipo editor), which I can't seem to find any documentation for a similar feature with SMIL.

Having said that though, we definitely need all of those import/export options that you mentioned.

Emasoft commented 8 years ago

I'm pretty sure you can emulate the "motion pasting" feature using SMIL. You need to cut/modify some paths, and add additional keyframes not present in the VEC file, but you can reproduce them. VEC will always be a more powerful format, but in the end graphicians will need SVG SMIL. It is like for Photoshop: of course you work internally with PSD, but when you have done your final product is a PNG. And SVG is for vector graphic what PNG is for bitmaps.

scribblemaniac commented 8 years ago

I absolutely agree that there should be an import and export for svg files, however I thought you were suggesting that it should replace the vec format, which is not something I agree with. Based on your latest response, it would seem that I simply misinterpreted what you were saying.

dalboris commented 8 years ago

Hi Emasoft, thx for all these suggestions! Here is my point of view on this issue:

Import/export SVG

First, just to be 100% clear on this point: I will not use SVG as the base format of VPaint. It's going to stay VEC for a variety of reasons, the most important is that unfortunately, the data structure I'm using on VPaint cannot at all be emulated with SVG or SVG+SMIL as you suggest. This is the reason why I have created a new format in the first place (otherwise, believe me, I'd rather use an existing format than having the hassle to create a new one). And unfortunately, SVG is not going to be able to support anything close to what VPaint supports in the foreseeable future. :-(

That being, I -do want- to make my best importing SVG, and exporting SVG, as it is absolutely critical for adoption. All I'm saying is that there is no way you can export in SVG (or SVG+SMIL), then import it back in VPaint without losing most of the information that makes VPaint useful, i.e. you'll basically lose the features that make you like VPaint in the first place.

The point is, here is a reasonable workflow I'd like to support:

  1. Do initial design in Inkscape/Illustrator/Whatever, export to SVG
  2. Import in VPaint, do most of the animation there, export to SVG
  3. Possibly, import the SVG in another software, and do post-anim cleanup / styling, export to SVG or raster video (.mp4, etc...)
  4. Play in browser / video player

But here is a workflow I'm not going to support, not because I don't like it, but because it is technically impossible: Going back and forth between VPaint and another software using SVG

Plugin in Inkscape

I'm not going to develop for Inkscape, first because I don't want to develop under the GPL (which I believe is the worst thing that happened to the open source world, but I'm not going to debate on this here), but also because it would be way too constraining. I need the freedom to design the interface of VPaint as freely as I need to support the workflow that makes VPaint unique. Building around Inkscape which is not designed for animation is not something I want. That being said, don't get me wrong, I love Inkscape. It's truly great, one of the best software I know (including commercial), and I'm using it regularly. Even if Illustrator was free and running on Linux, I would use Inkscape 90% of the time.

But if someone else wants to develop this plugin, go for it! It is possible to copy-paste the code of VPaint and plug it into Inkscape, as the license of VPaint is less restrictive as the one of Inkscape. Note that you cannot do the other way around (use Inkscape code in VPaint).

blurymind commented 8 years ago

I dont think that SVG file format's animation capabilities are mature/mainstream enough to be supported by a vpaint exporter. I never export animation to svg.

If you want to be compatible with other software (toonboom), you would need swf or fla - proprietary formats.

This is where VEC can become a mainstream open source vector animation format.

Importing svg as a single frame could be useful

dalboris commented 8 years ago

Yes, you can actually already export a single frame as SVG, even though it's pretty crappy as of now.

Emasoft commented 8 years ago

Thanks for your answer @dalboris !

  1. About the format: I agree that the native format should be VEC. Exactly like Photoshop uses PSD. But you must aim to the end product, and the end product of your work would be (almost) always SVG SMIL, exactly for the same reasons that 99% of the output of Photoshop in the end is a PNG file. I hope that VEC can become a new standard and popular open source Vector image format, but don't get your hopes too high. Imposing a graphic standard is something that requires money and power that only big corporations have. It is not by chance that in the last 15 years the only new vector image standard to impose itself was SVG. It was backed by the big corporations of the web. And even with that, it was a nightmare to reach a consensus. Try to be realistic, and always consider SVG a first class citizen of your app if you want it to matter in the real world.
  2. About the SVG workflow: I think that your workflow is enough most of the time, but you need to consider that in the real world the animation produced by VPaint would be used mostly in those areas:

70% - Web Icons and UI Animations 15% - Mobile App UI Animations 5% - MP4 Movies/Cartoon Animations 10% - Others

If you want VPaint to become popular, you should go where the higher demand is: the web. Animated SVG icons and UI are now very popular, but very hard to do (until now). See for example the following examples: http://tympanus.net/Development/AnimatedSVGIcons/ http://tympanus.net/Tutorials/BorderAnimationSVG/ http://tympanus.net/Tutorials/SVGLoaderGSAP/ http://tympanus.net/Development/TextInputEffects/index2.html http://tympanus.net/Development/ClickEffects/ http://tympanus.net/Tutorials/ShapeHoverEffectSVG/index3.html http://tympanus.net/Tutorials/InteractiveSVG/ http://tympanus.net/Development/CreativeGooeyEffects/share.html http://samherbert.net/svg-loaders/ http://alexk111.github.io/SVG-Morpheus/ http://fettblog.eu/blog/2013/07/16/basic-svg-path-tweening-with-smil/ http://codepen.io/verios/pen/ByYYQm http://codepen.io/ChrisJohnson/pen/jPeaOK http://codepen.io/guerreiro/pen/obhzc http://codepen.io/magnificode/pen/MYBjra http://tavmjong.free.fr/blog/?p=741

I also suggest you to read this article about SMIL by one of the leading experts on SVG, Sara Soueidan: https://css-tricks.com/guide-svg-animations-smil/

The only reason because SVG animations are not more used on the web is because until now it was hard to make them. Now VPaint is going to change all that. I'm pretty sure it is going to spread like fire between web designers. But you need to make it friendly to use for them. And this means making the SVG (frame by frame or SMIL) export simple, reliable and easy to modify back and fourth. You can also support different kind of export options, like HTML with a javascript snippet using Snap.svg to interpolate the paths (see: http://snapsvg.io ). The following article explains how to do it: http://tympanus.net/codrops/2013/11/05/animated-svg-icons-with-snap-svg/

The secret of success is to design your app around the needs of the people that will use it. Because offering more export formats means more adoption and an easier interchange between people on different platforms. You start from the web, become popular, and then you will spread to the other fields. At that point, when everybody is using it, you can hope to make VEC more than an internal format. But until then, you have to use all resources you have to make VEC animations working when saved as SVG SMIL. A huge number of specialized software tools out there, including those for animating cartoons, are able to import SMIL SVG animations, because it is has been a popular and fixed standard for many years. There are also converter that can take a SMIL animation and convert it to many different proprietary formats of expensive animation packages.

I'm looking forward to see the next version of VPaint.

dalboris commented 8 years ago

Thx a lot Emasoft for your detail point of view it's extremely useful. I think you make a lot of good points. Indeed, we agree that having a good and reliable SVG SMIL export (and possibly javascript snippet) is probably key to get the required adoption that would give the required momentum to VPaint.

It was just important for me to clarify that we shouldn't have big hopes of re-importing back this export into VPaint. :-)

blurymind commented 8 years ago

Thinking of vpaint as a tool for web banners is pretty depressing. I do hope the main point of design is character animation, not web buttons and ads

blurymind commented 8 years ago

There is already a ton of other software for that stuff. Please focus on being a real animation tool. I dont think svg smil export should be a high priority. We are lacking fundamentaly basic features needed for professional animation

dalboris commented 8 years ago

Blurymind: a good SVG export also serves the need of character animation, fortunately, so there is not a conflict of interest here. If you can embed you vector animation natively on your website, that's pretty cool isn't it? :-) Don't worry too much, character animation is my field of research, it will stay my highest priority.

blurymind commented 8 years ago

swf is a dying format. But there is currently no viable alternative to it. Please show me a website where animated clips (not just web banners,small tests and gui) is being played in the browser with svg smil. Who is embedding it? Is it a mainstream standard and how does it compare in terms of performance with swf?

No other professional animation software can import svg smil and edit it.None that i know of can export it either. Inkscape doesnt have animation on their roadmap.

It's like me demanding to implement webp format export. Nobody is using that, eventhough its supposed to be better than jpeg.

Web banners are made in adobe products. You need to import images and animate their distortion, add effects non destructively. You need to make them interactive via code. It is a whole different ball game for another type of software.

Vpaint is open source, so someone could take the tweening vac technology and apply it for that type of an application. But I am still trying to see the point. :)

Not that i'm against it. I just want to understand the usefulness of this.

blurymind commented 8 years ago

You could improve the single frame svg export though. This would make it very useful for doing illustrations and sending them to inkscape for adding gradients and filter effects on top. But then again - that is really not an animation focused workflow is it. GUI animation and motion graphics are really more in the realm of web development software.

Emasoft commented 8 years ago

SMIL is just the best way to animate SVG, and also an universal standard. Currently many animators are using SVG under the hood even if the software doesn't support it explicitly. Here is an example SVG character animation made with Tumult even if SVG is not officially supported: http://www.luckyde.com/ipad/turn/turn.html

You can read the details of why they had to use SVG in Tumult here: http://forums.tumult.com/t/tried-pivot-animation-with-svg-in-hype/3339

But even Tumult has to use some custom code to animate the various SVG rigged parts of the character, because SMIL is currently not supported in Microsoft browsers (because at the time they developed their own XAML vector format in Silverlight and considered SMIL to be a competitor. Now Silverlight is dead, but SVG is still the standard). But soon this is going to change. Thanks to a new web standard, finally endorsed by Microsoft, browsers would be able to support a common set of standard functions for animations called Web Animations. Thanks to WebAnimations and a simple polyfill, all SVG files animated with SMIL are going to play on all browsers, even the Microsoft ones. Eric Willigers created a SMIL polyfill implemented entirely on the Web Animations API. The polyfill translates the SMIL code in WebAnimations API calls behind the scene, with the user not even noticing. Also WebAnimations gives a standard support for graphic acceleration, improving the performances and the frame rates tenfold. You can find it here: https://github.com/ericwilligers/svg-animation

Very soon there will be a huge demand for SVG animations, but while there are a lot of great vector drawing applications for it (Inkscape, Illustrator, Affinity Designer, and now even Photoshop supports SVG) what is currently missing is a software that animates it and interpolates between the keyframes, and that saves in a standard animation format like SMIL SVG. The moment VPaint is going to offer that, I can assure you that your app will become quickly the most popular piece of software on the web. Then the world of animated movies will start to take notice too. But you need to embrace a standard, not fighting it, to make your algorithm and your innovative UI really matter. You can always improve in the future once your app became an estabilished standard for vector animations.

In summary if you want VPaint to succeed:

  1. Focus on an existing graphic standard (i.e. SVG SMIL)
  2. Focus on the animation part not on the drawing part (i.e. kframing, interpolation, char rigging, etc)

Don't waste your time on things that other applications already do well, and don't underestimate the capabilities of SMIL. It was created by some of the best experts in animations, it was carefully designed, and the only reason for it not becoming popular was Microsoft fighting it. But now with the recently approved Web Animations API nothing would stop it to gain the traction it deserves.

Good luck.

dalboris commented 8 years ago

Thx @Emasoft for all this information. But it is important to understand that VPaint is not just about the innovative UI, it's mainly about how it represents animation internally, and SVG+SMIL just cannot store this representation. If you export to SVG+SMIL, and it doesn't matter how good the export is, you lose this representation, and without it, you cannot have the innovative UI that makes VPaint unique.

So yes, I definitely want to have good support for exporting SVG+SMIL, but the new format VEC that VPaint is using will stay the primary focus. This is not a choice, but a technical limitation of SVG+SMIL. Hopefully, VEC can become a supported standard (or a similar format as powerful as VEC), and -that- would be game-changing. This should be the priority and where development should go: having a well supported VEC-based animation format, and good user interfaces to create/edit them.

Emasoft commented 8 years ago

As I said before, of course you have to mantain your custom VEC format. What I'm suggesting is that when you are going to export to SVG SMIL, you'll use a faithful SMIL translation of such animation even if it mean to replace the few keyframes needed by your morphing algorithm with a lot more keyframes to reproduce the animation even with the basic SMIL interpolation method. You cannot assume that all applications would suddenly incorporate your algorithm. And even years from now, it would always be more optimal to produce a vector animation format that doesn't require all the additional computing power that your algorithm surely require compared to the fast and basic SMIL interpolation. This is the same reason because even powerful 3D graphic cards still use simplified triangle meshes and not nurbs to render a scene. Because computing power is costly. So if you don't provide a way to perfectly translate the animation produced in VPaint in a format like SVG SMIL, or one that doesn't require your unique algorithm to be used to reproduce it, the output of your application will be dead on arrival. It would be like Photoshop not being able to export a .PSD file as a .PNG file. Who would be able to use those filters heavy and layer cluttered .PSD files directly in the rendering pipeline of a Inferno toon renderer or in a Softimage shader? Nobody. It would be an useless overkill. The real product of your VPaint should be an SVG SMIL animation, not a VEC file. In the same way as the real product of Sony Vegas Movie Studio or Final Cut Pro is not their proprietary project format, but an MPEGx video file. And because VPaint is an intermediate tool in the production chain, your final product is neither an internal format or a mpeg rendering, but a vector animation that can be modified, adapted, stretched, cut and rigged by whoever is going to edit the final movie. You should be able to export a "mickey-mouse-walk-cycle.svg" file and pass it to someone using Adobe After Effect or Softimage to composite it in many different movie scenes and still render fast enough to not slow down his workstation to a crawl. This doesn't mean that you have to support only export. SVG is an XML format, and that means that you can embed in it all the metadata you want. Inkscape already does this, for example, adding tons of special attributes needed to restore the additional inkscape specific informations when reloading the SVG image. You can theoretically add all the original keyframes and morphing informations as additional XML nodes in all SVG files you export, and those would be preserved in the same way, if not better than in your VEC custom format. Such SVG VEC flavoured file would be loaded again as a VEC advanced animation in VPaint, and as a standard SMIL animation instead in all the others applications. Nothing would be lost, and you would gain the advantage of a truly interchangeable graphic format that people will be able to use and to watch everywhere, from Oracle workstations to iPads, instead of having to install VPaint on a desktop computer just to play it.

dalboris commented 8 years ago

I think we agree, I did say "I definitely want to have good support for exporting SVG+SMIL" :-)

As for using SVG metadata, of course I can embed the VEC into the SVG to lose no information and re-open it correctly (it's actually trivial, VEC is XML as well). It might be a good idea, but it's still very different from what Inkscape does: there a difference between using a little metadata to store useful info (what Inkscape does), and completely ignoring the actual SVG data in favor of exclusively using the metadata (what VPaint would do in that case). ;-)

scribblemaniac commented 8 years ago

A feature like embedding VEC information into the SVG metadata should definitely be optional. Depending on how much of the SVG-SMIL data VPaint uses directly (which would be almost nothing during early implementations of such a feature) the file size of the SVG could easily double in size, if not more from 'redundant' data.

dalboris commented 8 years ago

Yes, if we have a feature like this, it should definitely be optional :-)

scribblemaniac commented 8 years ago

Good news everybody, I have started work on the SVG import feature!

At the moment it's not very exciting. It can draw colored rectangles, and that's about it. It's a busy time for me, but in a week or two I should have all of the basic shapes implemented, which should allow geometry to be imported from some programs. After I finish path, then you should be able to import most objects but it may take a bit longer to finish that one. We should have a fairly good SVG importer ready in time for v1.8.

You can find the code I have made so far here, and you can check out my progress here. I would appreciate any help with this, just let me know before you start something so we don't end up working on the same thing! If you are not a programmer, you can still help me out by testing things yourself and linking SVG files for me to test.

Edit: I ended up spending a more time on this today (mainly so I could procrastinate on other things). Line, polylines, and polygons are now supported. Here's an image of an SVG rendered with VPaint showing off some of the various shapes that can be imported, as well as a few translucent fills/strokes (and remember it's a demo, it doesn't have to be pretty): demo

dalboris commented 8 years ago

Wow, this is awesome!!! Thx so much. Aiming for v1.8 is great. A reasonable plan is to keep it separate from master until after v1.7 is released, since the parts of the code actually building the vertices/edges will not be compatible with the core rewrite that I'm doing and will roll out in v1.7.

Those parts will have to be rewritten, but that's fine, it will be pretty straightforward and quick to do (I see that most of the code is the parser and the overall engineering).

I looked very quickly at the code (didn't try to compile), and as far as I can tell it looks awesome! It looks so good I only have a very minor comment: could you rename svgparser.h/.cpp to SVGParser.h/.cpp? I use the convention the capitalize file names to match class names. For convenience in QtCreator: Tools > Options > C++ > uncheck "Lower case file names" so that when you create a new class via the wizard, the .h/.cpp files are named according this convention.

Thx again!

scribblemaniac commented 8 years ago

Thanks for the kind words! I was aware of the core rewrite that you are currently doing, which is why I was trying to focus primarily on the code that wouldn't change. I created the class with the QT Creator, which as you guessed, used the lowercase name of the class as the filename, and it also automatically added it to my git index. I have since updated it, but I realize now that the changes weren't pushed upstream because I have the ignorecase setting enabled in the git config. It will fixed soon. Thank you for the tip for changing that from the Tools menu.

Do you have an recommendations for how I should represent elliptical arcs and bezier curves in VPaint? I was planning on approximating it by modifying the curve with the points less than ds pixels apart, but I figured I'd ask in case there was a better way of doing it.

dalboris commented 8 years ago

Yes, for elliptical arcs and Bezier paths you should evaluate them every ds and store the dense samples you get. To start, I suggest not to insert vertices at path knots. If we have enough time, then we can implement an option of the importer to specify one of the following behaviors:

  1. Never insert vertices at path knots
  2. Insert vertices at non-smooth path knots only
  3. Insert a vertex at every path knot

We'll have to specify what "non-smooth path knots" exactly is (e.g.: smooth knot = all T or S knots, plus all knots whose tangents just before and just after are equal up to a threshold). I think Option 2. should be the default but I don't have a strong opinion between 1. and 2.. Option 3. should probably not be the default.

Other comment: may you pass the VAC to write to as a parameter to the parser, so that you remove the dependency to global()? I know I'm guilty of this myself, but I'd rather move away from this now that I have less strict time constraints. It's gonna make it easily portable when layers come (each layer will have its own VAC).

Thanks!

On February 29, 2016 7:55:40 AM scribblemaniac notifications@github.com wrote:

Thanks for the kind words! I was aware of the core rewrite that you are currently doing, which is why I was trying to focus primarily on the code that wouldn't change. I created the class with the QT Creator, which as you guessed, used the lowercase name of the class as the filename, and it also automatically added it to my git index. I have since updated it, but I realize now that the changes weren't pushed upstream because I have the ignorecase setting enabled in the git config. It will fixed soon. Thank you for the tip for changing that from the Tools menu.

Do you have an recommendations for how I should represent elliptical arcs and bezier curves in VPaint? I was planning on approximating it by modifying the curve with the points less than ds pixels apart, but I figured I'd ask in case there was a better way of doing it.


Reply to this email directly or view it on GitHub: https://github.com/dalboris/vpaint/issues/9#issuecomment-190267142

scribblemaniac commented 8 years ago

Well I wasn't planning on adding vertices to intersections mainly because other vector programs won't do that, so you expect the same behavior when importing SVGs. However now that you mention it, I can see how that should be an option. Can you please explain why differentiating between smooth and non-smooth knots is important? Also it seems to me like there are a few additional things to consider. Where should vertices be added: self-intersections, intersections with other paths within the svg, and with other paths in the image. This question could be simplified quite a bit when we get layers, as you can simply add it to a new layer and have some kind of merge operation if you want it to intersect with other objects. Another consideration is how does it behave when animated. I plan to add support for importing some basic svg animations (rotations, translations, color changes), so how would adding verticies work if the knot only occurs at a certain time?

I definitely can have the VAC passed in as a parameter. I'm glad you're thinking ahead to layers.

Other comment: What is the color of a vertex for? As far as I am aware, vertices aren't rendered on their own. What happens if two edges of differing colors share a vertex?

dalboris commented 8 years ago

No, I wasn't even talking about intersections, that's another very complex story altogether, let's postpone it ;-)

Within a single independent path (the d attribute of the SVG path), there are several knots (control points). We may or may not add a vertex for each of these knots. If the path is smooth at a given knot, then it's probably a good idea not to put a vertex there. But if it's a sharp corner point (e.g., every control point of the square-shaped path d="M 0,0 L 1,0 1,1 0,1 Z"), then it makes sense to add a vertex at each corner, to reflects the geometric semantics of strokes VPaint: corner/sharp points at vertices, everything else smooth.

Another thing to consider while I think about it (you may have thought about it already). There might be MoveTo (M, m) commands in the middle of the d attribute of path, this is often used to define compound paths. A different edge should be created for each of these, and if a fill-color is specified, then each of these edges should be a separate "cycle" of the face (For instance, creating holes in a face). Also, the edge should be closed edge if the ClosePath (Z, z) command is used, otherwise it should be an open edge.

The color of vertices is now useless and will be factored out. It was used at some point in the development, when I thought it was a good idea to allow users to make vertices visible and colored as part of the final drawing itself. In VPaint 1.0 (no animation), I had miter joins and I was doing something quite fancy to handle the color transition between two edges of different colors. That turned out to be too complex to generalize for animation within the time constraints I had, so I dropped the miter joins and color transitions. Now, the rounded cap of each edge is drawn together with the edge (and you can see the ugly artifact currently on semi-transparent edges ;-) ), so the color of the join is whichever edge is on top of the other in the detph ordering.

edgecolors

Eventually, I will have to add back miter joins but that's actually very complex to specify because of the ability to have n-way joins and edges of different and variable width (different from one another, and variable within itself). The SVG working group is already struggling to specify a good miter behaviour for SVG 2.0, even with only 2-way joins and constant width (since SVG joins are "within a path", i.e. at constant width as of SVG 1.1). Food for thoughts below:

edgejoins-foodforthoughts

dalboris commented 8 years ago

Another code styling request: In fact, I'd prefer "SvgParser" rather than SVGParser. I know you did the right thing, which is following my existing naming conventions! (e.g., "doExportSVG") But with more thoughts, let's stick to the Qt convention of not capitalizing acronyms, especially for SVG which also exist in Qt as the <QtSvg> module (with classes such as QSvgRenderer, etc.). I think the only exception in Qt is for OpenGL, so let's do the same in VPaint. I'll change (or you can do it if you wish) the existing SVG/PNG to Svg/Png in the code (not in the comments or user-visible strings!).

For the Vector Animation Complex, I've started by using VAC and OpenVAC , and it kindda hurts my eyes to see "Vac" or "OpenVac", but I'm changing to this anyway. The eye-hurting is only temporary (I already start to get used to the non-capitalized names), and consistency with other non-acronym class names or namespaces is more important. And when using smart pointers, VacPtr and VacSharedPtr is actually more readable than VACPtr and VACSharedPtr.

Thanks!

scribblemaniac commented 8 years ago

Ah sorry, I completely misinterpreted knots, I can see what you mean know. And I have no problem postponing that discussion on intersections ;)

I think I will add smooth knot detection to my todo list. It shouldn't really be too hard, since there is only a limited number of path descriptions for d and it is fairly easy to calculate the tangent on either side for all of the knots:

I have given some thought on the handling the moveto and the need for separate cycles in some situations, and unfortunately that's yet another complicated thing to deal with. Luckily the standards are fairly clear for this and there are only two behaviors specified by the fill-rule property. The biggest issue with importing this will probably be the fact that we need intersections in some situations (oh no I wasn't supposed to talk about that :P ). Take the star on the left for example: fill-rule Notice how we'd have to add 5 vertices to the interior portion where no knots would be specified by the SVG file. Not only would we have to add vertices there, but we'd have to detect that complete shape and make a separate cycle for it.

I'll change the naming convention for all of the stuff I've created, but you should change the ones that already exist (such as doExportSVG) so that the naming will be consistent for v1.7.

Thank you for taking the time to make such a detailed response.

dalboris commented 8 years ago

Moveto: a vertex on both the starting and finishing positions since they are endpoints.

Yes, and there is one subtlety (unrelated to tangent computation): If fill-rulle is not specified (i.e., when you don't create a face), then you shouldn't create a edge from the position before and after the MoveTo. However, if fill-rule is specified, then you do need to create an edge to be able to support the face. In this case, you should create a fully-transparent, zero-width edge.

Lineto/Closepath: the line between the two points obviously

Yes for LineTo. For ClosePath, I think there's some subtlety here too! If the two points are equal within ds, that means in practice that no "line" should be added, and it's just to specify that the path is closed. For instance, to specify a closed Bezier curves in SVG, I think (I didn't double-check) you need to duplicate the first and last control points to be able to specify their tangent, but still write "Z" at the end to "Glue" together the two control points. In this case, the tangent shouldn't be computed as the straight line between the start/end points (that would be a division by zero), but via what happens "just before" and "just after" the ClosePath.

Curveto: the line between the start/endpoint and it's corresponding control point.

Yes!

Arcto: the line perpendicular to the line between the arc center and the start/endpoint (I think?)

Unfortunately not ;-) This is true for circles but not for ellipses, see below. The formula is still pretty straightforward though, just express the ellipse as a parameterized curve (cx + rx*cos(t), cy + ry*sin(t)), which gives you the (non-normalized) tangent after derivation: (-rx * sin(t), ry*cos(t)).

ellipsetangent

Intersections: nope, you never have to compute them ;-) That would change the semantics of the drawing. In the case of the star, you want to be able to move the end points and have the edges "unaware" of one another (i.e., overlapping but not intersecting). Open VPaint and try this, you'll be surprised ;-)

  1. In Sketch mode (F2), turn off intersections but keep snapping on.
  2. Draw the 5 edges of the star
  3. Go to Paint mode (F3) and click in the middle of the star
scribblemaniac commented 8 years ago

All very good points thank you! Now I just have to code it ;-)

Open VPaint and try this, you'll be surprised ;-)

That's pretty awesome, but can it do nonzero fill-rule? Ex: nonzero fill

dalboris commented 8 years ago

Now I just have to code it ;-)

Hehe, "just" :-P

Currently it doesn't do nonzero fill-rule, but the back-end would be absolutely straightforward to implement. Literally one line of code to change, this one (actually two lines, because the drawing code is duplicated in InbetweenFace.cpp due to last-minute poor design):

https://github.com/dalboris/vpaint/blob/master/src/Gui/VectorAnimationComplex/KeyFace.cpp#L263

All we need is to add the fill-rule as a member variable of a face, then a way to set it in the Gui.

scribblemaniac commented 8 years ago

Good news, all basic shapes can be imported now! The code for processing the path tag is nearly complete. I just have to code the shortcut curve types. That just leaves group handling/inheritance, smooth knot detection, basic documentation, and various smaller details and edge cases (style, transform, animate maybe). Now that it's semi-functional, I will be taking a break to finish some other projects, but I will be back and it should still be finished in time for 1.8.

Here's an extension of the previous demo, showing some of the many different curves/shapes that can be imported now: basicsdone

Notice the new ellipses, quadratic bezier curves, cubic bezier curves, and elliptical curves. Once I get groups working, I will post some much more impressive examples.

dalboris commented 8 years ago

This is very good news, thank you so much for all this work! Glad to see that the ellipses are looking great!

What are your current plans for groups? My idea was that each SVG "group" would be converted to a VPaint "layer", since the concept of "layer" which I envision for VPaint would be the primary grouping mechanism, and closest equivalent to the concept of groups in SVG (I'll give more details on this after v1.7).

But in the meantime, since there is no grouping mechanism, I guess all you can do is parse the group, store the transform, and apply the transform recursively to all child elements (i.e., manually implement a "ungroup all" function). Though this work will be thrown away once layers are implemented... so maybe you would want to wait for layers? As you wish.

scribblemaniac commented 8 years ago

I definitely think that groups should be parsed as layers as soon as layers are implemented. For the moment I'll figure out some alternate way of handling it, but I'm not exactly sure what yet. I could implement a recursive ungrouping function as you suggest, or I could store a pointer to a parent element, or something else entirely. The work I do on it will not be wasted however because even when layers are implemented, there are still some attributes that will likely not be compatible with VPaint layers. For example, you can specify a fill color for a group which would be the default color for all the child elements, but I get the feeling that VPaint layers will not have such a feature. That's fine, infact I think that's the way it should be, but that means we still need to handle this case even when layers are implemented.

Emasoft commented 8 years ago

@scribblemaniac You are doing an amazing job! Wow! Any hope to see SMIL import/export anytime soon? SMIL is huge now (read my article about it: https://medium.com/@fmuaddib/the-following-are-the-possible-ways-to-create-professional-animations-in-svg-9d4caca5f4ec ).

About the layers and the color issue, as a content creation tool developer you should join the SvgWG discussion about the standardization of this feature: https://github.com/w3c/svgwg/issues/68 Groups are not the same as Layers. Layers need to be manageable in number, about 10-100 max. If you make layers the same as groups they are not manageable anymore, because an image can easily have thousands of groups. Groups are better left to a searchable document hierarchy tree window, not in the layers window.

scribblemaniac commented 8 years ago

Thanks! I do plan on having some very basic SMIL import support, although I don't know if it will make it into the first release.

dalboris commented 8 years ago

@scribblemaniac You are indeed right about children of SVG groups inheriting style from the group, it's likely to be different in VPaint. Though, might be worth considering, good point to raise. So yes, it still makes sense to implement group import before layers are available in VPaint, since not that much work would be wasted (i.e., much less than I initially thought).

@Emasoft Great write up, that's super useful! SMIL is still very low on my priority list, but definitely if someone wants to write import/export, I'd be stoked.

In terms of number of layers, my vision is in the order of ~100 for high-quality animation (Disney, Studio Ghibli, etc.). But the "layer window" (in fact, the timeline) will be smart and only show the relevant ones, where "relevant" will be customizable by the user (e.g., "all", or "selected", or "saved selection #5", etc.). A "layer" in VPaint would be more equivalent to a "node" in the scene hierarchy in 3D animation software: layers can have children layers, etc. Though of course, there would be much fewer layers in VPaint (~100) than nodes in 3D animation (~1k-10k), because each layer contains much more information, but "in spirit" they are the same.

It is yet unclear to me if in addition to layers, "groups" should exist in VPaint. Right now, I think not, and I'd rather just have layers and wait to see if there is a strong enough use case for a second grouping mechanism. The issue is that the concept of group as defined in SVG is not very suitable for the VPaint data structure model. One big difference between VPaint and SVG is that in VPaint, selectable entities (e.g., a key edge) only exist for a given instant or interval in time, while in SVG they are persistent. Another big difference is that in VPaint, selectable entities depend on other entities to be valid (e.g., an edge depends on its end vertices). Those are specific challenges that SVG does not have, and deeply affects what are our options in VPaint in terms of grouping behavior.

In a nutshell, SVG was historically created for non-animated content, so most of the design decisions behind SVG features (or even SMIL, which was constrained by SVG) do not apply for VPaint. I believe grouping is one of them, and my design decisions will be much more influenced by ToonBoom, CACANi, and TVPaint than by SVG. Anyway, there is still plenty of time/room for discussion on this subject, and things will become clearer as they become implemented.

Emasoft commented 8 years ago

@dalboris You should find a solution to make selectable entities somehow persistent. Maybe ading some abstraction or metadata that allows the artist to make effects or transformations following the entity, even if it split-morph in pieces or if it is joined with a boolean union with another one. Maybe some metatag associated with every polygon or vertex, marking it as belonging to a certain abstract entity, that are inherited by descendants and mixed with others but always presents. In the case of layers instead, the problem does not exist, because objects belonging to different layers cannot morph/merge with each others. This is why layers are a different thing from groups, onion skins or even timelines. Layers exist to make the work of an artist easier creating a clean separation of concerns. They should be treated as completely different pages with completely different entities and timelines. This is what makes layers useful to the artist: they compartimentalize the scene dividing it in independent and manageable chunks.

dalboris commented 8 years ago

@Emasoft Well, I can understand how that'd be awesome, but unfortunately, as of the current state of human knowledge, I don't see how this would be technically possible. Any solution would probably be either too much info to be manually provided by the artist to be worth it, or automatically computed via heuristics which would probably often fail and be unpredictable.

The current design I envision is: within a layer, things are not persistent. It is per-frame entities, as close as possible to a traditional hand-drawn animation workflow, and allows topological events. Then layer is the lowest-level concept which introduce persistence, and allow more "vector graphics / 3D animation" workflows, but losing the ability to have topological events across layers.

That's the best trade-off I can think of between usability, genericity, and feasability.

Emasoft commented 8 years ago

@dalboris It is a problem similar to that of the old hollywood B/W movie colorizer, when they needed to recognize the exact shape of the same guy walking in the image in each frame, because they needed to colorize it. It was a fluid shape, hard to track, but in the end such hard problem was solved by software, and now you can do the same in After Effects to track an effect on any shape you define.

image

dalboris commented 8 years ago

@Emasoft Sure, but that's different. I can (and will) definitely implement an algorithm that, based on the currently selected per-frame entity, extend the selection in time to corresponding strokes in the frames "before" and "after", even in case of topological events. Then you can apply a color to those guys. And possibly remember this selection of many non-persistent entities as a "group" (or set, or class, or style group, or whatever you want to call it). Such a concept of "group" might be considered. And we could have a notion of a "transformer" object that could be applied to an entity, or a selection of entity, i.e., a "group".

But It doesn't mean that the atomic selectable entity itself is persistent.

Emasoft commented 8 years ago

@dalboris Well, if you can apply the same effect to all corresponding strokes in the timeline, you have it.. that is what a selectable and persistent entity is all about. So even if you call it differently, for all practical purpouses it is the same.

dalboris commented 8 years ago

@Emasoft Yes, I guess we just misunderstood ourselves a little, which is understandable as it's quite abstract and hard to put in words.

Yes, why not introducing another entity, for instance called "set" (following the terminology you used on the svgWG thread), which would be orthogonal to layers. Like layers, it would be "persistent" , though the entities/elements it "contains" or "refer to" are not.

I thought you were suggesting that existing VPaint selectable entities (key/inbetween vertices/edges/faces) should somewhat be made persistent, which is not gonna happen as it is conflicting with traditionnal hand-drawn animation workflows.

dalboris commented 8 years ago

@Emasoft Anyway, even though this "set" concept might be considered, it will have to be carefully designed, and it is yet unclear of what a good design would be, due to the non-persistence of the elements in the set.

Emasoft commented 8 years ago

@dalboris Yes, of course. The need is to have an high level abstraction. If this translates in the exact same elements, or in elements changing each frame, this is an implementation detail. What does matter is that if I have an entity called "train", I can select it and track it in each frame, no matter what the differences are between the frames. It is still true, I believe, that if you are doing a inbetween morphing, using the interpolation trajectories you are able to know the correspondences between the vertices of the shape in a keyframe and in the following one. Am I right?

scribblemaniac commented 8 years ago

@dalboris 100 layers is way too low for a full project (especially a high-quality animation). I don't know about other people and professional studios, but personally for my large projects I would make a separate .vec file for each shot, which makes 100 a reasonable approximation of the number of layers.

I won't speak as to whether or not there should be groups of objects which is what you both are talking about it seems, but I will say that groups of layers is a must in my opinion. Things like grouping together the layers from an imported SVG, grouping together a shot if you have multiple shots would be very handy, or toggling the visibility of many layers at the same time. I imagine it would just be displayed as an expandable object in the layers section.

@Emasoft You raise some very interesting ideas. I'll be interested to see where they go.

I've come up with a bigger-picture idea based on the discussion between you too. I'll explore it a bit further and see if there's actually any value to it. If I think it is something that should be considered I'll make a rather large new issue on it. Thanks for the inspiration :smile:

scribblemaniac commented 8 years ago

Also, this issue is getting a little out of hand now. I feel like we should close this and break it up into the many separate issues that have been discussed here. Up to you @dalboris.

Emasoft commented 8 years ago

Happy to have helped to expand your approach to this matter. I gave you my small input on this, now I leave it to you. I'm sure you will do a great work! :-)

dalboris commented 8 years ago

@Emasoft Well, in the case of a entity "train", I would think that a layer would be the perfect concept for this kind of entity. The layer called "train" can be selected, and this is persistent. This layer is made of many per-frame strokes (possibly inbetweened), but with the layer selected, you can move from frame to frame and see that your "train" stays selected, even though the strokes selected at frame 1 can be completely unrelated from the strokes at frame 200 (e.g., when the train is turning, as in this shot from Dumbo, starting 1:51: https://youtu.be/bM9B3mY3JfA?t=1m51s).

@scribblemaniac Yes, "groups of layers", definitely. Though, I won't call them like this, it's just that layers have the ability to have children layers. So it's more a "hierarchy of layers" rather than "groups of layers". Thanks for the additional info regarding the number of layers in your experience! I think 100 is indeed an average estimate, but it would basically be lower for people more in the "traditional animation" style, and higher for people more in the "computer animation" style. "Computer animation" is a bad name which I use for "parameterizing a scene with persistent animation variables (rigging) then animating the values of these animation variables (animating)", as it's done in 3D animation and vector graphics animation. VPaint tries to find a sweet spot between those two worlds.

dalboris commented 8 years ago

@Emasoft

It is still true that if you are doing a inbetween morphing, using the interpolation trajevtories you are able to know the correspondences between the vertex of the shape in a keyframe and in the following one. Am I right?

Yes, you are correct.

Emasoft commented 8 years ago

@dalboris The point of using the train example was because it's made of cars that are in different layers, and the order of those layers changes (i.e. when as in dumbo the train turns, and the last car becomes the foreground layer, while the first the background layer, and so on for all cars) but the train entity remains the same. Anyway, I think I'll leave it to you to find the best solution for entity persistence. Keep up the good work!