みかづきメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ 書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

Canvas Image を Mesh に変換したい

なんでそんな必要があるのかって? Canvas 使いまくったものが送ってこられて Vket 入稿できなかったからです。

そういう需要があるにはあるので、放流します。

以下ソースコード全文

/*-------------------------------------------------------------------------------------------
 * Copyright (c) Natsuneko. All rights reserved.
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 *------------------------------------------------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using UnityEditor;

using UnityEngine;
using UnityEngine.UI;

using Object = UnityEngine.Object;

namespace Mochizuki.Camesh
{
    internal class CanvasToMesh : EditorWindow
    {
        [SerializeField]
        private Canvas[] canvases;

        [DirectoryField]
        [SerializeField]
        private DefaultAsset destTo;

        private List<Image> _images;

        private void OnGUI()
        {
            destTo = ObjectPicker("Destination To", destTo);

            EditorGUI.BeginChangeCheck();

            PropertyField(this, nameof(canvases));

            if (EditorGUI.EndChangeCheck())
                _images = (canvases ?? Array.Empty<Canvas>()).Where(w => w != null)
                                                             .Select(w => w.GetComponentInChildren<Image>())
                                                             .Where(w => w != null)
                                                             .ToList();

            if (GUILayout.Button("Generate Meshes for Canvas Images"))
                GenerateMeshesFromCanvasImages(_images, destTo);
        }

        private static void GenerateMeshesFromCanvasImages(List<Image> images, DefaultAsset destTo)
        {
            var dest = AssetDatabase.GetAssetPath(destTo);
            foreach (var (image, i) in images.Select((w, i) => (w, i)))
                GenerateMeshFromCanvasImage(image, Path.Combine(dest, $"{i}.asset"));

            AssetDatabase.Refresh();
        }

        private static void GenerateMeshFromCanvasImage(Image image, string dest)
        {
            // generate quad
            var canvas = image.GetComponent<RectTransform>();
            var rect = canvas.rect;

            var height = rect.height;
            var width = rect.width;

            var a = new Vector3(-1f * width / 2f, height / 2f);
            var b = new Vector3(width / 2f, height / 2f);
            var c = new Vector3(-1f * width / 2, -1f * height / 2f);
            var d = new Vector3(width / 2f, -1 * height / 2f);
            var tris = new[] { 0, 1, 2, 1, 3, 2 };
            var mesh = new Mesh { vertices = new[] { a, b, c, d }, triangles = tris };

            var w = 1 / 18f;

            var uvs = new[] { new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0) };
            mesh.SetUVs(0, uvs.ToList());
            mesh.RecalculateNormals();

            AssetDatabase.CreateAsset(mesh, dest);
        }

        [MenuItem("Mochizuki/Camesh/Editor")]
        public static void ShowWindow()
        {
            var window = GetWindow<CanvasToMesh>();
            window.titleContent = new GUIContent("Canvas Images to Mesh Converter");

            window.Show();
        }

        private static T ObjectPicker<T>(string label, T obj) where T : Object
        {
            return EditorGUILayout.ObjectField(new GUIContent(label), obj, typeof(T), true) as T;
        }

        private static void PropertyField(EditorWindow obj, string name)
        {
            var so = new SerializedObject(obj);
            so.Update();

            EditorGUILayout.PropertyField(so.FindProperty(name), true);

            so.ApplyModifiedProperties();
        }
    }
}

これだけ、おしまい。