Unity 生成圆角Cube

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CubeMeshController : MonoBehaviour
{
    private float xSize = 3;
    private float ySize = 2;
    private float zSize = 4;
    private float cornerRadius = 2.3f;
    private int cornerSplitTime = 2;
    private float xRadius;
    private float yRadius;
    private float zRadius;
    private List<Vector2> uvList;
    private List<int> triangleList;
    private List<Vector3> vertexList;
    private int cornerFaceMaxIdx = 4;
    private int curvePointCnt = 9;
    private int cornerPointCnt = 18;
    private int mainFaceVertexOffset; //因为侧面和正面的uv贴图要做区分,不能渐变,offset后的定点用来缝合正面(上下两面)
    private bool isLeftButtomCorner;
    private bool isLeftTopCorner;
    private bool isRightTopCorner;
    private bool isRightButtomCorner;


    private Mesh GenerateMesh()
    {
        Mesh mesh = new Mesh();
        generateVertices();
        generateTriangles();
        mesh.vertices = vertexList.ToArray();
        mesh.triangles = triangleList.ToArray();
        mesh.RecalculateNormals();
        mesh.RecalculateTangents();
        mesh.uv = uvList.ToArray();
        return mesh;
    }
    public Mesh GetMeshNormal(float xSize, float ySize, float zSize, float cornerRadius = 2f, float cornerSplitTime = 3)
    {
        this.isLeftButtomCorner = true;
        this.isLeftTopCorner = true;
        this.isRightButtomCorner = true;
        this.isRightTopCorner = true;
        this.xSize = xSize;
        this.ySize = ySize;
        this.zSize = zSize;
        this.cornerSplitTime = 3;
        this.cornerRadius = cornerRadius;
        xRadius = xSize / 2.0f;
        yRadius = ySize / 2.0f;
        zRadius = zSize / 2.0f;
        curvePointCnt = ((int)Math.Pow(2, cornerSplitTime) + 1);
        cornerPointCnt = curvePointCnt * 2;
        cornerFaceMaxIdx = curvePointCnt - 1;
        mainFaceVertexOffset = cornerPointCnt * 4;// 这里uniqueVertexCnt表示独立的定点数 72
        return GenerateMesh();
    }
    public Mesh GetMesh(float xSize, float ySize, float zSize, GroundModel groundModel,float cornerRadius = 2f, int cornerSplitTime = 3)
    {
        this.isLeftButtomCorner = groundModel.isLeftButtomCorner;
        this.isLeftTopCorner = groundModel.isLeftTopCorner;
        this.isRightButtomCorner = groundModel.isRightButtomCorner;
        this.isRightTopCorner = groundModel.isRightTopCorner;
        this.xSize = xSize;
        this.ySize = ySize;
        this.zSize = zSize;
        this.cornerSplitTime = cornerSplitTime;
        this.cornerRadius = cornerRadius;
        xRadius = xSize / 2.0f;
        yRadius = ySize / 2.0f;
        zRadius = zSize / 2.0f;
        this.curvePointCnt = ((int)Math.Pow(2, cornerSplitTime) + 1);
        this.cornerPointCnt = this.curvePointCnt * 2;
        this.cornerFaceMaxIdx = this.curvePointCnt - 1;
        this.mainFaceVertexOffset = this.cornerPointCnt * 4; //
        return GenerateMesh();
    }
    private void generateVertices()
    {
        vertexList = new List<Vector3>();
        SetRightTopCornerList();
        SetTopLeftCornerList();
        SetBottomLeftCornerList();
        SetBottomRightCornerList();
        vertexList.AddRange(rightTopCornerList);
        vertexList.AddRange(topLeftConnerList);
        vertexList.AddRange(buttomLeftConnerList);
        vertexList.AddRange(buttomRightConnerList);

        //此处再加一遍的原因是因为顶面和侧面的uv不一样
        vertexList.AddRange(rightTopCornerList);
        vertexList.AddRange(topLeftConnerList);
        vertexList.AddRange(buttomLeftConnerList);
        vertexList.AddRange(buttomRightConnerList);

        uvList = new List<Vector2>();
        for (int i = 0; i < vertexList.Count; i++)
        {
            Vector3 vertex = vertexList[i];
            Vector2 uv;
            if (i < mainFaceVertexOffset)
            {
                uv = new Vector2(0.5f + vertex.x /xSize, (0.5f + vertex.y / ySize) * 0.08f);
            }
            else
            {
                uv = new Vector2(0.5f + vertex.x / xSize,  0.14f + (0.5f + vertex.z/zSize)* 0.86f);
            }
            uvList.Add(uv);
        }
    }

    public class VectorCenter
    {
        public Vector3 center;
        public float distance;
        public VectorCenter(Vector3 center, float distance)
        {
            this.center = center;
            this.distance = distance;
        }
    }


    private void splitAndAppendCenter(Vector3 start, Vector3 end, int splitTime, List<VectorCenter> vectorCenters, Vector3 oriStart, Vector3 circelCenter, float splitlength)
    {

        Vector3 center = GetCircleEdgePioint((start + end) / 2.0f, circelCenter, splitlength);
        vectorCenters.Add(new VectorCenter(center, Vector3.Distance(center, oriStart)));
        splitTime -= 1;
        if (splitTime > 0)
        {
            splitAndAppendCenter(start, center, splitTime, vectorCenters, oriStart, circelCenter, splitlength);
            splitAndAppendCenter(center, end, splitTime, vectorCenters, oriStart, circelCenter, splitlength);
        }
    }

    private void AddCenterList(List<Vector3> list, Vector3 start, Vector3 end, Vector3 circelCenter, float splitlength)
    {
        List<VectorCenter> vectorCenters = GetCencer(cornerSplitTime - 1, start, end, circelCenter, splitlength);
        foreach (VectorCenter vectorCenter in vectorCenters)
        {
            list.Add(vectorCenter.center);
        }
    }
    private List<VectorCenter> GetCencer(int splitTime, Vector3 start, Vector3 end, Vector3 circleCenter, float _radius)
    {
        List<VectorCenter> vectorCenters = new List<VectorCenter>();
        splitAndAppendCenter(start, end, splitTime, vectorCenters, start, circleCenter, _radius);
        return vectorCenters.OrderBy(item => item.distance).ToList();

    }
    List<Vector3> buttomRightConnerList;
    private void SetBottomRightCornerList()
    {
        float spliteLength = cornerRadius;
        if (!isRightButtomCorner)
        {
            spliteLength = 0;
        }
        buttomRightConnerList = new List<Vector3>();
        // buttom face
        Vector3 corner1Point = new Vector3(xRadius, -yRadius, -zRadius);
        Vector3 circelCenter1 = GetCircleCenter(spliteLength, corner1Point, CORNERTYPE.bottomRight);
        Vector3 buttomCenter = GetCircleEdgePioint(corner1Point, circelCenter1, spliteLength);
        Vector3 point1Buttom = new Vector3(xRadius - spliteLength / 2.0f, -yRadius, -zRadius);
        Vector3 point2Buttom = new Vector3(xRadius, -yRadius, -zRadius + spliteLength / 2.0f);
        buttomRightConnerList.Add(point1Buttom);
        AddCenterList(buttomRightConnerList, point1Buttom, buttomCenter, circelCenter1, spliteLength);
        buttomRightConnerList.Add(buttomCenter);
        AddCenterList(buttomRightConnerList, buttomCenter, point2Buttom, circelCenter1, spliteLength);
        buttomRightConnerList.Add(point2Buttom);
        // top face
        Vector3 corner2Point = new Vector3(xRadius, yRadius, -zRadius);
        Vector3 circelCenter2 = GetCircleCenter(spliteLength, corner2Point, CORNERTYPE.bottomRight);
        Vector3 topCenter = GetCircleEdgePioint(corner2Point, circelCenter2, spliteLength);
        Vector3 point1Top = new Vector3(xRadius - spliteLength / 2.0f, yRadius, -zRadius);
        Vector3 point2Top = new Vector3(xRadius, yRadius, -zRadius + spliteLength / 2.0f);
        buttomRightConnerList.Add(point1Top);
        AddCenterList(buttomRightConnerList, point1Top, topCenter, circelCenter2, spliteLength);
        buttomRightConnerList.Add(topCenter);
        AddCenterList(buttomRightConnerList, topCenter, point2Top, circelCenter2, spliteLength);
        buttomRightConnerList.Add(point2Top);

    }
    List<Vector3> rightTopCornerList;
    private void SetRightTopCornerList()
    {
        float _cornerRadius = cornerRadius;
        if (!isRightTopCorner)
        {
            _cornerRadius = 0;
        }
        rightTopCornerList = new List<Vector3>();
        // buttom face
        Vector3 corner1Point = new Vector3(xRadius, -yRadius, zRadius);
        Vector3 circleCenter1 = GetCircleCenter(_cornerRadius, corner1Point, CORNERTYPE.topRight);
        Vector3 bottomCenter = GetCircleEdgePioint(corner1Point, circleCenter1, _cornerRadius);
        Vector3 point1Bottom = new Vector3(xRadius, -yRadius, zRadius - _cornerRadius / 2.0f);
        Vector3 point2Bottom = new Vector3(xRadius - _cornerRadius / 2.0f, -yRadius, zRadius);
        rightTopCornerList.Add(point1Bottom);
        AddCenterList(rightTopCornerList, point1Bottom, bottomCenter, circleCenter1, _cornerRadius);
        rightTopCornerList.Add(bottomCenter);
        AddCenterList(rightTopCornerList, bottomCenter, point2Bottom, circleCenter1, _cornerRadius);
        rightTopCornerList.Add(point2Bottom);
        // top face
        Vector3 corner2Point = new Vector3(xRadius, yRadius, zRadius);
        Vector3 circelCenter2 = GetCircleCenter(_cornerRadius, corner2Point, CORNERTYPE.topRight);
        Vector3 topCenter = GetCircleEdgePioint(corner2Point, circelCenter2, _cornerRadius);
        Vector3 point1Top = new Vector3(xRadius, yRadius, zRadius - _cornerRadius / 2.0f);
        Vector3 point2Top = new Vector3(xRadius - _cornerRadius / 2.0f, yRadius, zRadius);
        rightTopCornerList.Add(point1Top);
        AddCenterList(rightTopCornerList, point1Top, topCenter, circelCenter2, _cornerRadius);
        rightTopCornerList.Add(topCenter);
        AddCenterList(rightTopCornerList, topCenter, point2Top, circelCenter2, _cornerRadius);
        rightTopCornerList.Add(point2Top);
    }
    List<Vector3> topLeftConnerList;
    private void SetTopLeftCornerList()
    {
        float spliteLength = cornerRadius;
        if (!isLeftTopCorner)
        {
            spliteLength = 0;
        }
        topLeftConnerList = new List<Vector3>();
        // buttom face
        Vector3 corner1Point = new Vector3(-xRadius, -yRadius, zRadius);
        Vector3 circelCenter1 = GetCircleCenter(spliteLength, corner1Point, CORNERTYPE.topLeft);
        Vector3 buttomCenter = GetCircleEdgePioint(corner1Point, circelCenter1, spliteLength);
        Vector3 point1Buttom = new Vector3(-xRadius + spliteLength / 2.0f, -yRadius, zRadius);
        Vector3 point2Buttom = new Vector3(-xRadius, -yRadius, zRadius - spliteLength / 2.0f);
        topLeftConnerList.Add(point1Buttom);
        AddCenterList(topLeftConnerList, point1Buttom, buttomCenter, circelCenter1, spliteLength);
        topLeftConnerList.Add(buttomCenter);
        AddCenterList(topLeftConnerList, buttomCenter, point2Buttom, circelCenter1, spliteLength);
        topLeftConnerList.Add(point2Buttom);
        // top face
        Vector3 corner2Point = new Vector3(-xRadius, yRadius, zRadius);
        Vector3 circelCenter2 = GetCircleCenter(spliteLength, corner2Point, CORNERTYPE.topLeft);
        Vector3 topCenter = GetCircleEdgePioint(corner2Point, circelCenter2, spliteLength);
        Vector3 point1Top = new Vector3(-xRadius + spliteLength / 2.0f, yRadius, zRadius);
        Vector3 point2Top = new Vector3(-xRadius, yRadius, zRadius - spliteLength / 2.0f);
        topLeftConnerList.Add(point1Top);
        AddCenterList(topLeftConnerList, point1Top, topCenter, circelCenter2, spliteLength);
        topLeftConnerList.Add(topCenter);
        AddCenterList(topLeftConnerList, topCenter, point2Top, circelCenter2, spliteLength);
        topLeftConnerList.Add(point2Top);

    }
    List<Vector3> buttomLeftConnerList;

    private void SetBottomLeftCornerList()
    {
        float spliteLength = cornerRadius;
        if (!isLeftButtomCorner)
        {
            spliteLength = 0;
        }
        buttomLeftConnerList = new List<Vector3>();
        // buttom face
        Vector3 corner1Point = new Vector3(-xRadius, -yRadius, -zRadius);
        Vector3 circelCenter1 = GetCircleCenter(spliteLength, corner1Point, CORNERTYPE.bottomLeft);
        Vector3 buttomCenter = GetCircleEdgePioint(corner1Point, circelCenter1, spliteLength);
        Vector3 point1Buttom = new Vector3(-xRadius, -yRadius, -zRadius + spliteLength / 2.0f);
        Vector3 point2Buttom = new Vector3(-xRadius + spliteLength / 2.0f, -yRadius, -zRadius);
        buttomLeftConnerList.Add(point1Buttom);
        AddCenterList(buttomLeftConnerList, point1Buttom, buttomCenter, circelCenter1, spliteLength);
        buttomLeftConnerList.Add(buttomCenter);
        AddCenterList(buttomLeftConnerList, buttomCenter, point2Buttom, circelCenter1, spliteLength);
        buttomLeftConnerList.Add(point2Buttom);
        // top face
        Vector3 corner2Point = new Vector3(-xRadius, yRadius, -zRadius);
        Vector3 circelCenter2 = GetCircleCenter(spliteLength, corner2Point, CORNERTYPE.bottomLeft);
        Vector3 topCenter = GetCircleEdgePioint(corner2Point, circelCenter2, spliteLength);
        Vector3 point1Top = new Vector3(-xRadius, yRadius, -zRadius + spliteLength / 2.0f);
        Vector3 point2Top = new Vector3(-xRadius + spliteLength / 2.0f, yRadius, -zRadius);
        buttomLeftConnerList.Add(point1Top);
        AddCenterList(buttomLeftConnerList, point1Top, topCenter, circelCenter2, spliteLength);
        buttomLeftConnerList.Add(topCenter);
        AddCenterList(buttomLeftConnerList, topCenter, point2Top, circelCenter2, spliteLength);
        buttomLeftConnerList.Add(point2Top);

    }
    public enum CORNERTYPE
    {
        bottomLeft,
        bottomRight,
        topLeft,
        topRight

    }
    private Vector3 GetCircleCenter(float _cornerRadius, Vector3 cornerPoint, CORNERTYPE cornerType)
    {
        Vector3 center = Vector3.zero;
        switch (cornerType)
        {
            case CORNERTYPE.bottomLeft:
                center = new Vector3(cornerPoint.x + _cornerRadius / 2.0f, cornerPoint.y, cornerPoint.z + _cornerRadius / 2.0f);
                break;
            case CORNERTYPE.bottomRight:
                center = new Vector3(cornerPoint.x - _cornerRadius / 2.0f, cornerPoint.y, cornerPoint.z + _cornerRadius / 2.0f);
                break;
            case CORNERTYPE.topLeft:
                center = new Vector3(cornerPoint.x + _cornerRadius / 2.0f, cornerPoint.y, cornerPoint.z - _cornerRadius / 2.0f);
                break;
            case CORNERTYPE.topRight:
                center = new Vector3(cornerPoint.x - _cornerRadius / 2.0f, cornerPoint.y, cornerPoint.z - _cornerRadius / 2.0f);
                break;
        }
        return center;
    }

    private Vector3 GetCircleEdgePioint(Vector3 cornerPoint, Vector3 centerPoint, float spliteLength)
    {
        return centerPoint + (cornerPoint - centerPoint).normalized * spliteLength / 2.0f;
    }

    private void AddSurroundCornerTriangle(int cornerIdx)
    {
        if(cornerIdx != -1)
        {
            int cornerOffset = cornerIdx * cornerPointCnt;
            for (int i = 0; i < this.curvePointCnt - 1; i++)
            {
               
                //顺时针,底下1个点上面2个点的三角形
                triangleList.Add(i + cornerOffset);
                triangleList.Add(i + this.curvePointCnt + cornerOffset);
                triangleList.Add(i + this.curvePointCnt + 1 + cornerOffset);
                //顺时针,底下2个点上面1个点的三角形,与上面的三角形构成四边形
                triangleList.Add(i + cornerOffset);
                triangleList.Add(i + this.curvePointCnt + 1 + cornerOffset);
                triangleList.Add(i + 1 + cornerOffset);
            }
        }
    }

    private void AddSurroundFaceTriangle(int cornerIdx)
    {
        int cornerOffset = this.cornerPointCnt * cornerIdx;

        //上面三角形
        triangleList.Add((this.curvePointCnt - 1 + cornerOffset));
        triangleList.Add((this.cornerPointCnt - 1 + cornerOffset));
        if(cornerIdx == 3)
        {
            triangleList.Add(this.curvePointCnt);
        }
        else
        {
            triangleList.Add((this.cornerPointCnt + this.curvePointCnt + cornerOffset));
        }

        //下面三角形
        triangleList.Add((this.curvePointCnt - 1 + cornerOffset));
        if (cornerIdx == 3)
        {
            triangleList.Add(this.curvePointCnt);
            triangleList.Add(0);
        }
        else
        {
            triangleList.Add((this.cornerPointCnt + this.curvePointCnt + cornerOffset));
            triangleList.Add((this.cornerPointCnt + cornerOffset));
        }
      
    }

    
    private void AddBottomAndTopFaceEdge(int cornerIdx)
    {
        if(cornerIdx == 0)
        {

            for (int i = 1; i < this.curvePointCnt -1; i++)
            {
                //底面
                triangleList.Add(0 + mainFaceVertexOffset);
                triangleList.Add(i + mainFaceVertexOffset);
                triangleList.Add(i + 1 + mainFaceVertexOffset);
            }
            for (int i = 1; i < this.curvePointCnt - 1; i++)
            {
                //顶面
                triangleList.Add(0 + this.curvePointCnt + mainFaceVertexOffset);
                triangleList.Add(i + 1 + this.curvePointCnt + mainFaceVertexOffset);
                triangleList.Add(i + this.curvePointCnt + mainFaceVertexOffset );

            }
            
        }
        else
        {
            for (int i = 0; i < this.curvePointCnt - 1; i++)
            {
                //底面
                triangleList.Add(0 + mainFaceVertexOffset);
                triangleList.Add(i + mainFaceVertexOffset + cornerIdx * cornerPointCnt );
                triangleList.Add(i + 1 + mainFaceVertexOffset + cornerIdx * cornerPointCnt);
            }
            for (int i = 0; i < this.curvePointCnt - 1; i++)
            {
                //顶面
                triangleList.Add(0 + this.curvePointCnt + mainFaceVertexOffset );
                triangleList.Add(i + 1 + this.curvePointCnt + mainFaceVertexOffset + cornerIdx * cornerPointCnt);
                triangleList.Add(i + this.curvePointCnt + mainFaceVertexOffset + cornerIdx * cornerPointCnt);
            }
        }
        
    }
    
    private void AddButtomAndTopFaceCenter()
    {
        //bottom face 正确
        triangleList.Add(0 + mainFaceVertexOffset);
        triangleList.Add(this.curvePointCnt - 1 + mainFaceVertexOffset);
        triangleList.Add(this.cornerPointCnt + mainFaceVertexOffset);

        triangleList.Add(0 + mainFaceVertexOffset);
        triangleList.Add(this.curvePointCnt - 1 + this.cornerPointCnt + mainFaceVertexOffset);
        triangleList.Add(this.cornerPointCnt + this.cornerPointCnt + mainFaceVertexOffset);

        triangleList.Add(0 + mainFaceVertexOffset);
        triangleList.Add(this.curvePointCnt - 1 + this.cornerPointCnt * 2 + mainFaceVertexOffset);
        triangleList.Add(this.cornerPointCnt + this.cornerPointCnt * 2 + mainFaceVertexOffset);


        //顶面
        triangleList.Add(this.curvePointCnt - 1 + this.curvePointCnt + mainFaceVertexOffset);
        triangleList.Add(0 + this.curvePointCnt + mainFaceVertexOffset);
        triangleList.Add(this.cornerPointCnt + +this.curvePointCnt + mainFaceVertexOffset);

        triangleList.Add(this.curvePointCnt - 1 + this.cornerPointCnt + this.curvePointCnt + mainFaceVertexOffset);
        triangleList.Add(0 + mainFaceVertexOffset + this.curvePointCnt);
        triangleList.Add(this.cornerPointCnt + this.cornerPointCnt + this.curvePointCnt + mainFaceVertexOffset);


        triangleList.Add(this.curvePointCnt - 1 + this.curvePointCnt + this.cornerPointCnt * 2 + mainFaceVertexOffset);
        triangleList.Add(0 + mainFaceVertexOffset+ this.curvePointCnt);
        triangleList.Add(this.cornerPointCnt + this.curvePointCnt + this.cornerPointCnt * 2 + mainFaceVertexOffset);


    }
    private void generateTriangles()
    {
        triangleList = new List<int>();
        for (int cornerIndex = 0; cornerIndex < 4; cornerIndex++)
        {
            AddSurroundCornerTriangle(cornerIndex);
            AddSurroundFaceTriangle(cornerIndex);
            AddBottomAndTopFaceEdge(cornerIndex);
        }
        AddButtomAndTopFaceCenter();

    }
}

 

posted @ 2020-05-22 15:29  三里路异乡客  阅读(1052)  评论(0编辑  收藏  举报