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