Skip to content

Instantly share code, notes, and snippets.

@mandarinx
Last active July 22, 2022 02:43
Show Gist options
  • Save mandarinx/06192ee17d68c528edb9 to your computer and use it in GitHub Desktop.
Save mandarinx/06192ee17d68c528edb9 to your computer and use it in GitHub Desktop.
9 slice scaling with a mesh in Unity3D

Changes

  • Some fields have been hidden (marked as private) to simplify the interface and make it slightly easier to use.
  • Slicing is done by adjusting the slicePixels field. The number of pixels is counted inwards from the edges.
  • Simplified checking for changes in LateUpdate by reversing the if statement. Got rid of the change boolean.
  • Some of the maths in CreateMesh() was simplified to solve an issue with setting the width and height. Width and height seemed to be some arbitrary values. Now they represent world space units.
  • Added public methods for repositioning and scaling the object.

TODO

  • Validate slicePixels to make sure you're not trying to slice more pixels than the image has.
using UnityEngine;
// Nine slice scaling using a Mesh.
// Original code by Asher Vollmer
// https://twitter.com/AsherVo
// http://ashervollmer.tumblr.com
// Modifications by Thomas Viktil
// https://twitter.com/mandarinx
// http://ma.ndar.in/
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
[ExecuteInEditMode]
public class NineSlice : MonoBehaviour {
public Sprite useSprite;
public float width;
public float height;
public int slicePixels = 5;
private float oldWidth;
private float oldHeight;
private Sprite oldSprite;
private MeshFilter meshF;
private Renderer rend;
private Mesh mesh;
private Vector3 position;
public void LateUpdate() {
if (useSprite == oldSprite &&
width == oldWidth &&
height == oldHeight) {
return;
}
CreateMesh();
oldSprite = useSprite;
oldWidth = width;
oldHeight = height;
}
public void CreateMesh() {
if (meshF == null) {
meshF = GetComponent<MeshFilter>() as MeshFilter;
}
if (rend == null) {
rend = GetComponent<Renderer>() as Renderer;
}
if (meshF.sharedMesh) {
DestroyImmediate(meshF.sharedMesh);
}
if (mesh) {
DestroyImmediate(mesh);
}
if (useSprite == null) {
return;
}
MaterialPropertyBlock pBlock = new MaterialPropertyBlock();
pBlock.SetTexture("_MainTex", useSprite.texture);
rend.SetPropertyBlock(pBlock);
float ppu = useSprite.pixelsPerUnit;
float cornerWidth = (float)(slicePixels) / ppu;
float cornerHeight = (float)(slicePixels) / ppu;
mesh = new Mesh();
Vector3[] vertices = new Vector3[16];
Vector3[] normals = new Vector3[16];
Vector2[] uvs = new Vector2[16];
float[] xPValues = new float[4];
float[] yPValues = new float[4];
float cornerWidthP = cornerWidth / width;
float cornerHeightP = cornerHeight / height;
xPValues[0] = 0.0f;
yPValues[0] = 0.0f;
xPValues[1] = cornerWidthP;
yPValues[1] = cornerHeightP;
xPValues[2] = 1.0f - cornerWidthP;
yPValues[2] = 1.0f - cornerHeightP;
xPValues[3] = 1.0f;
yPValues[3] = 1.0f;
for (int x = 0; x < 4; x++) {
for (int y = 0; y < 4; y++) {
float xP = xPValues[x];
float yP = yPValues[y];
int index = OneDee(x, y);
vertices[index] = new Vector3(
Mathf.Lerp(-1.0f, 1.0f, xP) * width * 0.5f,
Mathf.Lerp(-1.0f, 1.0f, yP) * height * 0.5f,
0.0f);
uvs[index] = new Vector2((float)x / 3.0f, (float)y / 3.0f);
normals[index] = -Vector3.forward;
}
}
int[] tris = new int[9 * 2 * 3];
int i = 0;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
tris[i] = OneDee(x + 1, y);
i++;
tris[i] = OneDee(x, y);
i++;
tris[i] = OneDee(x + 1, y + 1);
i++;
tris[i] = OneDee(x, y);
i++;
tris[i] = OneDee(x, y + 1);
i++;
tris[i] = OneDee(x + 1, y + 1);
i++;
}
}
mesh.MarkDynamic();
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.triangles = tris;
mesh.normals = normals;
mesh.RecalculateBounds();
meshF.sharedMesh = mesh;
}
public static int OneDee (Vector2 coords) {
return OneDee((int)coords.x, (int)coords.y);
}
public static int OneDee (int x, int y) {
return (y * 4) + x;
}
public static Vector2 TwoDee (int index) {
int x = index % 4;
int y = index / 4;
return new Vector2(x, y);
}
public void SetPosition(float x, float y, float z) {
position.x = x;
position.y = y;
position.z = z;
transform.position = position;
}
public void SetSize(float w, float h) {
width = w;
height = h;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment