Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Official Vector Graphics Preview Package

Discussion in 'UI Toolkit' started by rustum, May 4, 2018.

  1. rab

    rab

    Joined:
    Nov 13, 2009
    Posts:
    101
    I also have a problem with the SVG coordinates (may be I'm using it wrong?).

    I created tree layers of objects I like to import as seperate objects. After this I want to create 3D-objects from the tessellated shapes out of the SVG planes.
    SVG-Test1.png

    As mentioned on page 3 using SVGRuntimeLoad.cs I manipulate the vector scene to create three objects out of the source SVG. I remove the unwanted nodes in each copy. The problem is that the SVG coordinates are not stored on each part resulting in a wrong positioning. Is this the result of the SVG coordinates bug mentioned earlier on page 4?

    Code (CSharp):
    1.  
    2.         var sceneInfo = SVGParser.ImportSVG(new StringReader(svgText));
    3.         int NrOfLayers = sceneInfo.Scene.Root.Children.Count;
    4.         m_Sprites = new Sprite[NrOfLayers];
    5.         SVGParser.SceneInfo[] m_SIArray = new SVGParser.SceneInfo[NrOfLayers];
    6.         List<VectorUtils.Geometry>[] m_Geoms = new List<VectorUtils.Geometry>[NrOfLayers];
    7.         for (int i = 0; i < NrOfLayers; i++)
    8.         {
    9.             m_SIArray[i] = SVGParser.ImportSVG(new StringReader(svgText));
    10.             int removed = 0;
    11.             for (int c = 0; c < NrOfLayers; c++)
    12.             {
    13.                 if (c!=i)
    14.                 {
    15.                     m_SIArray[i].Scene.Root.Children.Remove(m_SIArray[i].Scene.Root.Children[c- removed]);
    16.                     removed++;
    17.                 }
    18.             }
    19.  
    20.             m_Geoms[i] = VectorUtils.TessellateScene(m_SIArray[i].Scene, tessOptions);
    21.             m_Sprites[i] = VectorUtils.BuildSprite(m_Geoms[i], 10.0f, VectorUtils.Alignment.SVGOrigin, Vector2.zero, 128, true);
    22.             GameObject go = new GameObject();
    23.             SpriteRenderer s = go.AddComponent<SpriteRenderer>();
    24.             go.transform.parent = transform;
    25.             s.sprite = m_Sprites[i];
    26.         }

    SVG-Test2.png
    m_Sprites = VectorUtils.BuildSprite(m_Geoms, 10.0f, VectorUtils.Alignment.Custom, Vector2.zero, 128, true);
    SVG-Test3.png
    m_Sprites = VectorUtils.BuildSprite(m_Geoms, 10.0f, VectorUtils.Alignment.SVGOrigin, Vector2.zero, 128, true);

    How can I get all layers aligned to the original SVG origin of the source SVG?
    Thank you and kind regards!
     

    Attached Files:

    Last edited: Aug 20, 2018
  2. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    Yes, I think you are correct and that this situation should work with the "SVG Origin" pivot. I'll try your example to see if it is fixed with our next preview release.

    In the meantime, you could probably work around the issue by computing a custom pivot yourself. You can do that by computing the bounding-box of the layer node, and comparing it to the bounding-box of the whole scene. You can try something like this (this is untested code, but will hopefully point you to the right direction):

    Code (CSharp):
    1. var fullBounds = VectorUtils.SceneNodeBounds(sceneInfo.Scene.Root);
    2. var localBounds = VectorUtils.SceneNodeBounds(sceneInfo.Scene.Root.Children[i]);
    3. var pivot = localBounds.position / fullBounds.position;
    4.  
    5. m_Sprites[i] = VectorUtils.BuildSprite(m_Geoms[i], 10.0f, VectorUtils.Alignment.Custom, pivot, 128, true);
    6. // ...
    We have many fixes upcoming in the next release, hopefully the "SVG Origin" fix will make this situation easier to deal with.
     
  3. Miniced

    Miniced

    Joined:
    Aug 18, 2015
    Posts:
    9
    Hi, it's me again.
    After some work and research, I was able to create an editor script to generate UV coordinates for sprites in the asset folder using the SpriteDataAccessExtensions.SetVertexAttribute(...) method. However, it turns out that this change isn't permanent. As soon as I either relaunch the editor or modify the import setting of an SVG file, the UV coordinates are reset to 0. Unless I missed something, it appears there's no way to change the UV coordinate permanently.
    Here's the code I use to set the UV :

    Code (CSharp):
    1. public class GenerateUV
    2. {
    3.     [MenuItem("Assets/Fill UV")]
    4.     private static void FillUV()
    5.     {
    6.         foreach(Object obj in Selection.objects.Where(x => x is Sprite))
    7.         {
    8.             Sprite sprite = obj as Sprite;
    9.  
    10.             NativeSlice<Vector2> UV =
    11.                 SpriteDataAccessExtensions.GetVertexAttribute<Vector2>(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord0);
    12.  
    13.             NativeSlice<Vector3> Position =
    14.                 SpriteDataAccessExtensions.GetVertexAttribute<Vector3>(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.Position);
    15.  
    16.             Vector2 min = new Vector2(Position.Min(x => x.x), Position.Min(y => y.y));
    17.             Vector2 max = new Vector2(Position.Max(x => x.x), Position.Max(y => y.y));
    18.  
    19.             NativeArray<Vector2> newUV = new NativeArray<Vector2>(UV.Length, Allocator.Persistent);
    20.  
    21.             Vector2[] UVarray = new Vector2[UV.Length];
    22.  
    23.             for (int i = 0; i < UVarray.Length; ++i)
    24.                 UVarray[i] = new Vector2((Position[i].x - min.x) / (max.x - min.x), (Position[i].y - min.y) / (max.y - min.y));
    25.  
    26.             newUV.CopyFrom(UVarray);
    27.  
    28.             SpriteDataAccessExtensions.SetVertexAttribute(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord0, newUV);
    29.  
    30.             newUV.Dispose();
    31.         }
    32.     }
    33.  
    34.     [MenuItem("Assets/Fill UV", true)]
    35.     private static bool TypeValidation() => Selection.objects.Any(x => x is Sprite);
    36. }
     
  4. rab

    rab

    Joined:
    Nov 13, 2009
    Posts:
    101
    @mcoted3d: Thank you for the hint. I tried all possible ways of calculating the correct pivot but failed in getting correct results. The best way - which worked so far - is using topLeft positioning and changing the position of the created child gameobjects:

    SVG-Test4.png

    m_Sprites = VectorUtils.BuildSprite(m_Geoms, 1000.0f, VectorUtils.Alignment.TopLeft, position, 128, true);

    SVG-Test7.png

    and later reposition of the created gameobjects with the resulting Bounds-positions
    go.transform.position = new Vector3((localBounds.x)/1000f, (fullBounds.y - localBounds.y) /1000f , 0);

    There is still a problem with the positions, so that this is not perfectly aligned:
    SVG-Test5.png

    In the original SVG the positions fit perfectly:
    SVG-Test6.png

    I hope on the updates you've mentioned. Is there a release date for the next update of the toolset?

    For testing purposes I've attached the source code I used.

    Thank you and kind regards!
     

    Attached Files:

  5. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    We had a similar issue when implementing the SVGImporter class. I've tracked two different issues:
    1. It seems that both TexCoord0 and TexCoord1 are used by the Sprite system and cannot reliably be overridden.
    2. It seems that calling SetVertexAttribute on a sprite won't flag it as dirty and it won't re-serialize.

    For 1), using the TexCoord2 channel should work.
    For 2), calling AssetDatabase.ForceReserializeAssets should help.

    I had success with this version of your script:

    Code (CSharp):
    1. [MenuItem("Assets/Fill UV")]
    2. private static void FillUV()
    3. {
    4.     foreach (Object obj in Selection.objects.Where(x => x is Sprite))
    5.     {
    6.         Sprite sprite = obj as Sprite;
    7.  
    8.         var UV = sprite.GetVertexAttribute<Vector2>(UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord0);
    9.         var Position = sprite.GetVertexAttribute<Vector3>(UnityEngine.Experimental.Rendering.VertexAttribute.Position);
    10.  
    11.         Vector2 min = new Vector2(Position.Min(x => x.x), Position.Min(y => y.y));
    12.         Vector2 max = new Vector2(Position.Max(x => x.x), Position.Max(y => y.y));
    13.  
    14.         NativeArray<Vector2> newUV = new NativeArray<Vector2>(UV.Length, Allocator.Persistent);
    15.  
    16.         Vector2[] UVarray = new Vector2[UV.Length];
    17.  
    18.         for (int i = 0; i < UVarray.Length; ++i)
    19.             UVarray[i] = new Vector2((Position[i].x - min.x) / (max.x - min.x), (Position[i].y - min.y) / (max.y - min.y));
    20.  
    21.         newUV.CopyFrom(UVarray);
    22.  
    23.         sprite.SetVertexAttribute(UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord2, newUV);
    24.  
    25.         newUV.Dispose();
    26.  
    27.         AssetDatabase.ForceReserializeAssets(new string[] { AssetDatabase.GetAssetPath(obj) });
    28.     }
    29. }
    You'll have to adapt your shader to use TexCoord2 for this to work.

    I'll have a chat with the 2D team to see if these issues could be fixed in the future.

    Hope this helps!

    EDIT: Regarding this:

    When changing the import settings of an SVG file, the sprite is basically recreated from scratch. To automate the UV generation in that situation, you'll have to use an AssetPostprocessor.
     
    Last edited: Aug 23, 2018
  6. ReaktorDave

    ReaktorDave

    Joined:
    May 8, 2014
    Posts:
    139
    I've sent you the example file via PM as it contains a production asset I don't want to put into the public.
     
  7. ReaktorDave

    ReaktorDave

    Joined:
    May 8, 2014
    Posts:
    139
    There seems to be an issue with the pivot. When using the SVG Importer from the asset store and setting the pivot to an arbitrary point on the SVGs original canvas size, the animation plays back smoothly.

    However when using the vector graphics package by Unity Technologies, we set the pivot to "SVG Origin" but still have some frames "jumping" or "moving" out of their supposed position. Is this a known issue?
     
  8. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    Ok, that's really close, but still not seamless. This is probably because the SceneNodeBounds computes the bounding-box from the curve data, which may be different than the bounds of the tessellated mesh. Since you need the bounds of the vertices, you'll have to compute it from the generated geometry.

    You could do something like this to compute the "localBounds":
    Code (CSharp):
    1. var localMin = new Vector2(float.MaxValue, float.MaxValue);
    2. var localMax = new Vector2(-float.MaxValue, -float.MaxValue);
    3. foreach (var localGeoms in m_Geoms[i])
    4. {
    5.     foreach (var v in localGeoms.Vertices)
    6.     {
    7.         localMin = Vector2.Min(localMin, v);
    8.         localMax = Vector2.Max(localMax, v);
    9.     }
    10. }
    11. var localBounds = new Rect(localMin, localMax-localMin);
    You will have to do something similar with the "fullBounds".

    We still have a few fixes and features to complete first. I don't have an accurate date to give you, but I would say we need a few more weeks until the next release.
     
  9. Dangy

    Dangy

    Joined:
    Aug 26, 2013
    Posts:
    7
    Works like a treat! only wishlist is to somehow compare the id that is exported out from Ai incase someone decides to move the layers in Ai.

    And also if there's an easy way to reference the svg string of a svg file in the Project assets. Wasn't sure if this was already been asked previously. Such as a svg file to be assigned to a custom ScriptableObject public variable.
     
  10. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    Yes, we have plans to do that!

    In editor code, you can just do new SreamReader("Asset/File.svg"). In runtime code, the easiest is to put your SVG file in a StreamingAssets folder:
    https://docs.unity3d.com/Manual/StreamingAssets.html
    These files will be copied as-is in your player.
     
  11. Miniced

    Miniced

    Joined:
    Aug 18, 2015
    Posts:
    9
    I was wondering, is it possible to use SVG in a ParticleSystem?

    Edit: Found a way to do this. You can generate a Texture2D from the SVG sprite and use it in a ParticleSystem by using his method :
    Code (CSharp):
    1. public static Texture2D RenderSpriteToTexture2D(
    2.     Sprite sprite,          // The sprite to draw
    3.     int width, int height,  // The texture dimensions
    4.     Material mat,           // The material to use (should be Unlit_Vector or Unlit_VectorGradient)
    5.     int antiAliasing = 1);  // The number of samples per pixel
     
    Last edited: Aug 27, 2018
    mcoted3d likes this.
  12. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    The particle system doesn't seem to support the "tight" sprites that SVG is using. So, I would say that generating a Texture2D from your SVG sprite is a simple workaround to make it work!
     
  13. Deviros3D

    Deviros3D

    Joined:
    Dec 18, 2012
    Posts:
    19
  14. Deeeds

    Deeeds

    Joined:
    Mar 15, 2018
    Posts:
    739
    Are there performance advantages to using this geometry based drawing over using bitmaps (and eating up fillrate) on modern mobile devices?
     
  15. Eidoboy

    Eidoboy

    Joined:
    Jul 3, 2012
    Posts:
    29
    Still experiencing this in preview.15. Is a fix under way?
     
  16. michaeleconomy

    michaeleconomy

    Joined:
    Aug 28, 2018
    Posts:
    58
    This is great. Any idea on when anima2d will support this and when it will be supported in UI elements?

    Thanks!
     
  17. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    I think the problem is that the SamplingStepSize property is the actual size, not the number of steps. If you want the same results, you should use 0.01 instead of 100 when using the runtime APIs.

    Let me know if that doesn't work.
     
  18. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    Yes, we have a new version with many fixes that we hope to release in a few weeks. If you want something faster, I think you could implement it yourself. It should be feasible to write an asset postprocessor to "manually flip" the geometry of the imported SVG sprites (by using the Sprite.OverrideGeometry method). Let me know if you need help doing that.
     
  19. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    We definitely want to add UIElements support, but it's still not planned in our schedule at this time. If you are referring to the Canvas UI instead, we still can't promise anything, unfortunately.

    I don't know about Anima2d since it's a third-party Asset Store package. The best would be to contact them directly to see if they have any plan to add SVG sprite support in the future.
     
    michaeleconomy likes this.
  20. Deviros3D

    Deviros3D

    Joined:
    Dec 18, 2012
    Posts:
    19
    It work.
    Thanks
     
  21. Eidoboy

    Eidoboy

    Joined:
    Jul 3, 2012
    Posts:
    29
    Thanks, I'm still not using it in production. So I can wait for the update ;-)
     
  22. Deeeds

    Deeeds

    Joined:
    Mar 15, 2018
    Posts:
    739
    @mcoted3d for all that is good in the world, please add render-to-texture with alpha!

    Please!

    I will personally donate funds. And pizzas. And beer. And donuts. Whatever it takes.
     
  23. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    It's definitely planned and should be released soon-ish. It may not have support for all the same features as the regular texture importer (we may not have support for compression and mipmap generation at first). But otherwise, you'll have a render-to-texture with alpha for sure.
     
  24. Deeeds

    Deeeds

    Joined:
    Mar 15, 2018
    Posts:
    739
    THANK YOU.

    WONDERFULL!!

    No need compression, no need mipmaps. Both of these can be done manually, thanks to having the vector format and render to texture, with alpha!

    Let me know if/when/where pizzas/beer etc needed to make this happen faster/better.
     
  25. Deleted User

    Deleted User

    Guest

    Are these new vector sprites supposed to work with UnityEngine.UI.Image?
    If not, is support planned in the near future?

    The SpriteRenderer seems to have different sorting rules, and always draws behind our UI, and I haven't found a found a way to make it sort normally.

    Thanks
     
    khusainova_olga and Deeeds like this.
  26. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    This is not supported at this time, and we don't know if/when this will be fixed. Given that this will likely require changes in Unity itself, this is unlikely to be fixed "soon", if at all.

    The easiest workaround right now is to render the SVG sprites in a texture and use that in the UI system. We will eventually provide a "render to texture" option the SVG importer, but in the meantime, you can use the VectorUtils.
    RenderSpriteToTexture2D API to do it manually.
     
  27. michaeleconomy

    michaeleconomy

    Joined:
    Aug 28, 2018
    Posts:
    58
    I though Anima2d was an in-house asset: the developer is set to "unity technologies". If this is not the case, this is very misleading!

    https://assetstore.unity.com/packages/essentials/unity-anima2d-79840
     
  28. jeffweber

    jeffweber

    Joined:
    Dec 17, 2009
    Posts:
    616
    I believe, Anima2D is no longer in development except for simple support/fixes.

    Unity has a replacement for Anima2D in development: https://forum.unity.com/threads/2d-animation-preview-packages.521778/

    I would love to see the Vector stuff work with this new 2D animation system.
     
  29. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    My bad! I was confused with another 3rd-party animation system.

    We're working with the 2D team to have a tight integration with the new 2D features. This is still under heavy development. Stay tuned! :)
     
  30. Deleted User

    Deleted User

    Guest

    Could you please comment on why this is?

    I considered trying to rig something up myself, which would have involved inheriting UnityEngine.UI.Image, and overriding OnPopulateMesh to use the vertices from an SVG asset instead or the standard quad or 9 patch. Does this sound viable, or is there something I'm missing?

    Thanks
     
  31. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    The UI system only supports simple "full rect" sprites at the moment. Ideally, we would like to support "tight" sprites as well, but doing so requires a change in the Unity codebase.

    That said, the solution you're suggesting definitely sounds like a viable solution. We made a successful prototype using something similar to that (but with direct support in the Unity codebase). It was basically working except for some edge cases caused by the difference between the regular sprites and the SVG "textureless" sprites. I don't think you will run into these issues.

    Here's roughly the code that we used if you want to use it as a starting point:
    Code (CSharp):
    1. vh.Clear();
    2.  
    3. Vector2[] vertices = activeSprite.vertices;
    4. Vector2[] uvs = activeSprite.uv;
    5. var spriteColor = activeSprite.GetVertexAttribute<Color32>(Rendering.VertexAttribute.Color);
    6. for (int i = 0; i < vertices.Length; ++i)
    7. {
    8.     vh.AddVert(new Vector3((vertices[i].x / activeSprite.bounds.size.x) * imageSize.x, (vertices[i].y / activeSprite.bounds.size.y) * imageSize.y), spriteColor[i] * color32, new Vector2(uvs[i].x, uvs[i].y));
    9. }
    10.  
    11. UInt16[] triangles = activeSprite.triangles;
    12. for (int i = 0; i < triangles.Length; i += 3)
    13. {
    14.     vh.AddTriangle(triangles[i + 0], triangles[i + 1], triangles[i + 2]);
    15. }
    You may run into issues if you use SVG sprites with gradients and/or embedded textures, as those sprites make use of the TexCoord2 channel which isn't passed in the VertexHelper class. I notified the UI team regarding this.

    Hope this helps!
     
  32. Miniced

    Miniced

    Joined:
    Aug 18, 2015
    Posts:
    9
    I've attempted to use a AssetPostprocessor method to fill TexCoord2 with UV mapping using this method.

    SpriteDataAccessExtensions.SetVertexAttribute(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord2, newUV);

    However, while I'm able to confirm using GetVertexAttribute(...) that TexCoord2 is indeed filled, it appears my shader's TEXCOORD2 (as well as any other TEXCOORD) parameter is using data from TexCoord0 instead. I'm not sure if the root of this problem lies outside the scope of this package, so I'm sorry if that's the case, but right now, Filling TexCoord2 isn't cutting it.

    This is the AssetPostprocessor class to fill the UV.
    Code (CSharp):
    1. public class SVGPostprocess : AssetPostprocessor
    2. {
    3.     void OnPreprocessAsset()
    4.     {
    5.         if (!(assetImporter is SVGImporter)) return;
    6.         SVGImporter importer = assetImporter as SVGImporter;
    7.  
    8.         if (!(importer.targetObject is Sprite)) return;
    9.         Sprite sprite = importer.targetObject as Sprite;
    10.  
    11.         NativeSlice<Vector2> UV =
    12.             SpriteDataAccessExtensions.GetVertexAttribute<Vector2>(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord2);
    13.  
    14.         if (!UV.All(x => x == Vector2.zero)) return;
    15.  
    16.         NativeSlice<Vector3> Position =
    17.             SpriteDataAccessExtensions.GetVertexAttribute<Vector3>(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.Position);
    18.  
    19.         Vector2 min = new Vector2(Position.Min(x => x.x), Position.Min(y => y.y));
    20.         Vector2 max = new Vector2(Position.Max(x => x.x), Position.Max(y => y.y));
    21.  
    22.         NativeArray<Vector2> newUV = new NativeArray<Vector2>(UV.Length, Allocator.Persistent);
    23.  
    24.         Vector2[] UVarray = new Vector2[UV.Length];
    25.  
    26.         for (int i = 0; i < UVarray.Length; ++i)
    27.             UVarray[i] = new Vector2((Position[i].x - min.x) / (max.x - min.x), (Position[i].y - min.y) / (max.y - min.y));
    28.  
    29.         newUV.CopyFrom(UVarray);
    30.  
    31.         SpriteDataAccessExtensions.SetVertexAttribute(sprite, UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord2, newUV);
    32.  
    33.         newUV.Dispose();
    34.     }
    35. }
    This is how I attempt to pass it to the shader.

    Code (CSharp):
    1.             struct appdata
    2.             {
    3.                 float4 vertex : POSITION;
    4.                 fixed4 color : COLOR;
    5.                 float2 uv : TEXCOORD2;
    6.             };
    7.  
    8.             struct v2f
    9.             {
    10.                 float4 vertex : SV_POSITION;
    11.                 fixed4 color : COLOR;
    12.                 float2 uv : TEXCOORD2;
    13.             };
    It seems like the shader is ignoring TEXCOORD2 altogether and get whatever is in TexCoord0 instead.
     
  33. coshea

    coshea

    Joined:
    Dec 20, 2012
    Posts:
    319
    Fantastic! Native SVG support coming to Unity.

    I've used RageTools svg in a previous game and spent a year with SVG Importer asset making this game. Everything apart from the 3d doors and food is a vector (mesh).
    http://www.cowlyowl.com/games/sizzle-stew/

    I'm trying to entirely using SVGs and if I can do that without relying on a third party plugin, great! I've downloaded 2018.2.6 and the package to give it a try on my game assets.

    I like that the original SVG is unaffected, still there for you to update without making a new asset.

    Are the shaders for SVG sprites transparent or opaque?

    I used entirely opaque in my game, no sort layer order, used z position for depth for better performance.

    How do you get around z fighting on a sprite that has many layers that overlap? In SVG Importer (asset) you had to have some z distance between layers.

    As mentioned above, the ability to colour tint without effecting draw calls or performance would be great (something I can do in SVG Importer).

    Someone mentioned particles, it depends on what your particles look like. I ended up making all my particles as svg shapes (smoke etc), using SVG Importer to save out the raw Mesh and using that in the Particle System. The ability to export a mesh from this package would also be very welcome.

    Keep up the good work.
     
  34. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    The problem seems to be caused by the use of OnPreprocessAsset(), which is executed *before* the asset is imported. So, anything written to the asset there will be overwritten when the asset is imported.

    Using OnPostprocessAllAssets() seems to work for me:

    Code (CSharp):
    1. public class SVGPostprocess : AssetPostprocessor
    2. {
    3.     static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    4.     {
    5.         foreach (var assetPath in importedAssets)
    6.         {
    7.             var assetImporter = AssetImporter.GetAtPath(assetPath);
    8.             if (!(assetImporter is SVGImporter)) return;
    9.             var importer = assetImporter as SVGImporter;
    10.  
    11.             if (!(importer.targetObject is Sprite)) return;
    12.             var sprite = importer.targetObject as Sprite;
    13.  
    14.             var Verts = sprite.vertices;
    15.  
    16.             Vector2 min = new Vector2(Verts.Min(x => x.x), Verts.Min(y => y.y));
    17.             Vector2 max = new Vector2(Verts.Max(x => x.x), Verts.Max(y => y.y));
    18.  
    19.             NativeArray<Vector2> newUV = new NativeArray<Vector2>(Verts.Length, Allocator.Persistent);
    20.  
    21.             for (int i = 0; i < newUV.Length; ++i)
    22.                 newUV[i] = new Vector2((Verts[i].x - min.x) / (max.x - min.x), (Verts[i].y - min.y) / (max.y - min.y));
    23.  
    24.             sprite.SetVertexAttribute<Vector2>(UnityEngine.Experimental.Rendering.VertexAttribute.TexCoord2, newUV);
    25.  
    26.             newUV.Dispose();
    27.         }
    28.     }
    29. }
     
  35. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    This looks great and seems to be the perfect project for using vector graphics. Good stuff!

    The SVG shaders are in the transparent queue. This gives better results for alpha-blended sprites.

    The shader has "ZWrite Off". That way, the sprite geometry won't contribute to the depth buffer and it won't z-fight with itself.

    Yes, this is something that we kind of lack at the moment. Since we use the color channel to store the colors of the SVG shapes, we lose that channel for tinting purposes. The best way around it right now is to use GPU instancing.

    The SVG importer itself doesn't (yet) have the ability to generate a mesh, but you can do it in script using the VectorUtils.FillMesh() method.

    Thanks for the feedback! :)
     
  36. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    Please take a read of https://forum.unity.com/threads/unity-ui-svg-support-script.551254/ I've gone ahead and shared our working state of SVG support in Unity UI.
     
    thaiscorpion and Korindian like this.
  37. coshea

    coshea

    Joined:
    Dec 20, 2012
    Posts:
    319
    Do you have any plans to write an opaque shader, or provide details how this one could be changed to be opaque?

    If you aren't using any alpha, then it is a performance hit. It is much better for mobile to use complete opaque objects and avoid overdraw.

    Otherwise using the built in SVG is going to be a big no go for may people.

    Thanks
     
  38. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    At this time, if you don't need alpha blending, you could make your own copy of Vector.shader and VectorGradient.shader and turn off blending in them. We will consider providing an opaque version of these shaders.
     
  39. mokus

    mokus

    Joined:
    Dec 16, 2016
    Posts:
    2
    Still no plans/schedule for Canvas UI?
     
    AbgaryanFX likes this.
  40. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
  41. nickfourtimes

    nickfourtimes

    Joined:
    Oct 13, 2010
    Posts:
    219
    I'm trying to do something along the lines of this post (top of page 5) – which is itself based off of the samples – but in the editor instead of at runtime. The idea is that we'd like to make a prefab which is an imported SVG broken down into its component parts, so we can manipulate it in the editor (make animations, &c).

    However, it keeps tripping up at the VectorUtils.BuildSprite() line, with:

    Not allowed to override geometry on sprite ''


    Looking elsewhere, it seems like this might trace back to BuildSprite() using Sprite.overrideGeometry, which apparently cannot be used in the editor.

    Is there a way around this, or some other way I could interrupt/complement the SVG importer to create the different layers of the SVG as assets on disk?
     
  42. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    The Sprite.OverrideGeometry() method can be used either at runtime, or in-editor at import time. I think the only way around this is to override the sprite geometry in an AssetPostprocessor:
    https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html

    I would try to implement OnPostprocessSprites() and implement the logic there. If that doesn't work, give a try with OnPostprocessAllAssets().
     
  43. nickfourtimes

    nickfourtimes

    Joined:
    Oct 13, 2010
    Posts:
    219
    Thanks a bunch for that, you pointed me in exactly the right direction. Using
    OnPostprocessAllAssets(), I call this function, which is a slightly modified version of (rab's version of) the sample code:

    Code (CSharp):
    1. static void SvgLayerImporter(string assetPath) {
    2.     var originalSvgPathFull = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("/") + 1) + assetPath;
    3.  
    4.     var sceneInfo = SVGParser.ImportSVG(File.OpenText(originalSvgPathFull));
    5.     if(null == sceneInfo.Scene) {
    6.         Debug.LogError("Could not parse SVG at " + originalSvgPathFull + "!");
    7.  
    8.     } else {
    9.         Debug.Log("Custom import: " + originalSvgPathFull);
    10.  
    11.         // this could probably stand to be specified elsewhere
    12.         var tessOptions = new VectorUtils.TessellationOptions() {
    13.             StepDistance = 100.0f,
    14.             MaxCordDeviation = 0.5f,
    15.             MaxTanAngleDeviation = 0.1f,
    16.             SamplingStepSize = 0.01f
    17.         };
    18.  
    19.         // duplicate the original SVG prefab and create a GameObject that will serve as a pretend "instance" of that prefab
    20.         var newPrefabLocation = assetPath.Replace(".svg", " (Split).prefab");
    21.         var newPrefab = PrefabUtility.CreateEmptyPrefab(newPrefabLocation);
    22.         var instPrefab = new GameObject();
    23.  
    24.         // go through each layer of the SVG, and in each layer, remove SVG info nodes that are *not* in that layer
    25.         int numOriginalLayers = sceneInfo.Scene.Root.Children.Count;
    26.         for (int i = 0; i < numOriginalLayers; ++i) {
    27.             var newSceneInfo = SVGParser.ImportSVG(File.OpenText(originalSvgPathFull));
    28.             int removed = 0;
    29.             var layerName = "";
    30.             for (int c = 0; c < numOriginalLayers; ++c) {
    31.                 if (c == i) {
    32.                     layerName = "Layer " + c;
    33.  
    34.                 } else {
    35.                     newSceneInfo.Scene.Root.Children.Remove(newSceneInfo.Scene.Root.Children[c - removed]);
    36.                     ++removed;
    37.                 }
    38.             }
    39.  
    40.             // instantiate the current layer as a new sprite in the scene, and attach it to our new prefab which will soon be saved to disk
    41.             var geom = VectorUtils.TessellateScene(newSceneInfo.Scene, tessOptions);
    42.             var newSprite = VectorUtils.BuildSprite(geom, 10.0f, VectorUtils.Alignment.SVGOrigin, Vector2.zero, 128, true);
    43.             newSprite.name = layerName;
    44.            
    45.             // each SVG layer will have a corresponding GameObject that's part of the new prefab
    46.             GameObject go = new GameObject(layerName);
    47.             SpriteRenderer s = go.AddComponent<SpriteRenderer>();
    48.             s.sprite = newSprite;
    49.             go.transform.SetParent(instPrefab.transform);
    50.  
    51.             // bundle the new sprite (for this layer) in with the new SVG prefab
    52.             AssetDatabase.AddObjectToAsset(newSprite, newPrefab);
    53.         }
    54.  
    55.         // now apply the changes from the instantiated prefab to the saved prefab on disk, and destroy the instance
    56.         PrefabUtility.ReplacePrefab(instPrefab, newPrefab, ReplacePrefabOptions.ReplaceNameBased);
    57.         Object.DestroyImmediate(instPrefab);
    58.     }
    59.  
    60.     return;
    61. }
    This creates a new prefab "next" to the imported SVG, and it has each layer as a separate child GameObject, as well as having saved the sprites to disk as well.

    Next step is to see if we can get the layer names from within the SVG (via SceneNode?) in order to properly name the child GameObjects and Sprites. Not sure if that's feasible right now or in the future.

    I also haven't tested this on more than a trivial SVG – there's the SVG offset bugs that are mentioned up above that worry me, and of course I guess this being a preview extension, it's subject to change.
     
  44. rab

    rab

    Joined:
    Nov 13, 2009
    Posts:
    101
    @mcoted3d: Thank you again for your hint on the geometry bounding boxes. Now everything is fitting together like in the svg import.

    Result: SVG import to a GameObject with corresponding meshes and materials for each layer in the SVG.
    SVG-Test_Erfolg_2.png SVG-Test_Erfolg_2_Detail.png
     
    mcoted3d likes this.
  45. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    This will be feasible with the next version, the SceneInfo returned by ImportSVG() will have a dictionary of IDs mapping to SceneNodes. This should be released soon.
     
    nickfourtimes likes this.
  46. Alberts

    Alberts

    Joined:
    Jul 15, 2013
    Posts:
    1
    Is it possible to work with SpriteRenderer.Color if you are using SVG files. I am playing around with that right now, but it doesn't see to be working for me..?
     
  47. shaggun

    shaggun

    Joined:
    Aug 18, 2016
    Posts:
    1
    I also wanted to use the SpriteRenderer.Color so I modified the shader a bit, now it works with gradient and solid vectors.



    I just uploaded a small repository here so anyone can use it and improve the shader as they wish, I noticed that I broke the flip functionality but I fixed it by using transform properties, I also needed to skew the vectors so I added that to the shader as well, here's the shader only:
    Code (CSharp):
    1. Shader "Unlit/Vector_Extended"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Texture", 2D) = "white" {}
    6.         [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
    7.         [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
    8.         [PerRendererData] _HorizontalSkew ("Horizontal Skew", Float) = 0
    9.         [PerRendererData] _VerticalSkew ("Vertical Skew", Float) = 0
    10.     }
    11.     SubShader
    12.     {
    13.         Tags
    14.         {
    15.             "RenderType" = "Transparent"
    16.             "Queue" = "Transparent"
    17.             "IgnoreProjector" = "True"
    18.             "PreviewType" = "Plane"
    19.         }
    20.         Cull Off
    21.         Lighting Off
    22.         ZWrite Off
    23.         Blend SrcAlpha OneMinusSrcAlpha
    24.         Pass
    25.         {
    26.             CGPROGRAM
    27.             #pragma vertex VectorVert
    28.             #pragma fragment frag
    29.             #pragma multi_compile_instancing
    30.             #include "UnityCG.cginc"
    31.             #include "UnitySprites.cginc"
    32.             struct appdata
    33.             {
    34.                 float4 vertex : POSITION;
    35.                 fixed4 color : COLOR;
    36.                 float2 uv : TEXCOORD0;
    37.                 float2 settingIndex : TEXCOORD2;
    38.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    39.             };
    40.             struct v2f2
    41.             {
    42.                 fixed4 color : COLOR;
    43.                 float2 uv : TEXCOORD0; // uv.z is used for setting index
    44.                 float2 settingIndex : TEXCOORD2;
    45.                 float4 vertex : SV_POSITION;
    46.             };
    47.             //sampler2D _MainTex;
    48.             float4 _MainTex_ST;
    49.             float4 _MainTex_TexelSize;
    50.          
    51.             float _HorizontalSkew;
    52.             float _VerticalSkew;
    53.        
    54.             v2f2 VectorVert (appdata v)
    55.             {
    56.                 v2f2 o;
    57.                 UNITY_SETUP_INSTANCE_ID (v);
    58.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);  
    59.                 o.vertex = UnityObjectToClipPos(v.vertex);          
    60.                 #ifdef UNITY_COLORSPACE_GAMMA              
    61.                 fixed4 col = v.color;          
    62.                 #else
    63.                 fixed4 col = fixed4(GammaToLinearSpace(v.color.rgb), v.color.a);              
    64.                 #endif
    65.                 o.color = col * _RendererColor;      
    66.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);          
    67.                 o.settingIndex = v.settingIndex;
    68.                 //Create a skew transformation matrix
    69.                 float h = _HorizontalSkew;
    70.                 float vs = _VerticalSkew;
    71.                 float4x4 transformMatrix = float4x4(
    72.                     1,h,0,0,
    73.                     vs,1,0,0,
    74.                     0,0,1,0,
    75.                     0,0,0,1);
    76.                     float4 skewedVertex = mul(transformMatrix, v.vertex);
    77.                     o.vertex = UnityObjectToClipPos(skewedVertex);  
    78.                 return o;
    79.             }
    80.             float2 unpackFloat2(fixed4 c)
    81.             {
    82.                 return float2(c.r*255 + c.g, c.b*255 + c.a);
    83.             }
    84.             float2 rayUnitCircleFirstHit(float2 rayStart, float2 rayDir)
    85.             {
    86.                 float tca = dot(-rayStart, rayDir);
    87.                 float d2 = dot(rayStart, rayStart) - tca * tca;
    88.                 float thc = sqrt(1.0f - d2);
    89.                 float t0 = tca - thc;
    90.                 float t1 = tca + thc;
    91.                 float t = min(t0, t1);
    92.                 if (t < 0.0f)
    93.                     t = max(t0, t1);
    94.                 return rayStart + rayDir * t;
    95.             }
    96.             float radialAddress(float2 uv, float2 focus)
    97.             {
    98.                 uv = (uv - float2(0.5f, 0.5f)) * 2.0f;
    99.                 float2 pointOnPerimeter = rayUnitCircleFirstHit(focus, normalize(uv - focus));
    100.                 float2 diff = pointOnPerimeter - focus;
    101.                 if (abs(diff.x) > 0.0001f)
    102.                     return (uv.x - focus.x) / diff.x;
    103.                 if (abs(diff.y) > 0.0001f)
    104.                     return (uv.y - focus.y) / diff.y;
    105.                 return 0.0f;
    106.             }
    107.             fixed4 frag (v2f2 i) : SV_Target
    108.             {
    109.            
    110.                 int settingBase = ((int)(i.settingIndex.x + 0.5f)) * 3;
    111.                 float2 texelSize = _MainTex_TexelSize.xy;
    112.                 float2 settingUV = float2(settingBase + 0.5f, 0.5f) * texelSize;
    113.                 float2 uv = i.uv;
    114.                 fixed4 gradSettings = tex2D(_MainTex, settingUV);
    115.                 if (gradSettings.x > 0.0f)
    116.                 {
    117.                     // Radial texture case
    118.                     float2 focus = (gradSettings.zw - float2(0.5f, 0.5f)) * 2.0f; // bring focus in the (-1,1) range              
    119.                     uv = float2(radialAddress(i.uv, focus), 0.0);
    120.                 }
    121.                 int addressing = gradSettings.y * 255;
    122.                 uv.x = (addressing == 0) ? fmod(uv.x,1.0f) : uv.x; // Wrap
    123.                 uv.x = (addressing == 1) ? max(min(uv.x,1.0f), 0.0f) : uv.x; // Clamp
    124.                 float w = fmod(uv.x,2.0f);
    125.                 uv.x = (addressing == 2) ? (w > 1.0f ? 1.0f-fmod(w,1.0f) : w) : uv.x; // Mirror
    126.                 // Adjust UV to atlas position
    127.                 float2 nextUV = float2(texelSize.x, 0);
    128.                 float2 pos = (unpackFloat2(tex2D(_MainTex, settingUV+nextUV) * 255) + float2(0.5f, 0.5f)) * texelSize;
    129.                 float2 size = unpackFloat2(tex2D(_MainTex, settingUV+nextUV*2) * 255) * texelSize;
    130.                 uv = uv * size + pos;
    131.              
    132.                 fixed4 texColor = tex2D(_MainTex, uv);
    133.                 #ifndef UNITY_COLORSPACE_GAMMA
    134.                 texColor = fixed4(GammaToLinearSpace(texColor.rgb), texColor.a);
    135.                 #endif
    136.                 return texColor * i.color;
    137.             }
    138.             ENDCG
    139.         }
    140.     }
    141. }
    142.  
     
    ZealousProgramming and mcoted3d like this.
  48. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    101
    Hi, loving the vector graphics preview, thanks! One quick question. When importing svgs from Adobe Illustator, they don't scale when adjusting the PPU settings. This works when importing them from photoshop. Is this a bug or am I missing something? Many thanks!
     
  49. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    998
    It's a bug. It occurs when the SVG file has a viewbox defined, this will get fixed soon. In the meantime, you can play with the SVG export option to see if there's something that prevents it to output a viewbox (I don't remember which option does this off hand, I'll let you know when I find out).
     
  50. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    101
    I see, I use "export selection" so I have to open the exported SVG then save and uncheck "Responsive" in the advanced settings. Hopefully one day the unity importer can strip the viewbox attribute. Thanks for the heads up!
     
    mcoted3d likes this.