fryBender
fryBender

Reputation: 37

Gradient not rendering correctly on a Unity3D GUI object

I am attempting to apply a gradient effect on a Unity3D(5.2) gui object but its as if one of the gradient color keys is being completely ignored. I have tried with both instantiating a new gradient field and declaring a gradient field public and edit its keys in the editor but yet the effects remain the same. I'm beginning to think that I am not supposed to use Gradients in a BaseMeshEffect in the way I am using it. If only have 2 keys, the colors render properly. Where am I wrong?

Here is a code sample followed by a screen shot.

 public class GradientUI : BaseMeshEffect
    {

        [SerializeField]
        public Gradient Grad; 

        public override void ModifyMesh(VertexHelper vh)
        {
            if (!IsActive())
            {
                return;
            } 

            List<UIVertex> vertexList = new List<UIVertex>();
            vh.GetUIVertexStream(vertexList);

            ModifyVertices(vertexList);

            vh.Clear();
            vh.AddUIVertexTriangleStream(vertexList);
        }

        void ModifyVertices(List<UIVertex> vertexList)
        {
            int count = vertexList.Count;
            float bottomY = vertexList[0].position.y;

            float topY = vertexList[0].position.y;

            for (int i = 1; i < count; i++)
            {
                float y = vertexList[i].position.y;
                if (y > topY)
                {
                    topY = y;
                }
                else if (y < bottomY)
                {
                    bottomY = y;
                }
            }

            float uiElementHeight = topY - bottomY;

            for (int i = 0; i < count; i++)
            {
                UIVertex uiVertex = vertexList[i];
                float percentage = (uiVertex.position.y - bottomY) / uiElementHeight;
                //   Debug.Log(percentage);
                Color col = Grad.Evaluate(percentage);
                uiVertex.color = col;

                vertexList[i] = uiVertex;
                 Debug.Log(uiVertex.position);
            }
        }

Screen shot

Upvotes: 1

Views: 986

Answers (1)

Yuri Nudelman
Yuri Nudelman

Reputation: 2943

Your script is actually OK, no problem with it. The problem here is that UI elements simply don't have enough geometry for you to actually see the whole gradient.

Let me explain. In a nutshell, each UI element is actually a mesh made of several 3D triangles, each one rotated to face the camera exactly with its front so it looks 2D. You filter works by assigning a color value to each vertex of those triangles. The color values in the middle of triangles are interpolated based on the proximity to each of the colored vertices.

If you look at UI element in wireframe, you will see that its geometry is very simple. This is for example how a sliced image looks:

UI Panel wireframe

As you can see, all of its vertices are concentrated at the corners, and there are no vertices in the middle. So, lets assume your gradient is 2 keys WHITE=>RED. The upper vertices get value WHITE or close to WHITE, the bottom values get value RED or close to RED. This works OK for 2 keys.

Now assume you have 3 keys WHITE=>BLUE=>RED. The upper value is WHITE or close to WHITE, the bottom values get value RED or close to RED, the BLUE value is supposed to be somewhere in the middle, but there is no vertex in the middle, so it is not assigned to anything. So you still get WHITE to RED gradient.

Now, what you can do:

1) You can add some more geometry programmatically, for example by simply subdividing the whole mesh. This may help you: http://answers.unity3d.com/questions/259127/does-anyone-have-any-code-to-subdivide-a-mesh-and.html. Pay attention that in this case, the more keys your gradient has, the more subdivisions are required.

2) Use texture that looks like a gradient gradient.

Upvotes: 1

Related Questions