You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过代码实现可控制vertices的capsule mesh程序化生成?

程序化生成胶囊体网格(Capsule Mesh)的实现方案

胶囊体网格的生成逻辑非常成熟,完全可以在Runtime阶段自行实现,核心思路是将胶囊体拆分为上半球、中间圆柱体、下半球三个部分分别生成后拼接,保证衔接处顶点完全重合即可避免接缝,以下是具体实现方案:


核心实现步骤

  • 先定义可配置的基础参数:半球半径r、圆柱体高度h、径向分段数radialSegments、半球轴向分段数hemisphereSegments、圆柱体轴向分段数cylinderSegments,可根据精度需求自由调整参数
  • 生成上半球顶点:以(0, h/2, 0)为球心,纬度取值范围为0~π/2,每个纬度环的半径为r*cos(纬度角),y坐标为h/2 + r*sin(纬度角),x/z坐标按经度角循环计算即可
  • 生成中间圆柱体顶点:上下两个端环的顶点坐标和上下半球的赤道环顶点完全对齐,y坐标从h/2到-h/2按圆柱轴向分段数均匀分布,每个高度环的半径固定为r,x/z计算逻辑和半球赤道环保持一致
  • 生成下半球顶点:以(0, -h/2, 0)为球心,纬度取值范围为π/2~π,其余计算逻辑和上半球完全一致
  • 计算三角面索引:分别为三个部分拼接三角索引,保证所有面的环绕顺序统一,避免背面剔除出现异常
  • 补充附属属性:法线可直接通过顶点相对于对应球心/圆柱中心的归一化向量快速计算,也可根据需求生成UV、切线等属性

核心代码示例(C# 逻辑通用)

Mesh GenerateCapsuleMesh(float radius, float height, int radialSegments = 16, int hemiSegments = 8, int cylinderSegments = 8)
{
    Mesh mesh = new Mesh();
    List<Vector3> vertices = new List<Vector3>();
    List<int> triangles = new List<int>();

    // 生成上半球顶点
    for (int lat = 0; lat <= hemiSegments; lat++)
    {
        float latAngle = Mathf.PI * 0.5f * lat / hemiSegments;
        float sinLat = Mathf.Sin(latAngle);
        float cosLat = Mathf.Cos(latAngle);
        for (int lon = 0; lon <= radialSegments; lon++)
        {
            float lonAngle = 2 * Mathf.PI * lon / radialSegments;
            float sinLon = Mathf.Sin(lonAngle);
            float cosLon = Mathf.Cos(lonAngle);
            vertices.Add(new Vector3(radius * cosLat * cosLon, height/2 + radius * sinLat, radius * cosLat * sinLon));
        }
    }

    // 生成中间圆柱体顶点
    int cylinderVertStart = vertices.Count;
    for (int hSeg = 1; hSeg < cylinderSegments; hSeg++)
    {
        float y = height/2 - (float)hSeg / cylinderSegments * height;
        for (int lon = 0; lon <= radialSegments; lon++)
        {
            float lonAngle = 2 * Mathf.PI * lon / radialSegments;
            vertices.Add(new Vector3(radius * Mathf.Cos(lonAngle), y, radius * Mathf.Sin(lonAngle)));
        }
    }

    // 生成下半球顶点
    for (int lat = 1; lat <= hemiSegments; lat++)
    {
        float latAngle = Mathf.PI * 0.5f + Mathf.PI * 0.5f * lat / hemiSegments;
        float sinLat = Mathf.Sin(latAngle);
        float cosLat = Mathf.Cos(latAngle);
        for (int lon = 0; lon <= radialSegments; lon++)
        {
            float lonAngle = 2 * Mathf.PI * lon / radialSegments;
            float sinLon = Mathf.Sin(lonAngle);
            float cosLon = Mathf.Cos(lonAngle);
            vertices.Add(new Vector3(radius * cosLat * cosLon, -height/2 + radius * sinLat, radius * cosLat * sinLon));
        }
    }

    // 三角面索引计算:相邻两个环的每4个连续顶点拼成2个三角面,按分段逐个拼接即可
    int vertsPerLoop = radialSegments + 1;
    // 上半球索引
    for (int lat = 0; lat < hemiSegments; lat++)
    {
        for (int lon = 0; lon < radialSegments; lon++)
        {
            int cur = lat * vertsPerLoop + lon;
            int next = cur + vertsPerLoop;
            triangles.Add(cur);
            triangles.Add(next);
            triangles.Add(cur + 1);
            triangles.Add(cur + 1);
            triangles.Add(next);
            triangles.Add(next + 1);
        }
    }
    // 圆柱、下半球索引逻辑和上半球一致,可复用相同逻辑
    // ... 省略剩余索引拼接代码

    mesh.vertices = vertices.ToArray();
    mesh.triangles = triangles.ToArray();
    mesh.RecalculateNormals();
    mesh.RecalculateBounds();
    return mesh;
}

注意事项

  • 拼接三个部分时必须保证衔接处顶点坐标完全一致,否则会出现可见接缝
  • Runtime生成时建议对相同参数的网格做缓存复用,避免频繁生成导致GC
  • 要动态修改顶点属性时,直接获取Mesh.vertices数组修改后重新赋值给网格,调用RecalculateBounds、RecalculateNormals即可生效
  • 性能敏感场景可以降低分段数减少顶点数,平衡性能和显示效果

内容的提问来源于stack exchange,提问作者user15944701

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 01:45:02