Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  4. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Unity UI big problem with lacking materialpropertyblock for ui image

Discussion in 'Unity UI & TextMesh Pro' started by mahdiii, Nov 30, 2017.

  1. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    632
    Hi all
    I need to use materialpropertyblock for ui images. How can I handle that
    I have a lot of ui square images that have different properties (one property color for example or other field)
    Thx
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    2,971
    You can't use material property blocks with UI. What is it you want to change? Color is better changed through the UI components than a MPB. The color is placed into the mesh as vertex colors. If it's just lots of squares then changing the sprite color is perfectly fine. You could also write a custom component that puts the color into the vertexes yourself if it needs to be more complex.
     
  3. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    632
    thx but I have written a custom shader. the property is not color. I know an image ui has a color property
    it is four float (vector4: x and y bottom left coordinate point and height width) , I need to mask a texture on these squares and overlay them
    I almost have 200 squares and can not have 200 pass call for that
     
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    2,971
    What about putting the data into a different channel such as uv1 or uv2? The canvas allows for adding some extra channels. I have done something similar in the past using uv1 and a custom sprite to write in the channel.
     
    mahdiii likes this.
  5. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    632
    perfect I understood it
    Can you refer to me a link about that?
    So I set a channel uv2 float4
    float4 uv2:TEXCOORD2. my data are between 0 and 1 but I think a texture RGBA can not have enough precision
    putting the data into a channel instead of sending to a shader with setvector
     
    Last edited: Nov 30, 2017
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    2,971
    You can create a new BaseMeshEffect class and then put the data into the verts like this example:
    Then make sure you have enabled the channel in the canvas under the Additional Shader Channels
     
    mahdiii likes this.
  7. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    632
    some questions:
    1- ModifyMesh override function is executed only once?
    2- can we add different channels for different uis or not (in other words can we add texcoords to special uis not a canvas)
     
  8. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    2,971
    Its called whenever the canvas needs to generate a mesh. https://docs.unity3d.com/ScriptReference/UI.IMeshModifier.html

    What do you mean uis? You can modify selected elements, you dont have to attach your MeshModifier to every element.
     
    mahdiii likes this.
  9. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    632
    no, you said I must change Additional Shader Channels from the canvas so I can change it only for the canvas and if I want to have different channels for different images for example,I need to add all channels to consider all of them
     
  10. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    2,971
    Yes you need to make sure that the responsible canvas has the additional channels enabled. Then you can modify its child images.
     
    mahdiii likes this.
  11. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    632
    :) again thank you
    Code (CSharp):
    1. using System.Linq;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6.  
    7. [AddComponentMenu("UI/Effects/Position As UV1", 16)]
    8. public class PositionAsUV1 : BaseMeshEffect {
    9.  
    10.  
    11.     [SerializeField]
    12.     RectTransform m_maskImageRectTr;
    13.     [SerializeField]
    14.     RectTransform m_imageRectTr;
    15.     Vector4 vec;
    16.     [SerializeField]
    17.     int m_rowIdx;
    18.     [SerializeField]
    19.     int m_colIdx;
    20.     [SerializeField]
    21.     Vector2 m_margin;
    22.  
    23.     // Use this for initialization
    24.     protected override void Start() {
    25.         base.Start();
    26.         Vector2 vv = m_imageRectTr.sizeDelta.Divide(m_maskImageRectTr.sizeDelta);
    27.         vec.x = ((m_colIdx - 1) * (m_margin.x + m_imageRectTr.sizeDelta.x) + m_imageRectTr.sizeDelta.x) / m_maskImageRectTr.sizeDelta.x;
    28.         vec.y = ((m_rowIdx - 1) * (m_margin.y + m_imageRectTr.sizeDelta.y) + m_imageRectTr.sizeDelta.y) / m_maskImageRectTr.sizeDelta.y;
    29.         vec.z = vv.x;
    30.         vec.w = vv.y;
    31.     }
    32.     public void SetRowCol(int _row,int _col) {
    33.         m_rowIdx = _row;
    34.         m_colIdx = _col;
    35.     }
    36.     protected PositionAsUV1() { }
    37.  
    38.     public override void ModifyMesh(VertexHelper vh) {
    39.  
    40.         UIVertex vert = new UIVertex();
    41.         for (int i = 0; i < vh.currentVertCount; i++) {
    42.             vh.PopulateUIVertex(ref vert, i);
    43.             vert.uv1 = new Vector2(vec.x, vec.y);
    44.             vert.uv2 = new Vector2(vec.z, vec.w);          
    45.             vh.SetUIVertex(vert, i);
    46.         }
    47.     }
    48. }
    49.  


    Code (CSharp):
    1.     struct appdata
    2.             {
    3.                 float4 vertex : POSITION;
    4.                 float2 uv : TEXCOORD0;
    5.                 float2 uv1 : TEXCOORD1;
    6.                 float2 uv2 : TEXCOORD2;
    7.             };
    8.  
    9.             struct v2f
    10.             {
    11.                 float2 uv : TEXCOORD0;
    12.                 float2 uv1 : TEXCOORD1;
    13.                 float2 uv2 : TEXCOORD2;
    14.                
    15.                 float4 vertex : SV_POSITION;
    16.             };
    17.  
    18.             sampler2D _MainTex;
    19.             float4 _MainTex_ST;
    20.             sampler2D    _OverlayTex;
    21.             float4 _Rect;
    22.             fixed4 _Color;
    23.             float _Factor;
    24.             float _Factor2;
    25.             v2f vert (appdata v)
    26.             {
    27.                 v2f o;
    28.                 o.vertex = UnityObjectToClipPos(v.vertex);
    29.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    30.                 o.uv1=v.uv1;
    31.                 o.uv2=v.uv2;
    32.                 return o;
    33.             }
    34.            
    35.             fixed4 frag (v2f i) : SV_Target
    36.             {
    37.                 // sample the texture
    38.                 fixed4 col = tex2D(_MainTex, i.uv);
    39.                 float2 overlayUV=float2(i.uv1.x,i.uv1.y)+i.uv*float2(i.uv2.x,i.uv2.y);
    40.                 fixed4 col2 = tex2D(_OverlayTex,overlayUV);
    41.                 fixed4 finalCol=fixed4( col.r<=0.5 ? 2*col.r*col2.r: 1-2*(1-col.r)*(1-col2.r),
    42.                                         col.g<=0.5 ? 2*col.g*col2.g: 1-2*(1-col.g)*(1-col2.g),
    43.                                         col.b<=0.5 ? 2*col.b*col2.b: 1-2*(1-col.b)*(1-col2.b),1);
    44.                 finalCol=lerp(finalCol,col2*col,_Factor);
    45.                 finalCol=lerp(col,finalCol,_Factor2)*_Color;
    46.                 finalCol.a=col2.a;
    47.  
    48.                 return finalCol;
    49.             }
     

    Attached Files:

    karl_jones likes this.
  12. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    2,971
    Looks great. Happy to help :D
     
  13. pbhogan

    pbhogan

    Joined:
    Aug 17, 2012
    Posts:
    174
    What is the justification for this obtuse restriction? Why doesn't CanvasRenderer have material property blocks?

    It arbitrarily limits UI elements and its super unintuitive. I'm trying to write a custom UI component with a fairly complex shader that needs quite a few bits of data passed in and that's in addition to vertex colors and UVs.

    I originally wanted to pass in several properties but I've been banging my head on this for hours only to come to find out there is no way to even pass in a single color property on a per instance basis. Encoding a uniform property value into additional UV channels is just silly and inefficient. And what if we wanted to pass in a second texture?

    I need many instances of this component with differing data values so I don't want draw calls to scale with instances.
     
    Aaron-Meyers and Lars-Steenhoff like this.
  14. Aaron-Meyers

    Aaron-Meyers

    Joined:
    Dec 8, 2009
    Posts:
    63
    +1 for using MaterialPropertyBlocks with CanvasRenderer. MaterialPropertyBlock is an essential unity workflow. Why should it be any different for UI components with custom shaders/materials?