Last active
April 7, 2020 19:38
-
-
Save Softdrink117/04ecf6891197da36ce8b78b635a802d7 to your computer and use it in GitHub Desktop.
An extension of UnityEngine.UI.MaskableGraphic that allows for the drawing of arbitrary meshes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
namespace Softdrink | |
{ | |
// Adapted from https://www.hallgrimgames.com/blog/2018/11/25/custom-unity-ui-meshes | |
// with significant modifications to account for arbitrary meshes and UVs | |
public class MeshGraphic : MaskableGraphic | |
{ | |
[TooltipAttribute("For best results, use a 2D mesh built on the XY plane, with UVs, scaled to fit a unit square.")] | |
public Mesh mesh = null; | |
[TooltipAttribute("A scalar multiplier applied to mesh Z thickness.")] | |
public float zThickness = 0f; | |
// Scaling factor that will be automatically calculated based on mesh vertices | |
// Will attempt to automatically long-edge fit the XY projection of the Mesh to the RectTransform area | |
private float scaleFactor = 1f; | |
[SerializeField] | |
[TooltipAttribute("A Texture to map to the Mesh. If the Mesh has no UVs, new UVs will be generated in the RectTransform space.")] | |
Texture _texture; | |
[TooltipAttribute("If enabled, the Mesh will be recalculated whenever the RectTransform dimensions change. This provides the most intuitive results, but can be performance intensive. \nIf disabled, you must call UpdateMesh() manually to resize the mesh when changing the RectTransform dimensions.")] | |
public bool autoUpdateMesh = true; | |
private Vector3 vertMax; | |
private Vector3 vertMin; | |
// Redraw element when texture changed in Inspector | |
public Texture texture | |
{ | |
get | |
{ | |
return _texture; | |
} | |
set | |
{ | |
if (_texture == value) | |
return; | |
_texture = value; | |
SetVerticesDirty(); | |
SetMaterialDirty(); | |
} | |
} | |
// Use default white texture if nothing is specified | |
public override Texture mainTexture | |
{ | |
get | |
{ | |
return _texture == null ? s_WhiteTexture : _texture; | |
} | |
} | |
#if UNITY_EDITOR | |
protected override void OnValidate() | |
{ | |
base.OnValidate(); | |
CalcMeshScaleFactor(); | |
SetVerticesDirty(); | |
SetMaterialDirty(); | |
} | |
#endif | |
// Calculate a scaling factor for the input mesh based | |
// on bounding box size of all vertices | |
void CalcMeshScaleFactor() | |
{ | |
vertMax = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue); | |
vertMin = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue); | |
for(int i = 0; i < mesh.vertices.Length; i++) | |
{ | |
vertMax = Vector3.Max(vertMax, mesh.vertices[i]); | |
vertMin = Vector3.Min(vertMin, mesh.vertices[i]); | |
} | |
float xRange = Mathf.Abs(vertMax.x - vertMin.x); | |
float yRange = Mathf.Abs(vertMax.y - vertMin.y); | |
float maxRange = Mathf.Max(xRange, yRange); | |
if(maxRange != 0f) scaleFactor = 1.0f/maxRange; | |
else scaleFactor = 1.0f; | |
} | |
// Calculate a UV in RectTransform space by mapping the current vertex position relative | |
// to the min and max vertex positions of the entire mesh | |
Vector2 CalculateRectspaceUV(Vector3 vPos) | |
{ | |
return new Vector2(Map(vPos.x, vertMin.x, vertMax.x, 0f, 1f), Map(vPos.y, vertMin.y, vertMax.y, 0f, 1f)); | |
} | |
float Map(float x, float aMin, float aMax, float bMin, float bMax) | |
{ | |
return (x - aMin) * (bMax - bMin) / (aMax - aMin) + bMin; | |
} | |
protected override void OnPopulateMesh(VertexHelper vh) | |
{ | |
vh.Clear(); | |
if(mesh == null) return; | |
bool hasUV = (mesh.uv != null && mesh.uv.Length > 0); | |
Vector3 scale = new Vector3(rectTransform.rect.width, rectTransform.rect.height, zThickness); | |
scale *= scaleFactor; | |
for(int i = 0; i < mesh.vertices.Length; i++) | |
{ | |
if(hasUV) vh.AddVert(Vector3.Scale(mesh.vertices[i], scale), color, mesh.uv[i]); | |
else vh.AddVert(Vector3.Scale(mesh.vertices[i], scale), color, CalculateRectspaceUV(mesh.vertices[i])); | |
} | |
for(int j = 0; j < mesh.triangles.Length; j+= 3) | |
{ | |
vh.AddTriangle(mesh.triangles[j], mesh.triangles[j+1], mesh.triangles[j+2]); | |
} | |
} | |
protected override void OnRectTransformDimensionsChange() | |
{ | |
base.OnRectTransformDimensionsChange(); | |
if(!autoUpdateMesh) return; | |
SetVerticesDirty(); | |
SetMaterialDirty(); | |
} | |
public void UpdateMesh() | |
{ | |
SetVerticesDirty(); | |
SetMaterialDirty(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
MIT License per https://gist.github.com/Softdrink117/cbe9bd2efa614001fc18eb71e15b870a