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(); } }