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

Warp/bend the UI

Discussion in 'UGUI & TextMesh Pro' started by Demozo, Nov 30, 2014.

  1. Demozo

    Demozo

    Joined:
    Aug 19, 2014
    Posts:
    20
    I'm looking to create an effect like this



    I was thinking about using "projection matrices" or something like that but I have no clue how those work or what they are in detail.

    I know you can rotate the elements in the UI but that doesn't give a nice smooth cylinder-ish effect, and messes up when using worldspace mode.

    EDIT: I apologize if the image is inappropriate due to the background, but it was the best image I could find which showed what I was looking for in detail.
     
    ahmadian and thienhaflash like this.
  2. Mikeysee

    Mikeysee

    Joined:
    Oct 14, 2013
    Posts:
    155
    Hmm I would definately say you need some sort of post-process effect here. If you don't get an answer perhaps ask the shader lab forum, those guys know their stuff.
     
    shkar-noori likes this.
  3. Demozo

    Demozo

    Joined:
    Aug 19, 2014
    Posts:
    20
    Will do thanks!
     
  4. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    Lol... unity releases advanced, highly streamlined visual UI editor and then the first thing people do is try to make it do things beyond it's original intended functionality. :D
     
  5. Demozo

    Demozo

    Joined:
    Aug 19, 2014
    Posts:
    20
    It's not the first thing I've done with it though. :p
    And part of it's intended functionality is to be highly customizable.
     
  6. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    Render your 2D UI to a texture (requires Unity Pro, though), then map onto a curved mesh.
     
  7. Demozo

    Demozo

    Joined:
    Aug 19, 2014
    Posts:
    20
    Sadly I do not own Unity Pro. Any other ideas? Or how I might get the equivalent of a rendertexture on Free.
     
  8. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    Just a quick note that this only really works for non-interactible elements, as the hitboxes for buttons etc. don't warp along. Unless you write your own wrapper for this of course. =)
     
  9. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    You seriously could have just use a flat menu though? Do you absolutely 100% have to copy this game exactly? You could achieve some really interesting effects with the built-in system
     
  10. Midnitte

    Midnitte

    Joined:
    Apr 16, 2014
    Posts:
    2
    Could you perhaps do this for menus that are meant to be controlled by key presses instead of mouse clicks?

    Likewise, you could always fake it being shaped that way - merely use graphics which give the impression of it being bent like SAO.
     
  11. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    @Midnitte: It would definitely work for keypress-controlled UIs! You could probably even make it work for mouse clicks relatively easy. I'm guessing there's likely a way to get the UV coordinates (or fake them) of wherever the mouse or touch is hovering over, which you could then use to send the appropriate event to the correct UI element through an Event System.

    Using bent graphics is all fine and well until you need something dynamic, like a moving element, a masked HP bar, or even dynamic text.

    I'm really curious if a non-pro solution for this exists; following this thread ancipitatedly!
     
    thienhaflash and Midnitte like this.
  12. Demozo

    Demozo

    Joined:
    Aug 19, 2014
    Posts:
    20
    It's not this game perse I just like the visor-like effect it has. I could have posted a screenshot of Borderlands, Dead Space w/e here. It's just that this screenshot shows best what I want.
     
  13. XKnightmare

    XKnightmare

    Joined:
    Sep 1, 2014
    Posts:
    5
    I actually have a system like what your describing in my current UI. I actually use several masked "segments" and make a copy of each canvas and place them on the tangent angle of the canvas. This gives a very nice illusion of being curved. The quality of this curved is based on the amount of segments and the angle they produced. Of course, you will need to probably write your own UI code like I had to with Listeners. Because you need to have interaction of each segment's copy of the same UI element such as a Button. So if the user hovers over said button, all copies of that button will correctly update. I also wrote plenty of code that helps optimize this solution so you don't have needless copies of a element that weren't in that segment. Even with this solution, I have maintained a very high level of FPS. I think the biggest hindered of this solution was the issue of the Text.
     
  14. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    Nothing like holding up/derailing your entire game over one feature. :rolleyes:
     
    SunkInk29 likes this.
  15. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    You can't expect an effect like this in Unity free. Most of the ultra spectacular/complex/special visual effects can only be achieved from pro. One alternative to consider for free is building the UI with physics colliders, then implementing all of the UI components you want with physics. You can use the same interfaces and events system.

    In pro the RenderTexture method would not be too hard to implement. For the interaction you could simply get the point that the user clicked on the texture, convert that back to canvas space, then ray cast into your actual UI and pass the event through there. Unfortunately I don't have pro to play around with this and write you the code. If anyone is willing to pay for my pro licence I can write you a curvy UI script. :)
     
  16. Ony

    Ony

    Joined:
    Apr 26, 2009
    Posts:
    1,977
  17. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    It exists, just go pay for it like everybody else.
     
  18. Gibbonator

    Gibbonator

    Joined:
    Jul 27, 2012
    Posts:
    204
    I had a go at doing this without using render textures and came up with something that works. In theory this will work in non-pro Unity but I haven't tested it since I have pro installed.

    These are the problems that need solving:
    1) Mapping of input positions so they line up correctly with graphics.
    2) Mapping of veritices so they appear in the correct place.
    3) Tessellation of UI elements so non-linear transforms can be approximated. This is an essential stage if you cannot use render textures. If you don't do this then the UI will not correctly wrap around curved surfaces.

    Here is how I solved each stage:
    1) Unity UI already has a GraphicRaycaster class. This implements a Raycast method that takes an input event and populates a list of RaycastResults based on things the ray hits. I wrote a class that inherits from GraphicRaycaster and overrides the Raycast method. In the overridden method I pass eventData.position through a mapping and write back the result into the same event. I then call the base class implementation of Raycast to do all the default raycasting work, but with the modified position.

    2) Mapping of vertices is all done in a vertex shader. For each type of mapping you need to write a new shader (actually two, fonts are handled separately but they can share code). You don't need to do everything from scratch. Use the default UI shaders available in the built in shaders download as a starting point. Unity UI also provides the IMaterialModifier interface, you can use this to implement a behaviour that sets up all the parameters your vertex shader needs. I actually have a single mapping behaviour that lives on the canvas object. All the UI graphic components have modifiers that fetch the mapping using GetComponentInParent and ask the mapping to configure the material for them.

    3) Unity UI has the IVertexModifier interface and the BaseVertexEffect behaviour that can be used to modify geometry it generates. As far as I can tell all the geometry that gets passed to the ModifyVertices method is arranged as quads. Using this assumption you can subdivide the quads based on their size and append the results to the vertex list. You then delete all the old quads from the list. Producing subdivided vertices just involves lots of bilinear interpolation of vertex attributes.

    A couple more things to mention:
    As far as I can tell you can't merge stages 2 and 3 into a single stage just using a vertex modifier. This is because vertices are kept in object space for each graphic then merged into big canvas space buffers.
    Tessellation of the UI elements can introduce a lot of vertices, so be careful, this may impact performance.

    Here is a cylinder mapped UI using this technique:
    CurvedUI.png
    And a UI distorted by a sin wave:
    CurvedUISinWave.png

    There should also be a demo package attached...

    HTH
     

    Attached Files:

  19. Breyer

    Breyer

    Joined:
    Nov 10, 2012
    Posts:
    412
    @Gibbonator

    Did you try adding bending to .z property of uivertex.position? I modified your solution and this work for me. You only have to check data bending (as anim curve or as progammatic equation) on root (usually canvas go) and check canvas position (so you have to convert local position to local position for whole canvas) of generated uivertex and calculate proper bending thanks to this canvas position. What is even better because i dont need custom shader nor raycaster and imaterialmodifier

    Anyway thanks for sharing solution! without your work i probably never develop this version
     
    Last edited: Dec 15, 2014
  20. Gibbonator

    Gibbonator

    Joined:
    Jul 27, 2012
    Posts:
    204
    @Breyer

    I did notice that the example in the Unity scripting reference shows that the vertex z component can be changed (http://docs.unity3d.com/ScriptReference/UI.BaseVertexEffect.html). I decided on the shader approach since I wanted to work in canvas space.

    If you're keeping everything in object space as you describe, then you'll need to call SetVerticesDirty on any graphic when it moves. If your UI isn't moving much then this is probably a better way of doing things.

    I also like your idea of using an animation curve to define the curvature of the UI :)
     
  21. Breyer

    Breyer

    Joined:
    Nov 10, 2012
    Posts:
    412
    i think this can be also useable for uneven&complex line drawing like in skill tree in many games (PoE for instance). maybe this wont be super effective since this isnt built-in feature but Unity havent line drawing feature for uGUI (only simple line in runtime and complex in editor only but without any support for uGUI) There is need for some changes like better editor script (3x anim curves/programmatic equations for all dimension - optional 1 for .z bending, 1 for .y curvature and optionally 1 for .x offsetting)
     
  22. brendan-vance

    brendan-vance

    Joined:
    Jan 16, 2014
    Posts:
    36
    Couldn't you do the UI in worldspace and use a camera with a really strong perspective (ie: a fisheye lens)?
     
    jalapen0 likes this.
  23. asadsohail

    asadsohail

    Joined:
    Sep 13, 2012
    Posts:
    3
    Hi @Gibbonator,

    You have done an awesome job by making these warp/bend curve shaders. I am using your package and I have set everything according to your example scenes but I am facing an issue here. When I assign UI-Cyclinder material to any of UI element the image or sprite disappears and stays disappeared. Please help me in this regard. @SimonDarksideJ Please contribute and help me resolving this issue. Thanks in advance.
     
    Last edited: Feb 16, 2015
  24. Play_Edu

    Play_Edu

    Joined:
    Jun 10, 2012
    Posts:
    722
    Awesome stuff man
     
  25. TechnicalArtist

    TechnicalArtist

    Joined:
    Jul 9, 2012
    Posts:
    736
    useful update
     
  26. vuong_vin

    vuong_vin

    Joined:
    Sep 17, 2014
    Posts:
    18
    Hello, I import your assets to my scene and have error: error CS0117: `UnityEngine.RenderMode' does not contain a definition for `ScreenSpaceCamera'. What is it? and how can i fix? Thanks
     
  27. Gibbonator

    Gibbonator

    Joined:
    Jul 27, 2012
    Posts:
    204
    Hi,

    Sorry for the late replies. I've not been on the forums in a while.

    @asadsohail
    My guess is the parameters that define the cylinder are not being set on the materials. To ensure this happens you need to do two things:
    1) Make sure there is a CylinderMapping script added to the Canvas object at the root of your UI. This holds the parameters that define the cylinder. You should be able to change the parameters using the inspector.
    2) Add a MappedGraphicMaterialModifier script to the Graphic object (e.g. Image, Text). This will take the Material that the Graphic uses and ask the CylinderMapping to set the parameters on it.

    You can also try resetting the CylinderMapping (right click menu in the inspector). This will force all the materials that the graphics use to be marked as dirty.

    @quenhoai2003
    I'm not sure what's going on here. I've tried this in Unity 4.6.4 and it compiles fine. Are you using Unity 5? AFAICT 5 still has ScreenSpaceCamera in the RenderMode enum.

    As a last resort you can just remove that if statement:
    Code (csharp):
    1.  
    2. if (m_canvas.renderMode != RenderMode.ScreenSpaceCamera)
    3. {
    4.     Debug.LogWarning("Cylinder mapping works best in ScreenSpaceCamera mode", this);
    5. }
    6.  
    It's just a warning, not a critical part of the code.
     
  28. arklay_corp

    arklay_corp

    Joined:
    Apr 23, 2014
    Posts:
    242
    @Breyer
    Would you mind sharing your updated solution?
     
  29. Breyer

    Breyer

    Joined:
    Nov 10, 2012
    Posts:
    412
    sorry i stopped this project. Im completely sure (especially since UI is mostly open sourced) this is possible but lost interest myself in this project.
     
  30. arklay_corp

    arklay_corp

    Joined:
    Apr 23, 2014
    Posts:
    242
    ok, thanks anyway :)
     
  31. isidro02139

    isidro02139

    Joined:
    Jul 31, 2012
    Posts:
    72
    @Gibbonator Thanks for this fantastic example, it has really helped me on my VR project :)

    I'm having one issue now, which is that I can't seem to locate the distorted ui in world-space to draw my cursor over it:
    Screen Shot 2015-08-31 at 12.48.04.png

    I guess what is happening is the UI mesh geometry is being distorted by the UI-Cylinder material and shader but it's collider remains in non-distorted world space (?) Will experiment and report back if I can get everything working!

    UPDATE #1: I realized that I wasn't finding the right "screen" space value where my virtual PointerEvent data should be placed. Below is a screenshot where the Yellow line is my new calculation of a custom PointerEventData hitting the warped ui (and the hit is correctly detected):
    Screen Shot 2015-08-31 at 18.44.16.png

    However this calculation is still wrong, the yellow line should start at where the green line (VR focus ray) intersects the canvas plane and stay perpendicular to the plane... will keep at it ^^
     
    Last edited: Aug 31, 2015
  32. blastone

    blastone

    Joined:
    Apr 7, 2009
    Posts:
    168
    hey @Gibbonator
    This looks really awesome, my question, how would I make the cylinder effect go top to bottom, instead of left to tight?
     
  33. RazaTech

    RazaTech

    Joined:
    Feb 27, 2015
    Posts:
    178
    hi!
    i m facing following issue in curved ui pkg

    Assets/CurvedUI/Scripts/TessellationVertexEffect.cs(6,14): error CS0619: `UnityEngine.UI.BaseVertexEffect' is obsolete: `Use BaseMeshEffect instead'
     
  34. arklay_corp

    arklay_corp

    Joined:
    Apr 23, 2014
    Posts:
    242
    aammfee, you need the core, VertexEffect must inherit from BaseMeshEffect instead of BaseVertexEffect.

    It doesnt work out of the box anymore
     
    RazaTech likes this.
  35. RazaTech

    RazaTech

    Joined:
    Feb 27, 2015
    Posts:
    178
    try to modify it , but it does not work ,

    if you , r any body have lastes ui curve pkg.?
     
  36. arklay_corp

    arklay_corp

    Joined:
    Apr 23, 2014
    Posts:
    242
    I was giving it a try but i dropped it and implemented another custom solution.

    If you are developing for windows, if i remember right, you can use tesselation on the GPU and forget about the VertexEffect.

    (I'm talking from memory, i worked this solution only for a couple of days)
     
  37. arklay_corp

    arklay_corp

    Joined:
    Apr 23, 2014
    Posts:
    242
    Also notice that when you warp a canvas element your shader will receive the whole canvas, that means that UV coordinate 0,0 is the top left of your canvas, not the element you are bending.
     
  38. chisely

    chisely

    Joined:
    Jan 14, 2016
    Posts:
    6
    Hey there!

    Ive made my own solution to the warped canvas problem. It works in unity 5.1 and above and uses object space so you can use it from any direction. If you are wondering if it will suit your needs just ask here or reach me at
    curvedui[at]chisely.com. I'll be glad to help.

    Check it out on asset store:
    http://u3d.as/nmE

     
  39. Phazeshift

    Phazeshift

    Joined:
    Jan 31, 2016
    Posts:
    3
    Chisely, that is exactly what I'm looking for! Thanks for this. I'm just learning Unity from scratch while learning to program a UI for VR.
     
  40. Abrita

    Abrita

    Joined:
    Jun 17, 2015
    Posts:
    1
    I changed the TessallationVertexEffect class to work in Unity 5.4

    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections;
    using System.Collections.Generic;

    public class TessellationVertexEffect : MonoBehaviour
    {
    #region BaseMeshEffect

    public void ModifyVertices(Mesh verts)
    {
    List<UIVertex> list = new List<UIVertex>();
    using (VertexHelper vertexHelper = new VertexHelper(verts))
    {
    vertexHelper.GetUIVertexStream(list);
    }
    if (verts.vertexCount == 0)
    {
    // Nothing to do...
    return;
    }

    // Assume we are getting quads
    if ((verts.vertexCount % 4) != 0)
    {
    Debug.LogError("Modifier expects vertices to be arranged as quads");
    return;
    }

    // Tessellate
    int startingVertexCount = verts.vertexCount;
    for (int i = 0; i < startingVertexCount; i += 4)
    {
    TessellateQuad(list, i);
    }

    // Remove old quads from the start of the list
    list.RemoveRange(0, startingVertexCount);
    }

    #endregion

    void TessellateQuad(List<UIVertex> verts, int vertexIndex)
    {
    // Read the existing quad vertices
    UIVertex v0 = verts[vertexIndex];
    UIVertex v1 = verts[vertexIndex + 1];
    UIVertex v2 = verts[vertexIndex + 2];
    UIVertex v3 = verts[vertexIndex + 3];

    // Position deltas, A and B are the local quad up and right axes
    Vector3 dPdA = v2.position - v1.position;
    Vector3 dPdB = v1.position - v0.position;

    // Determine how many tiles there should be
    float rcpTessSize = 1.0f / Mathf.Max(1.0f, m_tessellationSize);
    int aQuads = Mathf.CeilToInt(dPdA.magnitude * rcpTessSize);
    int bQuads = Mathf.CeilToInt(dPdB.magnitude * rcpTessSize);

    // Build the sub quads
    float rcpAQuads = 1.0f / (float)aQuads;
    float rcpBQuads = 1.0f / (float)bQuads;
    float startBProp = 0.0f;
    for (int b = 0; b < bQuads; ++b)
    {
    float endBProp = (float)(b + 1) * rcpBQuads;
    float startAProp = 0.0f;
    for (int a = 0; a < aQuads; ++a)
    {
    float endAProp = (float)(a + 1) * rcpAQuads;

    // Append new quad to list
    verts.Add(Bilerp(v0, v1, v2, v3, startAProp, startBProp));
    verts.Add(Bilerp(v0, v1, v2, v3, startAProp, endBProp));
    verts.Add(Bilerp(v0, v1, v2, v3, endAProp, endBProp));
    verts.Add(Bilerp(v0, v1, v2, v3, endAProp, startBProp));

    startAProp = endAProp;
    }
    startBProp = endBProp;
    }
    }

    #region Interpolation

    // TODO: This could all be optimised by calculating the four weighting factors once
    // and re-using the result for all attributes

    UIVertex Bilerp(UIVertex v0, UIVertex v1, UIVertex v2, UIVertex v3, float a, float b)
    {
    UIVertex output;
    output.position = Bilerp(v0.position, v1.position, v2.position, v3.position, a, b);
    output.normal = Bilerp(v0.normal, v1.normal, v2.normal, v3.normal, a, b);

    // Bilerping w is almost certainly not the right thing to do here
    output.tangent = Bilerp(v0.tangent, v1.tangent, v2.tangent, v3.tangent, a, b);

    output.uv0 = Bilerp(v0.uv0, v1.uv0, v2.uv0, v3.uv0, a, b);
    output.uv1 = Bilerp(v0.uv1, v1.uv1, v2.uv1, v3.uv1, a, b);
    output.color = Bilerp(v0.color, v1.color, v2.color, v3.color, a, b);
    return output;
    }

    float Bilerp(float v0, float v1, float v2, float v3, float a, float b)
    {
    float top = Mathf.Lerp(v1, v2, a);
    float bottom = Mathf.Lerp(v0, v3, a);
    return Mathf.Lerp(bottom, top, b);
    }

    Vector2 Bilerp(Vector2 v0, Vector2 v1, Vector2 v2, Vector2 v3, float a, float b)
    {
    Vector2 top = Vector2.Lerp(v1, v2, a);
    Vector2 bottom = Vector2.Lerp(v0, v3, a);
    return Vector2.Lerp(bottom, top, b);
    }

    Vector3 Bilerp(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3, float a, float b)
    {
    Vector3 top = Vector3.Lerp(v1, v2, a);
    Vector3 bottom = Vector3.Lerp(v0, v3, a);
    return Vector3.Lerp(bottom, top, b);
    }

    Vector4 Bilerp(Vector4 v0, Vector4 v1, Vector4 v2, Vector4 v3, float a, float b)
    {
    Vector4 top = Vector4.Lerp(v1, v2, a);
    Vector4 bottom = Vector4.Lerp(v0, v3, a);
    return Vector4.Lerp(bottom, top, b);
    }

    Color Bilerp(Color v0, Color v1, Color v2, Color v3, float a, float b)
    {
    Color top = Color.Lerp(v1, v2, a);
    Color bottom = Color.Lerp(v0, v3, a);
    return Color.Lerp(bottom, top, b);
    }

    #endregion

    [SerializeField]
    float m_tessellationSize = 10.0f;
    }
     
  41. infinite360VR

    infinite360VR

    Joined:
    Apr 19, 2016
    Posts:
    23
    @chisely

    I bought this assetCurved UI - VR Ready Solution To Bend / Warp Your Canvas! to work with Oculus Gear VR and found a problem. As It only bends Graphics (and displace them from actual UI elements position), so interaction doesn't work well with Oculus Gaze input for certain UI items. Because UI interaction detects rect transform instead of displayed image. If user is click at button graphic, nothing happens, if user clicks at position where rect transform is placed it works. creates annoying behaviour as sometimes I point and click on one button and next button receives clicks. Please fix it asap
     
  42. Konst

    Konst

    Joined:
    Aug 26, 2013
    Posts:
    78
  43. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    583
    Nice, but now it doesn't seem to work on images in 5.6. Any idea why?
     
  44. ColorStorm

    ColorStorm

    Joined:
    Jul 4, 2012
    Posts:
    28
    Seems like the output variable needs to be assigned.

    UIVertex output = new UIVertex();

    But sliders and buttons are not bent?
     
  45. Amarbaysgalan

    Amarbaysgalan

    Joined:
    Nov 24, 2017
    Posts:
    2
    please help me i need bend(curve) image UI. sorry my poor language.
     
  46. HelicalStudio

    HelicalStudio

    Joined:
    Oct 9, 2016
    Posts:
    6
    Hello all,



    Curve your UI or Canvas

    I have made a solution to curve your canvas. It is highly optimized for both pc and mobile devices.
    Curve your canvas with in seconds. Lowest cost solution on asset store.
    Works with both unity personal and pro versions.

    Check it out on asset store: https://www.assetstore.unity3d.com/en/#!/content/104725

    Check it out on YouTube also:


    For any query drop email to helicalstudio@gmail.com. I'll be glad to help.

    Thanks.
     
    Last edited: Jan 4, 2018
  47. Play_Edu

    Play_Edu

    Joined:
    Jun 10, 2012
    Posts:
    722
    Does anyone have a solution for NGUI and unity 2018
     
    CameronLewis likes this.
  48. Afroworms

    Afroworms

    Joined:
    Feb 24, 2017
    Posts:
    1
    That's very generous