Search Unity

UI Billboard Shader - Wrong rotation pivot

Discussion in 'Shaders' started by Celtc, Sep 15, 2017.

  1. Celtc

    Celtc

    Joined:
    Jan 19, 2014
    Posts:
    5
    I'm trying to display several Images as billboards. All the Images are under the same Canvas. I'm using a billboard shader I've been working on (vertex part, the whole shader is attached):

    Code (CSharp):
    1.  
    2.             v2f vert(appdata_t IN)
    3.             {
    4.                 v2f OUT;
    5.                 UNITY_SETUP_INSTANCE_ID(IN);
    6.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    7.  
    8.                 // Method 1
    9.                 /*
    10.                 float scaleX = length(mul(unity_ObjectToWorld, float4(1.0, 0.0, 0.0, 0.0)));
    11.                 float scaleY = length(mul(unity_ObjectToWorld, float4(0.0, 1.0, 0.0, 0.0)));
    12.                 OUT.vertex = mul(
    13.                     UNITY_MATRIX_P,
    14.                     float4(UnityObjectToViewPos(float3(0, 0, 0)), 1) + float4(IN.vertex.x * scaleX, IN.vertex.y * scaleY, 0, 0)
    15.                     //mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0)) + float4(IN.vertex.x * scaleX, IN.vertex.y * scaleY, 0.0f, 0.0f)
    16.                 );
    17.                 */
    18.  
    19.                 // Method 2
    20.                 float4x4 mv = UNITY_MATRIX_MV;
    21.  
    22.                 mv[0][0] = 1.0;
    23.                 mv[0][1] = 0.0;
    24.                 mv[0][2] = 0.0;
    25.  
    26.                 mv[1][0] = 0.0;
    27.                 mv[1][1] = 1.0;
    28.                 mv[1][2] = 0.0;
    29.  
    30.                 mv[2][0] = 0.0;
    31.                 mv[2][1] = 0.0;
    32.                 mv[2][2] = 1.0;
    33.  
    34.                 OUT.vertex = mul(
    35.                     UNITY_MATRIX_P,
    36.                     mul(mv, IN.vertex)
    37.                 );
    38.  
    39.                 OUT.worldPosition = OUT.vertex;
    40.                 OUT.texcoord = IN.texcoord;
    41.                 OUT.color = IN.color * _Color;
    42.  
    43.                 return OUT;
    44.             }
    The problem is that when the Image is not at the center of the canvas (0,0,0), the billboard rotation is not around it's pivot, but the canvas pivot. Here is a small gif:



    As you can see the Image on the left (2,0,0) is rotating around the same pivot of the left one (0,0,0), the Canvas pivot (0,0,0).

    Here are some caps of the Images transforms and the Canvas transform:




    I've tried several things but with no success. I'm still learning to programming shaders. Any suggestion is really welcome.
     

    Attached Files:

  2. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,442
    test if disabling [x] Dynamic Patching from player settings helps,
    or in shader tags, add DisableBatching:

    "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
     
  3. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    It's definitely the batching. You should consider writing the pivot you want into UV2 if you're going to have a lot of these.
     
  4. Celtc

    Celtc

    Joined:
    Jan 19, 2014
    Posts:
    5
    I've tried both but didn't work, not with UI elements. I've used the "DisableBatching" tag on a similar shader for quads displayed by a mesh renderer and did worked, but when using a Canvas and UI elements it did not.

    So the only way to achive multiple billboard images on a same canvas is by storing thier pivot point into another shader var? I was trying to avoid these, believing that there was a way I didn't knew since like I mentioned before I'm a total newbie in shader programming.
     
  5. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    The UI system is its own ball of crazy... Every time something gets transformed inside a canvas a whole new mesh gets built by Unity.

    There is a component called PositionAsUV1. This will bake extra data onto the vertices of the mesh the Canvas is building. It's not super reliable depending on your pivot and slice settings, but it is a good example of how you can write your own component to do something similar.

    You can't do a MaterialPropertyBlock to effectively instance the Mat either, the UI rendering doesn't follow the same path as everything else (eyeroll).

    Be really deliberate with this, cause you're putting some C# in the middle of what is otherwise mostly fast C++ code, so there is definitely a trade-off to going down this road. I used this very heavily in our new The Walking Dead March To War which has LOTS of menus and it didn't result in any crippling performance hit. You'll probably want to inline all your math and do all the efficiency things you can think of.