How to use " 9-sliced" image type in non-GUI elements?
Asked Answered
L

3

7

In my game, I am using simple textures on quads. I could see Unity GUI allows us to slice the image by setting "image type" option as sliced.

I would like to do the same to my other textures I use in quads.

In simple words, I dont want the edges of my textures to be scaled when the texture itself is scaled.

Thanks.

Lauranlaurance answered 14/2, 2015 at 13:38 Comment(0)
P
8

Looks like you have to generate the mesh yourself, not so hard as it sounds. The mesh has to look like this:

9 slice on a quad

Each textured mesh is defined by vertices (red dots on the picture) and (in this case) each vertex has two parameters:

  1. A Vector3 with position. Only x and y used here, as a quad is flat (so, z = 0).
  2. A Vector2 with the UV, that is how the material is put on the mesh. This are the texture coordinates: u and v.

To configure this mesh, I added parameters:

b - for border - how big is the border of the gameobject (in 3d units)
w, h - for width and height of the gameobject (in 3d units)
m - how big is the margin in the image (in float 0f to 0.5f)

How to do this in Unity3d:

  1. Create an GameObject, add a MeshRenderer with the material you want and an empty MeshFilter.
  2. Add a script that creates a mesh. Look at Unity3d docs for Mesh, first example.

Note that for unity3d you have to create this with triangles, not quads (so for each quad make two triangles).

Polymorphism answered 16/2, 2015 at 9:29 Comment(1)
Thank you Chanibal! It worked for me. There were some small errors: - At the bottom, you wrote v instead of u in every column but the first one. It should be: u=0, u=m, u=1-m, u =1. - You never actually used the h variable. The y value for the 2nd and 3rd row should be: y=h-b and y=h.Wensleydale
W
5

Chanibal's solutions worked like a charm for me, but since I wasn't an expert in the matter, it wasn't trivial to me to implement this. I will let this code here in case somebody could find it useful.

using UnityEngine;

public class SlicedMesh : MonoBehaviour
{
    private float _b = 0.1f;
    public float Border
    {
        get
        {
            return _b;
        }
        set
        {
            _b = value;
            CreateSlicedMesh();
        }
    }

    private float _w = 1.0f;
    public float Width
    {
        get
        {
            return _w;
        }
        set
        {
            _w = value;
            CreateSlicedMesh();
        }
    }

    private float _h = 1.0f;
    public float Height
    {
        get
        {
            return _h;
        }
        set
        {
            _h = value;
            CreateSlicedMesh();
        }
    }

    private float _m = 0.4f;
    public float Margin
    {
        get
        {
            return _m;
        }
        set
        {
            _m = value;
            CreateSlicedMesh();
        }
    }

    void Start() 
    {

        CreateSlicedMesh();
    }

    void CreateSlicedMesh()
    {
        Mesh mesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;

        mesh.vertices = new Vector3[] {
            new Vector3(0, 0, 0), new Vector3(_b, 0, 0), new Vector3(_w-_b, 0, 0), new Vector3(_w, 0, 0),
            new Vector3(0, _b, 0), new Vector3(_b, _b, 0), new Vector3(_w-_b, _b, 0), new Vector3(_w, _b, 0),
            new Vector3(0, _h-_b, 0), new Vector3(_b, _h-_b, 0), new Vector3(_w-_b, _h-_b, 0), new Vector3(_w, _h-_b, 0),
            new Vector3(0, _h, 0), new Vector3(_b, _h, 0), new Vector3(_w-_b, _h, 0), new Vector3(_w, _h, 0)
        };

        mesh.uv = new Vector2[] {
            new Vector2(0, 0), new Vector2(_m, 0), new Vector2(1-_m, 0), new Vector2(1, 0),
            new Vector2(0, _m), new Vector2(_m, _m), new Vector2(1-_m, _m), new Vector2(1, _m),
            new Vector2(0, 1-_m), new Vector2(_m, 1-_m), new Vector2(1-_m, 1-_m), new Vector2(1, 1-_m),
            new Vector2(0, 1), new Vector2(_m, 1), new Vector2(1-_m, 1), new Vector2(1, 1)
        };

        mesh.triangles = new int[] {
            0, 4, 5,
            0, 5, 1,
            1, 5, 6,
            1, 6, 2,
            2, 6, 7,
            2, 7, 3,
            4, 8, 9,
            4, 9, 5, 
            5, 9, 10,
            5, 10, 6,
            6, 10, 11,
            6, 11, 7,
            8, 12, 13,
            8, 13, 9,
            9, 13, 14,
            9, 14, 10,
            10, 14, 15,
            10, 15, 11
        };
    }
}
Wensleydale answered 12/3, 2015 at 9:3 Comment(1)
Nice, but remember to mesh.RecalculateBounds() after setting the triangles! I would also add [RequireComponent(typeof(MeshRenderer))] [RequireComponent(typeof(MeshFilter))] before the class declaration.Daukas
V
-1

Here is another impementation of the same mesh as described above(just add Tile9Mesh script to empty GameObject and it should work Screen of usage in Unity):

using UnityEngine;

namespace Util {
    [ExecuteInEditMode]
    [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
    public class Tile9Mesh : MonoBehaviour {

        public float width = 1;
        public float height = 1;

        [Range(0, 0.5f)]
        public float uvLeft = 0.2f;
        [Range(0, 0.5f)]
        public float uvRight = 0.2f;
        [Range(0, 0.5f)]
        public float uvTop = 0.2f;
        [Range(0, 0.5f)]
        public float uvBottom = 0.2f;
        public float uvToWorldScaleX = 1;
        public float uvToWorldScaleY = 1;

        private Mesh mesh;

        private Vector3[] vertices;
        private Vector2[] uv;

        private void Start() {
            vertices = new Vector3[16];
            uv = new Vector2[16];

            mesh = new Mesh {
                name = "Tile9Mesh"
            };
            FillGeometry();
            FillMesh();
            mesh.triangles = new[] {
                0, 1, 12, 0, 12, 11,
                1, 2, 13, 1, 13, 12,
                2, 3, 4, 2, 4, 13,
                13, 4, 5, 13, 5, 14,
                14, 5, 6, 14, 6, 7,
                15, 14, 7, 15, 7, 8,
                10, 15, 8, 10, 8, 9,
                11, 12, 15, 11, 15, 10,
                12, 13, 14, 12, 14, 15
            };
            RecalculateMesh();

            gameObject.GetComponent<MeshFilter>().mesh = mesh;
        }

        public void UpdateMesh() {
            if (mesh != null) {
                FillGeometry();
                FillMesh();
                mesh.RecalculateBounds();
                mesh.RecalculateNormals();
            }
        }

        private void FillGeometry() {
            {
                float w = width;
                float h = height;
                float l = uvLeft * uvToWorldScaleX;
                float r = width - uvRight * uvToWorldScaleX;
                float t = height - uvTop * uvToWorldScaleY;
                float b = uvBottom * uvToWorldScaleY;
                vertices[0] = new Vector3(0, 0, 0);
                vertices[1] = new Vector3(0, b, 0);
                vertices[2] = new Vector3(0, t, 0);
                vertices[3] = new Vector3(0, h, 0);
                vertices[4] = new Vector3(l, h, 0);
                vertices[5] = new Vector3(r, h, 0);
                vertices[6] = new Vector3(w, h, 0);
                vertices[7] = new Vector3(w, t, 0);
                vertices[8] = new Vector3(w, b, 0);
                vertices[9] = new Vector3(w, 0, 0);
                vertices[10] = new Vector3(r, 0, 0);
                vertices[11] = new Vector3(l, 0, 0);
                vertices[12] = new Vector3(l, b, 0);
                vertices[13] = new Vector3(l, t, 0);
                vertices[14] = new Vector3(r, t, 0);
                vertices[15] = new Vector3(r, b, 0);
            }
            {
                const float w = 1;
                const float h = 1;
                float l = uvLeft;
                float r = 1 - uvRight;
                float t = 1 - uvTop;
                float b = uvBottom;
                uv[0] = new Vector2(0, 0);
                uv[1] = new Vector2(0, b);
                uv[2] = new Vector2(0, t);
                uv[3] = new Vector2(0, h);
                uv[4] = new Vector2(l, h);
                uv[5] = new Vector2(r, h);
                uv[6] = new Vector2(w, h);
                uv[7] = new Vector2(w, t);
                uv[8] = new Vector2(w, b);
                uv[9] = new Vector2(w, 0);
                uv[10] = new Vector2(r, 0);
                uv[11] = new Vector2(l, 0);
                uv[12] = new Vector2(l, b);
                uv[13] = new Vector2(l, t);
                uv[14] = new Vector2(r, t);
                uv[15] = new Vector2(r, b);
            }
        }

        private void FillMesh() {
            mesh.vertices = vertices;
            mesh.uv = uv;
        }

        private void RecalculateMesh() {
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
        }

#if UNITY_EDITOR
        private void OnValidate() {
            if (mesh != null) {
                UpdateMesh();
            }
        }
#endif


    }
}
Vitamin answered 13/1, 2018 at 21:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.