유니티 삼각형 그래프 그리기 #(외곽선)테두리만 존재하게

삼각형 그래프를 그리고 싶었는데 LineRender는 잘 안되고...

어쩔 수 없이 Mesh를 활용해서 삼각형 그래프를 그려보는 방식으로 시도해봤습니다.

 

결과는 아래 움짤과 같이 잘 작동하나 코드에 문제가 있을 수 있으니.. 조심히 사용하시길 바랍니다.

삼각형 그래프 그리기

 

 

코드

using System.Collections.Generic;
using UnityEngine;

namespace IslandMonkey
{
    [RequireComponent(typeof(MeshFilter))]
    [RequireComponent(typeof(MeshRenderer))]
#if UNITY_EDITOR
    [ExecuteAlways]
#endif
    public class PieChartOutline : MonoBehaviour
    {
        [SerializeField, Range(0,5f)] private float convenience = 2f;
        [SerializeField, Range(0,5f)] private float fun = 2f;
        [SerializeField, Range(0,5f)] private float productivity = 2f;
        [SerializeField, Range(0.1f, 1f)] private float circleSize = 0.2f;

        [SerializeField] private Sprite circleSprite;
        [SerializeField] private Material material;

        private Mesh mesh;
        private Dictionary<int, GameObject> circleObjects = new ();

        private MeshFilter cachedMeshFilter;
        private MeshRenderer cachedMeshRenderer;


        private void Awake()
        {
	        cachedMeshFilter = GetComponent<MeshFilter>();
	        cachedMeshRenderer = GetComponent<MeshRenderer>();
        }

        private void Start()
        {
            CreateMesh();
        }

        private void CreateMesh()
        {
            mesh = new Mesh
            {
	            name = "PieChartOutlineMesh"
            };

            Vector3 center = Vector3.zero;
            Vector3 top = center + Vector3.up * Convenience; // Todo : From Saved Convenience Value
            Vector3 left = center + Quaternion.Euler(0f, 0f, 120f) * (Vector3.up * Fun); // Todo : From Saved Fun Value
            Vector3 right = center + Quaternion.Euler(0f, 0f, -120f) * (Vector3.up * Productivity); // Todo : From Saved Productivity Value

            // Define vertices (only need vertices for the outline)
            Vector3[] vertices = new Vector3[] { top, left, right };

            // Define edges (outline lines)
            int[] indices = new int[]
            {
                0, 1, // Line 1: top -> left
                1, 2, // Line 2: left -> right
                2, 0,  // Line 3: right -> top
            };

            mesh.vertices = vertices;
            mesh.SetIndices(indices, MeshTopology.Lines, 0); // Use MeshTopology. Lines to draw lines between vertices

            MeshFilter meshFilter = cachedMeshFilter;
            meshFilter.mesh = mesh;

            MeshRenderer meshRenderer = cachedMeshRenderer;
            meshRenderer.material = material;

            if (circleObjects.Count <= 0)
            {
                InstantiateCircleAtVertex(top, 0);
                InstantiateCircleAtVertex(left, 1);
                InstantiateCircleAtVertex(right, 2);
            }
        }

        private void UpdateMesh()
        {
	        if (circleObjects.Count <= 0) return;

	        Vector3 center = Vector3.zero;
	        Vector3 top = center + Vector3.up * Convenience;
	        Vector3 left = center + Quaternion.Euler(0f, 0f, 120f) * (Vector3.up * Fun);
	        Vector3 right = center + Quaternion.Euler(0f, 0f, -120f) * (Vector3.up * Productivity);

	        // Define vertices (only need vertices for the outline)
	        Vector3[] vertices = new Vector3[] { top, left, right };

	        // Define edges (outline lines)
	        int[] indices = new int[]
	        {
		        0, 1, // Line 1: top -> left
		        1, 2, // Line 2: left -> right
		        2, 0,  // Line 3: right -> top
	        };

	        mesh.vertices = vertices;
	        mesh.SetIndices(indices, MeshTopology.Lines, 0); // Use MeshTopology. Lines to draw lines between vertices

	        MeshFilter meshFilter = cachedMeshFilter;
	        meshFilter.mesh = mesh;

	        MeshRenderer meshRenderer = cachedMeshRenderer;
	        meshRenderer.material = material;

	        ChangeCircleAtVertex(top, 0);
	        ChangeCircleAtVertex(left, 1);
	        ChangeCircleAtVertex(right, 2);
        }

        private void InstantiateCircleAtVertex(Vector3 vertexPosition, int point)
        {
            if (transform.childCount > 2) return;

            GameObject circleObj = new GameObject("CircleSprite");
            circleObj.transform.parent = transform;
            circleObj.transform.localPosition = new Vector3(vertexPosition.x, vertexPosition.y, -0.5f);

            SpriteRenderer spriteRenderer = circleObj.AddComponent<SpriteRenderer>();
            spriteRenderer.sprite = circleSprite;
            spriteRenderer.sortingLayerName = "UI";
            spriteRenderer.sortingOrder = 2;

            circleObj.transform.localScale = new Vector3(CircleSize, CircleSize, 1f);

            circleObjects.Add(point, circleObj);
        }

        private void ChangeCircleAtVertex(Vector3 vertexPosition, int point)
        {
            // Check if the circleObjects dictionary contains the specified point key
            if (circleObjects.ContainsKey(point))
            {
                GameObject circleObj = circleObjects[point];

                if (circleObj != null)
                {
                    circleObj.transform.localScale = new Vector3(CircleSize, CircleSize, 1f);
                    circleObj.transform.localPosition = new Vector3(vertexPosition.x, vertexPosition.y, -0.5f);
                }
                else
                {
                    // Handle case where the GameObject has been destroyed or is null
                    Debug.LogWarning("Circle GameObject is null or destroyed.");
                    // Optionally, remove the key from the dictionary if needed
                    //circleObjects.Remove(point);
                }
            }
            else
            {
                Debug.LogWarning($"Circle GameObject for point {point} not found in dictionary.");
            }
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
	        UpdateMesh();
        }
#endif
    }
}