Advertisement
Guest User

UIMeshRenderer.cs

a guest
Jun 27th, 2025
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.20 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5.  
  6. [RequireComponent(typeof(CanvasRenderer))]
  7. [ExecuteAlways]
  8. public class UIMeshRenderer : MonoBehaviour
  9. {
  10.  
  11.     [SerializeField]
  12.     Material Material;
  13.     [SerializeField]
  14.     private Mesh mesh;
  15.     [SerializeField]
  16.     bool mask;
  17.  
  18.     [SerializeField]
  19.     bool showMaskGraphic;
  20.  
  21.     [SerializeField]
  22.     bool maskable;
  23.  
  24.     [SerializeField]
  25.     bool preserveAspect;
  26.  
  27.     CanvasRenderer canvasRenderer;
  28.  
  29.     Image[] childImage;
  30.  
  31.     Vector3[] baseVertices;
  32.  
  33.     RectTransform rect;
  34.     float cachedHeight, cachedWidth;
  35.     void Start()
  36.     {
  37.         SetupMesh();
  38.     }
  39.  
  40.     void SetupMesh()
  41.     {
  42.         // grab the canvasrenderer
  43.         if (canvasRenderer == null)
  44.         {
  45.             canvasRenderer = GetComponent<CanvasRenderer>();
  46.         }
  47.         if (rect == null)
  48.         {
  49.             rect = GetComponent<RectTransform>();
  50.         }
  51.         // set the mesh and material
  52.         canvasRenderer.SetMaterial(Material, null);
  53.         // create new mesh with scale
  54.         canvasRenderer.SetMesh(CreateNewMesh());
  55.         if (mask)
  56.         {
  57.             // set the stencil buffer of this mesh to be a mask
  58.             SetStencilSelf();
  59.             // check if there are images to mask
  60.             childImage = GetComponentsInChildren<Image>();
  61.             if (childImage.Length > 0)
  62.             {
  63.                 SetStencilChildren(childImage);
  64.             }
  65.         }
  66.         else if (maskable)
  67.         {
  68.             // set stencil buff of this mesh to be maskable
  69.             SetMaskableSelf();
  70.         }
  71.     }
  72.  
  73.     void Update()
  74.     {
  75.         // if rect changed, update
  76.         if (cachedWidth != rect.rect.width || cachedHeight != rect.rect.height)
  77.         {
  78.             canvasRenderer.SetMesh(CreateNewMesh());
  79.             cachedWidth = rect.rect.width;
  80.             cachedHeight = rect.rect.height;
  81.         }
  82.     }
  83.  
  84.     void OnEnable()
  85.     {
  86.         SetupMesh();
  87.         canvasRenderer.cull = false;
  88.     }
  89.  
  90.     void OnDisable()
  91.     {
  92.         canvasRenderer.Clear();
  93.         canvasRenderer.cull = true;
  94.     }
  95.  
  96.     private Mesh CreateNewMesh()
  97.     {
  98.         // create copy of the mesh
  99.         Mesh newMesh = Instantiate(mesh);
  100.         baseVertices = newMesh.vertices;
  101.         var vertices = new Vector3[baseVertices.Length];
  102.         // base size on mesh bounds
  103.         Vector2 size = new Vector2(newMesh.bounds.extents.x, newMesh.bounds.extents.y);
  104.         Rect r = rect.rect;
  105.  
  106.         // handle preserving aspect
  107.         if (preserveAspect && size.sqrMagnitude > 0.0f)
  108.         {
  109.             var meshRatio = size.x / size.y;
  110.             var rectRatio = r.width / r.height;
  111.  
  112.             if (meshRatio > rectRatio)
  113.             {
  114.                 var oldHeight = r.height;
  115.                 r.height = r.width * (1.0f / meshRatio);
  116.                 r.y += (oldHeight - r.height) * rect.pivot.y;
  117.             }
  118.             else
  119.             {
  120.                 var oldWidth = r.width;
  121.                 r.width = r.height * meshRatio;
  122.                 r.x += (oldWidth - r.width) * rect.pivot.x;
  123.             }
  124.         }
  125.  
  126.         // scale to rect transform size
  127.         float scaleY = (r.height / newMesh.bounds.size.y);
  128.         float scaleX = (r.width / newMesh.bounds.size.x);
  129.  
  130.         // mesh center in case of offcenter pivot
  131.         Vector3 meshCenter = newMesh.bounds.center;
  132.  
  133.  
  134.         // use scale on all vertices
  135.         for (var i = 0; i < vertices.Length; i++)
  136.         {
  137.             var vertex = baseVertices[i];
  138.  
  139.             // subtract any off-center pivot
  140.             vertex -= meshCenter;
  141.  
  142.             vertex.x *= scaleX;
  143.  
  144.             vertex.y *= scaleY;
  145.  
  146.             vertex.z *= scaleX;
  147.  
  148.             vertices[i] = vertex;
  149.  
  150.  
  151.         }
  152.  
  153.         // set new vertices
  154.         newMesh.vertices = vertices;
  155.  
  156.         newMesh.RecalculateNormals();
  157.         newMesh.RecalculateBounds();
  158.  
  159.         return newMesh;
  160.     }
  161.  
  162.     void SetStencilSelf()
  163.     {
  164.         Material instancedMat = Instantiate(Material);
  165.         canvasRenderer.SetMaterial(instancedMat, null);
  166.  
  167.         // stencil buffer for mask
  168.         canvasRenderer.GetMaterial().SetInt("_Stencil", 1);
  169.         canvasRenderer.GetMaterial().SetInt("_StencilComp", 8);
  170.         canvasRenderer.GetMaterial().SetInt("_StencilOp", 2);
  171.         if (showMaskGraphic)
  172.         {
  173.             // set colormask all
  174.             canvasRenderer.GetMaterial().SetInt("_ColorMask", 15);
  175.         }
  176.         else
  177.         {
  178.             // no colormask
  179.             canvasRenderer.GetMaterial().SetInt("_ColorMask", 0);
  180.         }
  181.     }
  182.  
  183.     void SetMaskableSelf()
  184.     {
  185.         // instantiate and adjust the material for this mesh
  186.         Material instancedMat = Instantiate(Material);
  187.         canvasRenderer.SetMaterial(instancedMat, null);
  188.         // stencil buffer for maskable
  189.         canvasRenderer.GetMaterial().SetInt("_Stencil", 1);
  190.         canvasRenderer.GetMaterial().SetInt("_StencilComp", 3);
  191.         canvasRenderer.GetMaterial().SetInt("_StencilOp", 0);
  192.         canvasRenderer.GetMaterial().SetInt("_StencilReadMask", 1);
  193.         canvasRenderer.GetMaterial().SetInt("_StencilWriteMask", 0);
  194.     }
  195.  
  196.     void SetStencilChildren(Image[] images)
  197.     {
  198.         for (int i = 0; i < images.Length; i++)
  199.         {
  200.             // if child has maskable enabled
  201.             if (images[i].maskable)
  202.             {
  203.                 // instantiate the standard UI material (If you have custom image shaders, you will want to grab them seperately and cache them)
  204.                 Material instancedMat = new Material(Shader.Find("UI/Default"));
  205.                 images[i].material = instancedMat;
  206.                 // stencil buffer for maskable
  207.                 images[i].material.SetInt("_Stencil", 1);
  208.                 images[i].material.SetInt("_StencilComp", 3);
  209.                 images[i].material.SetInt("_StencilOp", 0);
  210.                 images[i].material.SetInt("_StencilReadMask", 1);
  211.                 images[i].material.SetInt("_StencilWriteMask", 0);
  212.             }
  213.  
  214.         }
  215.     }
  216.     void OnValidate()
  217.     {
  218.         if (!Application.isPlaying)
  219.         {
  220.             SetupMesh();
  221.         }
  222.  
  223.     }
  224.  
  225. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement