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

如何为实时生成楼梯的Unity脚本添加Mesh并优化代码?

Unity楼梯Mesh生成问题修复与优化

核心问题分析与修复

1. 修复Update()执行顺序

原代码中楼梯尺寸计算逻辑滞后于顶点和Mesh生成,导致每帧使用上一帧的旧数据。需将参数计算移至最前端:

void Update()
{
    // 先计算台阶高度、深度等核心参数
    float HOS = EndPoint.position.y - StartPoint.position.y;
    float LOS = EndPoint.position.z - StartPoint.position.z;
    float stepHeight = HOS / steps_in_flight;
    float stepDepth = LOS / steps_in_flight;
    
    CreateStair(stepHeight, stepDepth);
    CreateMesh();
    UpdateMesh();
}

2. 修复顶点数组与生成逻辑

原代码存在顶点数组尺寸错误、循环条件混乱、缺少踏板顶点等问题。重新设计顶点生成逻辑,每个台阶包含6个顶点(垂直 riser 的4个+水平 tread 的2个):

void CreateStair(float stepHeight, float stepDepth)
{
    // 每个台阶6个顶点,总顶点数为台阶数×6
    vertices = new Vector3[steps_in_flight * 6];
    float halfWidth = width / 2f;
    float xLeft = StartPoint.position.x + halfWidth;
    float xRight = StartPoint.position.x - halfWidth;
    
    for (int s = 0; s < steps_in_flight; s++)
    {
        int baseIndex = s * 6;
        float currentY = StartPoint.position.y + s * stepHeight;
        float nextY = currentY + stepHeight;
        float currentZ = StartPoint.position.z + s * stepDepth;
        float nextZ = currentZ + stepDepth;
        
        // 垂直面(riser)顶点
        vertices[baseIndex] = new Vector3(xLeft, currentY, currentZ);
        vertices[baseIndex + 1] = new Vector3(xRight, currentY, currentZ);
        vertices[baseIndex + 2] = new Vector3(xLeft, nextY, currentZ);
        vertices[baseIndex + 3] = new Vector3(xRight, nextY, currentZ);
        
        // 水平面(tread)顶点
        vertices[baseIndex + 4] = new Vector3(xLeft, nextY, nextZ);
        vertices[baseIndex + 5] = new Vector3(xRight, nextY, nextZ);
    }
}

3. 修复三角面生成逻辑

原ChatGPT生成的三角面索引完全无效,需根据顶点顺序生成符合Unity顺时针法线规则的三角面:

void CreateMesh()
{
    // 每个台阶包含4个三角面(riser2个+tread2个),每个三角面3个索引
    triangles = new int[steps_in_flight * 12];
    int triIndex = 0;
    
    for (int s = 0; s < steps_in_flight; s++)
    {
        int baseVert = s * 6;
        
        // 绘制垂直riser面
        triangles[triIndex++] = baseVert;
        triangles[triIndex++] = baseVert + 1;
        triangles[triIndex++] = baseVert + 2;
        
        triangles[triIndex++] = baseVert + 1;
        triangles[triIndex++] = baseVert + 3;
        triangles[triIndex++] = baseVert + 2;
        
        // 绘制水平tread面
        triangles[triIndex++] = baseVert + 2;
        triangles[triIndex++] = baseVert + 3;
        triangles[triIndex++] = baseVert + 4;
        
        triangles[triIndex++] = baseVert + 3;
        triangles[triIndex++] = baseVert + 5;
        triangles[triIndex++] = baseVert + 4;
    }
}

4. 性能优化:避免每帧重建Mesh

原代码每帧强制重建Mesh,性能损耗极大。改为仅在参数或端点位置变化时才重新生成:

Vector3 lastStartPos;
Vector3 lastEndPos;
int lastSteps;
float lastWidth;

void Start()
{
    mesh = new Mesh();
    mesh.name = "StairMesh";
    GetComponent<MeshFilter>().mesh = mesh;
    
    lastStartPos = StartPoint.position;
    lastEndPos = EndPoint.position;
    lastSteps = steps_in_flight;
    lastWidth = width;
    
    GenerateStair();
}

void Update()
{
    // 仅在参数变化时触发重建
    if (StartPoint.position != lastStartPos || EndPoint.position != lastEndPos 
        || steps_in_flight != lastSteps || width != lastWidth)
    {
        GenerateStair();
        lastStartPos = StartPoint.position;
        lastEndPos = EndPoint.position;
        lastSteps = steps_in_flight;
        lastWidth = width;
    }
}

void GenerateStair()
{
    float HOS = EndPoint.position.y - StartPoint.position.y;
    float LOS = EndPoint.position.z - StartPoint.position.z;
    float stepHeight = HOS / steps_in_flight;
    float stepDepth = LOS / steps_in_flight;
    
    CreateStair(stepHeight, stepDepth);
    CreateMesh();
    UpdateMesh();
}

数学优化建议

1. 共享顶点减少冗余计算

将楼梯视为网格结构,相邻台阶共享顶点,总顶点数从6×台阶数降至2×(台阶数+1)²,大幅减少内存占用和计算量:

void CreateOptimizedStair(float stepHeight, float stepDepth)
{
    int numY = steps_in_flight + 1;
    int numZ = steps_in_flight + 1;
    vertices = new Vector3[2 * numY * numZ];
    
    int index = 0;
    for (int y = 0; y < numY; y++)
    {
        float currentY = StartPoint.position.y + y * stepHeight;
        for (int z = 0; z < numZ; z++)
        {
            float currentZ = StartPoint.position.z + z * stepDepth;
            vertices[index++] = new Vector3(StartPoint.position.x + width/2, currentY, currentZ);
            vertices[index++] = new Vector3(StartPoint.position.x - width/2, currentY, currentZ);
        }
    }
}

2. 向量运算简化坐标计算

使用Unity内置Vector3运算替代单独计算x/y/z,代码更简洁高效:

Vector3 stepDir = (EndPoint.position - StartPoint.position) / steps_in_flight;
Vector3 currentPos = StartPoint.position;
for (int s = 0; s < steps_in_flight; s++)
{
    Vector3 nextPos = currentPos + stepDir;
    // 基于currentPos和nextPos生成顶点
    currentPos = nextPos;
}

完整修正后的代码

Mesh mesh;
public Vector3[] vertices;
int[] triangles;

public Transform StartPoint;
public Transform EndPoint;
public int steps_in_flight = 10;
public float width = 10f;

Vector3 lastStartPos;
Vector3 lastEndPos;
int lastSteps;
float lastWidth;

void Start()
{
    mesh = new Mesh();
    mesh.name = "StairMesh";
    GetComponent<MeshFilter>().mesh = mesh;
    
    lastStartPos = StartPoint.position;
    lastEndPos = EndPoint.position;
    lastSteps = steps_in_flight;
    lastWidth = width;
    
    GenerateStair();
}

void Update()
{
    if (StartPoint.position != lastStartPos || EndPoint.position != lastEndPos 
        || steps_in_flight != lastSteps || width != lastWidth)
    {
        GenerateStair();
        lastStartPos = StartPoint.position;
        lastEndPos = EndPoint.position;
        lastSteps = steps_in_flight;
        lastWidth = width;
    }
}

void GenerateStair()
{
    float HOS = EndPoint.position.y - StartPoint.position.y;
    float LOS = EndPoint.position.z - StartPoint.position.z;
    float stepHeight = HOS / steps_in_flight;
    float stepDepth = LOS / steps_in_flight;
    
    CreateStair(stepHeight, stepDepth);
    CreateMesh();
    UpdateMesh();
}

void CreateStair(float stepHeight, float stepDepth)
{
    vertices = new Vector3[steps_in_flight * 6];
    float halfWidth = width / 2f;
    float xLeft = StartPoint.position.x + halfWidth;
    float xRight = StartPoint.position.x - halfWidth;
    
    for (int s = 0; s < steps_in_flight; s++)
    {
        int baseIndex = s * 6;
        float currentY = StartPoint.position.y + s * stepHeight;
        float nextY = currentY + stepHeight;
        float currentZ = StartPoint.position.z + s * stepDepth;
        float nextZ = currentZ + stepDepth;
        
        // 垂直面顶点
        vertices[baseIndex] = new Vector3(xLeft, currentY, currentZ);
        vertices[baseIndex + 1] = new Vector3(xRight, currentY, currentZ);
        vertices[baseIndex + 2] = new Vector3(xLeft, nextY, currentZ);
        vertices[baseIndex + 3] = new Vector3(xRight, nextY, currentZ);
        
        // 水平面顶点
        vertices[baseIndex + 4] = new Vector3(xLeft, nextY, nextZ);
        vertices[baseIndex + 5] = new Vector3(xRight, nextY, nextZ);
    }
}

void CreateMesh()
{
    triangles = new int[steps_in_flight * 12];
    int triIndex = 0;
    
    for (int s = 0; s < steps_in_flight; s++)
    {
        int baseVert = s * 6;
        
        // 绘制垂直面
        triangles[triIndex++] = baseVert;
        triangles[triIndex++] = baseVert + 1;
        triangles[triIndex++] = baseVert + 2;
        
        triangles[triIndex++] = baseVert + 1;
        triangles[triIndex++] = baseVert + 3;
        triangles[triIndex++] = baseVert + 2;
        
        // 绘制水平面
        triangles[triIndex++] = baseVert + 2;
        triangles[triIndex++] = baseVert + 3;
        triangles[triIndex++] = baseVert + 4;
        
        triangles[triIndex++] = baseVert + 3;
        triangles[triIndex++] = baseVert + 5;
        triangles[triIndex++] = baseVert + 4;
    }
}

void UpdateMesh()
{
    mesh.Clear();
    mesh.vertices = vertices;
    mesh.triangles = triangles;
    mesh.RecalculateBounds();
    mesh.RecalculateNormals();
}

void OnDrawGizmos()
{
    if (vertices == null) return;
    foreach (var vert in vertices)
    {
        Gizmos.DrawSphere(vert, 0.1f);
    }
}

内容的提问来源于stack exchange,提问作者the one and only

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 19:24:53