Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Official Introducing the Vector API in Unity 2022.1

Discussion in 'UI Toolkit' started by SimonDufour, Dec 10, 2021.

  1. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    The code looks fine. I think the border is a side-effect of the geometry generated by the Painter2D. The geometry is slightly larger than the visible content to make room for antialiasing.

    If you can open a new issue (Help > Report a Bug...) that would be appreciated.
     
  2. AndreaGalet

    AndreaGalet

    Joined:
    May 21, 2020
    Posts:
    63
    Done, thank you, IN-45080
     
    mcoted3d likes this.
  3. Nostromos

    Nostromos

    Joined:
    Nov 30, 2019
    Posts:
    22
    this is awesome and i got simple bezier curves working between 2 buttons in my UI. Great job! This is going to be great to work with. A couple dumb questions...where do i go to find the full documentation of the latest of this API so i can see full functionality (is that available?)

    Also, does hover over (Mouse Enter Mouse Leave) events work for lines? i have this code here and when i hover over the line it doesn't detect my mouse. Is this even supported?


    Code (CSharp):
    1. class LineDrawerElement : VisualElement
    2. {
    3.     public Vector2 startPoint { get; set; }
    4.     public Vector2 endPoint { get; set; }
    5.     public Color lineColor { get; set; }
    6.     public Color hoverColor { get; set; }
    7.     public Color defaultColor { get; set; }
    8.  
    9.     public LineDrawerElement()
    10.     {
    11.         generateVisualContent += OnGenerateVisualContent;
    12.  
    13.         RegisterCallback<MouseEnterEvent>(evt =>
    14.         {
    15.             Debug.Log("MouseEnterEvent got called");
    16.             lineColor = hoverColor;
    17.             MarkDirtyRepaint();
    18.         });
    19.         RegisterCallback<MouseLeaveEvent>(evt =>
    20.         {
    21.             Debug.Log("MouseLeaveEvent got called");
    22.             lineColor = defaultColor;
    23.             MarkDirtyRepaint();
    24.         });
    25.  
    26.         pickingMode = PickingMode.Position;
    27.     }
    //...the rest of my class that draws a bezier between 2 points (visualelements). Works wonderfully and is a nice thick line 15.0f so plenty of room for mouse detection i would think.

    Thanks this is coming together nicely!
     
  4. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    Thanks! The Painter2D API docs would be a good start:
    https://docs.unity3d.com/ScriptReference/UIElements.Painter2D.html

    The whole VisualElement should still detect the mouse events, but it will detect events over the rectangular region covered by the element. Here, I suspect the element has a size of (0,0) so no mouse events got captured.
    You will probably have to position and resize the element to cover the whole line to make it work.

    The ContainsPoint method could help here:
    https://docs.unity3d.com/ScriptReference/UIElements.VisualElement.ContainsPoint.html

    In that method, if you return true only when the mouse cursor is near the line, you would effectively get a mouse event that triggers only for the line.
     
  5. Nostromos

    Nostromos

    Joined:
    Nov 30, 2019
    Posts:
    22
    Awesome thanks! Keep up the most excellent work!
     
  6. Adrien_CareprodTech

    Adrien_CareprodTech

    Joined:
    Aug 22, 2023
    Posts:
    9
    Hello, I'm trying to make drawing tools with Painter2D. It's look great with this code for simple draw

    Code (CSharp):
    1.     public class ShapeElement : VisualElement
    2.     {
    3.         public new class UxmlFactory : UxmlFactory<ShapeElement> { }
    4.  
    5.         public Color Color;
    6.  
    7.         public List<Line> Lines = new List<Line>();
    8.  
    9.         private Line currentLine;
    10.  
    11.         public ShapeElement()
    12.         {
    13.             style.height = Length.Percent(100);
    14.             style.width = Length.Percent(100);
    15.             generateVisualContent += GenerateVisualContent;
    16.             RegisterCallback<PointerDownEvent>(OnPointerDownEvent);
    17.             RegisterCallback<PointerUpEvent>(OnPointerUpEvent);
    18.         }
    19.  
    20.         private void OnPointerDownEvent(PointerDownEvent evt)
    21.         {
    22.             RegisterCallback<PointerMoveEvent>(OnPointerMoveEvent);
    23.             currentLine = new Line(new(), Color, 10);
    24.             Lines.Add(currentLine);
    25.         }
    26.  
    27.         private void OnPointerMoveEvent(PointerMoveEvent evt)
    28.         {
    29.             // We need to invert Y
    30.             Vector2 currentPos = Input.mousePosition;
    31.             currentPos.y = Screen.height - currentPos.y;
    32.             currentLine.Points.Add(currentPos);
    33.             MarkDirtyRepaint();
    34.         }
    35.  
    36.         private void OnPointerUpEvent(PointerUpEvent evt)
    37.         {
    38.             UnregisterCallback<PointerMoveEvent>(OnPointerMoveEvent);
    39.         }
    40.  
    41.         void GenerateVisualContent(MeshGenerationContext ctx)
    42.         {
    43.             var painter = ctx.painter2D;
    44.             painter.lineJoin = LineJoin.Round;
    45.             painter.lineCap = LineCap.Round;
    46.  
    47.             foreach (var line in Lines)
    48.             {
    49.                 painter.lineWidth = line.LineWidth;
    50.                 painter.strokeColor = line.Color;
    51.                 painter.BeginPath();
    52.                 painter.MoveTo(line.Points[0]);
    53.                 for (int i = 1; i < line.Points.Count; i++)
    54.                 {
    55.                     painter.LineTo(line.Points[i]);
    56.                 }
    57.                 painter.Stroke();
    58.             }
    59.         }
    60.     }
    My Line class :
    Code (CSharp):
    1.     public class Line
    2.     {
    3.         public List<Vector2> Points;
    4.         public Color Color;
    5.         public float LineWidth;
    6.         public Line(List<Vector2> points, Color color, float lineWidth)
    7.         {
    8.             Points = points;
    9.             Color = color;
    10.             LineWidth = lineWidth;
    11.         }
    12.     }

    But I want to add eraser and I'm a bit lost. I tried to set color to Color.clear but it is not the solution.
    How can I erase existing point ?

    Thanks
     
  7. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    It depends how the eraser should work. You can make it so that it erases full paths that were drawn in the past, in which case you just need to stop drawing that path. But you probably want a photoshop-style eraser, which has its own shape. This would require "baking" your content in a texture and erasing that content instead.
     
  8. Adrien_CareprodTech

    Adrien_CareprodTech

    Joined:
    Aug 22, 2023
    Posts:
    9
    Thanks for your reply !

    upload_2023-8-29_15-42-27.png

    I want something like this.
    I was thinking of "cutting" my path into 2 new ones but it seems I don't have enough points to do it smoothly.
    I don't understand the "baking" part, can you elaborate?
     
  9. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    Instead of drawing the paths "on screen", you would perform the drawing in a RenderTexture, using a PanelSettings configured to render in a RenderTexture (RT).

    Then you can erase by making part of that RT transparent. Unfortunately, because of the way the blending is setup in UI Toolkit, drawing transparent paths will not be enough to paint transparency in the RT. The way I would do it is using an "eraser texture" that will only write alpha values using a custom material that has the blending mode properly setup.

    Let me know if you need more details.
     
  10. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,104
    Turns out I am not (and I'm confused why you thought this and the Spline Package are somehow equivalent?).

    The Spline Package does nothing I want, while I would like to use the vector API for my own in-universe 3d worldspace UIs. Tying it to the Artist previously known as UIElements is a mistake.
     
  11. Adrien_CareprodTech

    Adrien_CareprodTech

    Joined:
    Aug 22, 2023
    Posts:
    9

    I understand the idea but I'm not sure about the implementation. Do I need to create a custom render texture (like https://docs.unity3d.com/Manual/class-CustomRenderTexture.html) and give it a transparent material? And then add zones with position and size where I want to erase?
     
  12. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    That sounds right!
     
  13. Adrien_CareprodTech

    Adrien_CareprodTech

    Joined:
    Aug 22, 2023
    Posts:
    9
    I tried this solution but I'm not convinced because the update zones for custom RT feel chaotic to me, they don't behave like I expect them to and I can't find a way to use them properly.
    Do you know of any other solution to create an eraser? Or can you provide me an example of custom RT as you described them?
     
  14. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    I had a proof-of-concept of Painter2D drawing to a RenderTexture (drawing with the left mouse button). I added an "eraser" support with the right mouse button. I'm attaching the demo project here.

    Some notes:
    • There an object "PaintInteraction" that only draws the "preview" of the line being drawn.
    • When the left mouse button is released, the path is sent to the "PaintBaker" which draws the same path to the target render texture.
    • The render texture is rendered over the camera with the "RenderTextureOverCamera" script.
    • The demo uses a fixed-size render texture (HD resolution), but doing a dynamic resolution is feasible.
    • The eraser is done with a shader that only multiplies the incoming alpha to the render target's alpha, hence acting as a thing that draws transparency.
    Eraser.gif

    Hope this help.
     

    Attached Files:

    Fep310, Mj-Kkaya, ontrigger and 3 others like this.
  15. Adrien_CareprodTech

    Adrien_CareprodTech

    Joined:
    Aug 22, 2023
    Posts:
    9
    Thank you !
    It works pretty well but it looks like the eraser is applied with not enough intensity upload_2023-9-21_15-35-24.png
    I erase by clicking once, twice, etc... and I would like to erase like the last one even with a single click.

    Other thing I noticed is when I moved my cursor fast, it erase points but doesn't link them. upload_2023-9-21_15-38-54.png
    Is it possible to link them ?

    And a last question, how can I clear my texture from all drawing points ?
     
  16. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    974
    That's correct. The current solution simply stamps a little square at the current mouse position. You'll have to pass over a few times to bring the texture to fully transparent. Using a more opaque eraser texture will help.

    Linking the eraser points could be done by creating an eraser mesh that covers back to the last mouse position instead of stamping a little square at the current mouse position. Look at the GL.Vertex3 calls in PaintEraser.cs. That mesh could be stretched to cover the whole last pos/current pos distance.

    To clear the texture, you can use the same method at the beginning of the Start() method in PaintBaker.cs.

    Hope this helps!
     
    Adrien_CareprodTech likes this.
  17. Adrien_CareprodTech

    Adrien_CareprodTech

    Joined:
    Aug 22, 2023
    Posts:
    9
    IT WORKS !
    Thank you sooooo much for your time.

    It looks like this for now
    eraserDemo.gif

    I currently store my drawing in a RT and display it on a cube for my project's needs.

    I upload my POC here if someone want to try it. Just open the scene, play it and select GameManager in hierarchy to have access to different options buttons.
     

    Attached Files:

    hou4jau4coi3 and mcoted3d like this.