Unity制作3D图表组件------扇形图

上篇有柱状图于折线图的实现。

这篇主要实现一下柱状图。

实现方式:把圆环体拆分成一个一个的小长方体,如图(顶视图)绿色部分

还是继承ChartBase.cs

上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 扇形统计图
/// </summary>
public class SectorChart : ChartBase
{
    List<float> tempPointY = new List<float>();
    /// <summary>
    /// 展示动画
    /// </summary>
    public override void ShowAnim()
    {
        for (int i = 0; i < pointsInfos.Count; i++)
        {
            for (int j = 0; j < pointsInfos[i].itemSectorPercent.Length; j++)
            {
                int tempI = i;
                int tempJ = j;

                StartCoroutine(DoFloatValue(0, pointsInfos[i].itemSectorPercent[j], 1, (value) =>
                {
                    pointsInfos[tempI].itemSectorPercent[tempJ] = value;
                }));
            }
        }
    }


    public override void CreateMesh()
    {

        for (int i = 0; i < pointsInfos.Count; i++)
        {
            if (pointsInfos[i].itemSectorPercent.Length != meshs.Count)
            {
                DeleteAllItemObjs();
                GameObject tempParent = new GameObject();
                tempParent.name = meshName;
                tempParent.transform.position = Vector3.zero;
                allChartParentObj.Add(tempParent);
                for (int j = 0; j < pointsInfos[i].itemSectorPercent.Length; j++)
                {
                    GameObject itemObj = new GameObject();
                    itemObj.name = meshName + "_Child_" + j.ToString();
                    itemObj.transform.parent = tempParent.transform;
                    Mesh mesh = new Mesh();
                    meshs.Add(mesh);
                    itemObj.AddComponent<MeshFilter>().mesh = mesh;
                    itemObj.AddComponent<MeshRenderer>();
                    itemObj.GetComponent<MeshRenderer>().material = mat;
                    allChartItemObj.Add(itemObj);
                }
            }
        }
    }
    /// <summary>
    /// 当前这个扇形的起始角度
    /// </summary>
    float pieceAngle = 0;
    /// <summary>
    /// 当前这个扇形的结束角度
    /// </summary>
    float nextAngle = 0;

    public override void SetMeshInfo()
    {
        triangles.Clear();
        verticesAddOffset.Clear();

        pieceAngle = 0;
        nextAngle = 0;

        for (int j = 0; j < pointsInfos[0].itemSectorPercent.Length; j++)
        {
            Vector3[] vertices = GetPointsVector3s(pointsInfos[0], j);
            verticesAddOffset.Add(new PointsInfo(SetVerticesOffset(vertices, pointsInfos[0]), Vector3.one));
            triangles.Add(GetTrianglesVector3s(vertices));
        }
    }


    /// <summary>
    /// 根据顶点和位移差获取最终位置
    /// </summary>
    /// <param name="vertices"></param>
    /// <param name="index"></param>
    /// <returns></returns>
    public override Vector3[] SetVerticesOffset(Vector3[] vertices, PointsInfo _points)
    {

        Vector3[] tempV3 = new Vector3[vertices.Length];

        for (int i = 0; i < vertices.Length; i++)
        {
            tempV3[i] = vertices[i];

            tempV3[i] += _points.points[0];

        }

        return tempV3;
    }


    /// <summary>
    /// 获取正方体的每个面顶点坐标   (先绘出顶面第一个长方形,再绘制底面第一个长方形,依次连接长方体的面)
    /// </summary>
    /// <param name="count"></param>
    /// <returns></returns>
    protected Vector3[] GetPointsVector3s(PointsInfo _points, int index)
    {

        List<Vector3> tempPoints = new List<Vector3>();

        //立方体初始的点,取内圆心   上表面的一个点
        Vector3 firstUpPoint = new Vector3(_points.size.x * _points.inCirclePercent, -_points.size.y / 2f, 0);
        ///上表面的中心点
        Vector3 centerUp = center + new Vector3(0, _points.size.y / 2f, 0);

        if (index == 0)
        {
            pieceAngle = 0;
        }
        else
        {
            pieceAngle += _points.itemSectorPercent[index - 1] * 360f;
        }

        nextAngle += _points.itemSectorPercent[index] * 360f;
        float offsetAngle = nextAngle - pieceAngle;
        for (int i = 0; i < _points.sertorCount; i++)
        {
            //立方体上表面多边形点
            List<Vector3> tempUpPoints = new List<Vector3>();
            //立方体下表面多边形点
            List<Vector3> tempDownPoints = new List<Vector3>();

            float tempAngle = pieceAngle + (float)(i) / (float)_points.sertorCount * (nextAngle - pieceAngle);
            float tempNextAngle = pieceAngle + (float)(i + 1) / (float)_points.sertorCount * (nextAngle - pieceAngle);
            if (i == 0)
            {
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x * _points.inCirclePercent, tempAngle, offsetAngle * _points.insertValue));
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x, tempAngle, offsetAngle * _points.insertValue));
            }
            else
            {
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x * _points.inCirclePercent, tempAngle));
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x, tempAngle));
            }
            if (i == _points.sertorCount - 1)
            {
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x, tempNextAngle, -offsetAngle * _points.insertValue));
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x * _points.inCirclePercent, tempNextAngle, -offsetAngle * _points.insertValue));
            }
            else
            {
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x, tempNextAngle));
                tempUpPoints.Add(RotateAroundByPointByDistance(firstUpPoint, centerUp, Vector3.up, _points.size.x * _points.inCirclePercent, tempNextAngle));
            }


            for (int j = 0; j < tempUpPoints.Count; j++)
            {
                tempDownPoints.Add(tempUpPoints[j] - new Vector3(0, _points.size.y, 0));
            }
            tempPoints.AddRange(GetAllTrianglesPoint(tempUpPoints, tempDownPoints));

        }

        return tempPoints.ToArray();
    }
    /// <summary>
    /// 根据上表面下表面的八个顶点确定立方体的所有点位(顺时针排序)
    /// </summary>
    /// <param name="inputUpV3s">上表面的四个点</param>
    /// <param name="inputDownV3s">下表面的四个点</param>
    /// <returns></returns>
    Vector3[] GetAllTrianglesPoint(List<Vector3> inputUpV3s, List<Vector3> inputDownV3s, string ceMian = "Both")
    {
        Vector3[] outPutPoints = new Vector3[24];

        //顶面
        for (int i = 0; i < inputUpV3s.Count; i++)
        {
            outPutPoints[i] = inputUpV3s[i];
        }
        //内侧
        outPutPoints[4] = inputUpV3s[0];
        outPutPoints[5] = inputUpV3s[3];
        outPutPoints[6] = inputDownV3s[3];
        outPutPoints[7] = inputDownV3s[0];

        //右面
        if (ceMian == "Both" || ceMian == "Right")
        {
            outPutPoints[8] = inputUpV3s[3];
            outPutPoints[9] = inputUpV3s[2];
            outPutPoints[10] = inputDownV3s[2];
            outPutPoints[11] = inputDownV3s[3];
        }
        //外侧
        outPutPoints[12] = inputUpV3s[2];
        outPutPoints[13] = inputUpV3s[1];
        outPutPoints[14] = inputDownV3s[1];
        outPutPoints[15] = inputDownV3s[2];

        //左面
        if (ceMian == "Both" || ceMian == "Left")
        {
            outPutPoints[16] = inputUpV3s[1];
            outPutPoints[17] = inputUpV3s[0];
            outPutPoints[18] = inputDownV3s[0];
            outPutPoints[19] = inputDownV3s[1];
        }

        //底面
        outPutPoints[20] = inputDownV3s[3];
        outPutPoints[21] = inputDownV3s[2];
        outPutPoints[22] = inputDownV3s[1];
        outPutPoints[23] = inputDownV3s[0];

        return outPutPoints;
    }


    public Vector3 RotateAroundByPointByDistance(Vector3 selfPoint, Vector3 rotatePoint, Vector3 axis, float distance, float angle, float offsetAngle = 0)
    {
        Quaternion q = Quaternion.AngleAxis(angle + offsetAngle, axis);
        Vector3 distanceOffset = Vector3.ProjectOnPlane(Vector3.Normalize(new Vector3((1 - axis.x) * selfPoint.x, (1 - axis.y) * selfPoint.y, (1 - axis.z) * selfPoint.z) - new Vector3((1 - axis.x) * rotatePoint.x, (1 - axis.y) * rotatePoint.y, (1 - axis.z) * rotatePoint.z)), axis) * distance;
        return q * distanceOffset;
    }

}



public partial class PointsInfo
{
    /// <summary>
    /// 内圈比例
    /// </summary>
    public float inCirclePercent;
    /// <summary>
    /// 扇形之间的间隔
    /// </summary>
    public float insertValue;
    /// <summary>
    /// 多边形边数
    /// </summary>
    public int sertorCount;

    /// <summary>
    /// 每个扇形的百分比
    /// </summary>
    public float[] itemSectorPercent;
    public PointsInfo(Vector3[] _points, Vector3 _size, float _percent, float _insertValue, int _sertorCount, float[] _itemSectorPercent)
    {
        points = _points;
        size = _size;
        inCirclePercent = _percent;
        insertValue = _insertValue;
        sertorCount = _sertorCount;
        itemSectorPercent = _itemSectorPercent;
    }
}

工程链接:https://github.com/wtb521thl/ChartTest

原文地址:https://www.cnblogs.com/yzxhz/p/13039362.html