void CreateClosedRoad(List<Vector3> points, Material loadedMat) { if (points.Count < 4) throw new ArgumentException("至少需要4个以上的点才能创建一条闭合道路"); // 确保道路是闭合的,复制首个元素到末尾模拟闭合效果 List<Vector3> closedPoints = DuplicatePathToFormStrip(points); List<int> indices = GenerateTriangleIndicesForClosure(closedPoints.Count); GameObject gameObject = new GameObject("Quad"); gameObject.transform.SetParent(transform, true); // 构建 Mesh 数据 Mesh mesh = new Mesh(); mesh.vertices = closedPoints.ToArray(); // 设置顶点位置 mesh.triangles = indices.ToArray(); // 设置三角形索引 // 计算法线和 UV 映射 (可选,提升视觉质量) mesh.RecalculateNormals(); // 将生成的 Mesh 应用到游戏对象上 var mf = gameObject.AddComponent<MeshFilter>(); mf.mesh = mesh; // 添加渲染组件 gameObject.AddComponent<MeshRenderer>(); Renderer renderer = gameObject.GetComponent<Renderer>(); renderer.material = loadedMat; // 应用材质 } // 增强型版本 - 创建更多细分层次增强立体感 List<Vector3> DuplicatePathToFormStrip(List<Vector3> originals) { float segmentDetailFactor = 5F; //控制细分数目因子越大越细致 List<Vector3> refinedResult = new List<Vector3>(); for (int idx = 0; idx < originals.Count() - 1; ++idx) { Vector3 currPnt = originals[idx]; Vector3 nextPnt = originals[(idx + 1) % originals.Count()]; // 插值计算沿途若干中间参考位置以便更好拟合实际轨迹走向 for (float t = 0; t <= segmentDetailFactor; t += 1) { float ratio = t / segmentDetailFactor; Vector3 interpolatedPt = Vector3.Lerp(currPnt, nextPnt, ratio); // 此处同样沿法线方向拓展获得双边布局形式... Vector3 dir = (nextPnt - currPnt).normalized; Vector3 normalVec = Vector3.Cross(dir, Vector3.up).normalized; refinedResult.Add(interpolatedPt - normalVec * roadWidth * .5F); //左半部 refinedResult.Add(interpolatedPt + normalVec * roadWidth * .5F); //右半部 } } return refinedResult; } List<int> GenerateTriangleIndicesForClosure(int vertexCount) { if (vertexCount < 4 || vertexCount % 2 != 0) throw new ArgumentException("Vertex count should be even and greater than or equal to four."); List<int> indices = new List<int>(); // 构建内部矩形分割 for (int i = 0; i < vertexCount - 2; i += 2) { int leftStart = i; int rightStart = i + 1; // 添加第一个三角形 indices.AddRange(new int[] { leftStart, rightStart, leftStart + 2 }); // 添加第二个三角形 indices.AddRange(new int[] { rightStart, rightStart + 2, leftStart + 2 }); } // 完善闭环处理 if (vertexCount >= 4) { int firstLeft = 0; int firstRight = 1; int lastLeft = vertexCount - 2; int lastRight = vertexCount - 1; // 关联最后一排回到第一列构成封闭结构 indices.AddRange(new int[] { lastLeft, lastRight, firstLeft }); indices.AddRange(new int[] { lastRight, firstRight, firstLeft }); } return indices; }上面的代码已经成功绘制出了道面面的外边框的形状 带状的 但是我实际想要的是面状的mesh 如何调整
时间: 2025-06-27 18:04:59 浏览: 16
根据您的描述,您希望将现有的带状(条纹状)网格结构调整为面状的完整 Mesh 形式。目前代码生成的结果更像是“双车道”式的两侧平行扩展形式,而未完全闭合成单一实体表面。
为了达到真正的面状效果,我们需要注意以下几点:
1. **减少冗余顶点**
当前代码中每段路径都被分解成了左右两边独立的一系列顶点对儿。实际上对于构建单层连续表面积分模型而言没必要这样做。只需要保留原始输入路径上的那些基准控制节点就够了。
2. **修改索引导则规则**
需重新设计三角剖分策略使得各片段间能够无缝衔接成为整体而非仅仅两侧行走路线简单拼接而成的样子。具体做法可以从当前某一边开始逐一向另一侧推进直至完成整个循环过程为止。
下面是改进后的版本示例代码及其解释说明:
---
### 修改版代码
```csharp
// 主函数入口:创建闭合道路
void CreateClosedSurface(List<Vector3> points, Material loadedMat, float width)
{
if (points.Count < 4)
throw new ArgumentException("至少需要四个以上点才能创建一条闭合的道路");
// 计算每个顶点对应的偏移向量(用于宽度扩展)
ComputeOffsetVectors(points);
// 构造最终顶点集合
List<Vector3> vertices = GenerateVerticesWithWidth(points, width);
// 生产对应三角形索引组
List<int> indices = GenerateTriangularIndices(vertices.Count);
// 创建 GameObject 并添加必要组件
GameObject go = new GameObject("ClosedRoad");
go.transform.SetParent(transform, true);
// 初始化并配置 Mesh 数据
Mesh mesh = new Mesh();
mesh.vertices = vertices.ToArray();
mesh.triangles = indices.ToArray();
// 自动计算法线和 UV 贴图
mesh.RecalculateNormals();
mesh.UV = CalculateDefaultUVs(vertices);
// 绑定至场景当中
var mf = go.AddComponent<MeshFilter>();
mf.mesh = mesh;
var mr = go.AddComponent<MeshRenderer>();
mr.material = loadedMat;
}
/// <summary>
/// 根据给定点序列计算横向偏移矢量
/// </summary>
private Dictionary<int, Vector3> offsetDirectionsCache = new Dictionary<int, Vector3>();
void ComputeOffsetVectors(List<Vector3> points)
{
for (int i = 0; i < points.Count; ++i)
{
int prevIndex = (i == 0 ? points.Count - 1 : i - 1);
int nextIndex = (i + 1) % points.Count;
Vector3 directionA = points[i] - points[prevIndex];
Vector3 directionB = points[nextIndex] - points[i];
Vector3 avgDirection = ((directionA.normalized + directionB.normalized)/2f).normalized;
Vector3 crossProductDir = Vector3.Cross(avgDirection, Vector3.up).normalized;
offsetDirectionsCache[i] = crossProductDir;
}
}
/// <summary>
/// 使用指定宽度生成包含加宽边缘的新顶点列表
/// </summary>
List<Vector3> GenerateVerticesWithWidth(List<Vector3> originalPoints, float roadWidth)
{
List<Vector3> resultVerts = new List<Vector3>();
foreach(var kvp in offsetDirectionsCache){
int pointIdx = kvp.Key;
Vector3 basePoint = originalPoints[pointIdx];
Vector3 offsetVec = kvp.Value * (roadWidth / 2f);
// 左右两侧分别增加两个顶点
resultVerts.Add(basePoint - offsetVec); // Left side
resultVerts.Add(basePoint + offsetVec); // Right side
}
return resultVerts;
}
/// <summary>
/// 自动生成基本默认 UV 数组匹配顶点分布情况
/// </summary>
Vector2[] CalculateDefaultUVs(List<Vector3> verts)
{
Vector2[] uvs = new Vector2[verts.Count];
bool oddFlagToggle = false;
for(int j=0;j<uvs.Length;++j){
double ratioVal = j/(double)(uvs.Length-1);
if(oddFlagToggle){uv[j]=new Vector2((float)(ratioVal*.9+.05),(float)((j%2)==0?0:.7));}else{uv[j].x=(float)rV.y=.3;}
}
}
```
此代码尝试解决的问题在于消除不必要的重复项同时合理安排相邻单元之间的链接关系,进而保证最后呈现出来的图形既满足需求又具备良好渲染特性。
---
阅读全文
相关推荐

















