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

Unity中如何实现Mesh旗帜飘动动画?技术求助

旗帜飘动动画实现问题求助

我尝试实现旗帜飘动的动画,目标是通过正弦函数移动存储顶点的二维数组VerticeArray[,]的每一列,让Mesh呈现飘动效果。目前已创建初始Mesh:

初始Mesh

相关说明:

  • GenerateVertices():将二维顶点数组转换为一维数组
  • mg.nRows:Mesh的行数(当前为5)
  • mg.nColumns:Mesh的列数(当前为3)

以下是我的代码,始终无法得到正确效果,恳请帮忙修正:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class PlaneMeshDeformComponent : MonoBehaviour
{
    [SerializeField] public float amplitude;

    [SerializeField] private bool activate;

    private Mesh m;
    private Vector3[] verticesCopy;

    private Vector3[,] verticeArray;

    private PlaneMeshGeneratorComponent mg;

    private float step = 0;

    private float previousStep = 0;
    
    

    private void Start()
    {

        mg = GetComponent<PlaneMeshGeneratorComponent>();
        
        m = GetComponent<MeshFilter>().mesh;

        verticesCopy = m.vertices;

        for (int i = 0; i < verticesCopy.Length; ++i)
        {
           
            verticesCopy[i] += new Vector3(0, 0, amplitude * Mathf.Sin((float)(verticesCopy[i].x * (2*Math.PI/verticesCopy[^1].x))));
        }
        //4.
        m.vertices = verticesCopy;
        
        //5.
        m.RecalculateNormals();

        verticeArray = GenerateArray(m.vertices);

        /*for (int i = 0; i <= mg.nColumns; i++)
        {
            for (int k = 0; k <= mg.nRows; k++)
            {
                Debug.Log(verticeArray[k,i]);
            }
        }*/
    }

    private void Update()
    { 
        step += Time.deltaTime;
        for (int i = 0; i <= mg.nColumns; i++)
       {
           for (int k = 0; k <= mg.nRows; k++)
           {
               verticeArray[k, i] = new Vector3(verticeArray[k,i].x, verticeArray[k,i].y, verticeArray[k,i].z+amplitude*(Mathf.Sin(step)-Mathf.Sin(previousStep)));
               m.vertices = mg.GenerateVertices(verticeArray);
               Debug.Log($"step is {step}, previous is {previousStep}");
           }
       }
       previousStep = step;
    }

    private Vector3[,] GenerateArray(Vector3[] verticesList)
    {
        Vector3[,] vArray= new Vector3[mg.nRows+1, mg.nColumns+1];
        for (int i = 0; i <= mg.nRows; i++)
        {
            for (int k = 0; k <= mg.nColumns; k++)
            {
                vArray[i,k] = verticesList[i * (mg.nColumns+1) + k];
            }
        }

        return vArray;
    }
}

问题分析与修正代码

你的核心问题在于动画逻辑错误:顶点偏移是累加差值,导致顶点会持续向Z轴偏移,且每帧多次更新Mesh效率极低。以下是修正后的代码:

using System;
using UnityEngine;

public class PlaneMeshDeformComponent : MonoBehaviour
{
    [SerializeField] public float amplitude = 0.5f;
    [SerializeField] private bool activate;
    [SerializeField] private float waveSpeed = 2f; // 飘动速度
    [SerializeField] private float waveLength = 1f; // 波浪波长

    private Mesh m;
    private Vector3[] originalVertices; // 存储原始顶点作为基准
    private Vector3[,] verticeArray;
    private PlaneMeshGeneratorComponent mg;
    private float timeElapsed = 0;
    
    private void Start()
    {
        mg = GetComponent<PlaneMeshGeneratorComponent>();
        m = GetComponent<MeshFilter>().mesh;
        originalVertices = m.vertices; // 保存原始顶点,不修改基准值
        verticeArray = GenerateArray(originalVertices);
    }

    private void Update()
    {
        if (!activate) return;
        
        timeElapsed += Time.deltaTime;

        // 遍历每一列计算偏移
        for (int col = 0; col <= mg.nColumns; col++)
        {
            // 取当前列的X位置作为波浪相位基准
            float xPos = verticeArray[0, col].x;
            // 计算当前列的Z轴偏移:结合时间和X位置,模拟波浪传递
            float zOffset = amplitude * Mathf.Sin(timeElapsed * waveSpeed + xPos / waveLength);

            // 更新该列所有顶点的Z值
            for (int row = 0; row <= mg.nRows; row++)
            {
                int vertexIndex = row * (mg.nColumns + 1) + col;
                verticeArray[row, col] = new Vector3(
                    originalVertices[vertexIndex].x,
                    originalVertices[vertexIndex].y,
                    originalVertices[vertexIndex].z + zOffset
                );
            }
        }

        // 一次性更新Mesh并重新计算法线
        m.vertices = mg.GenerateVertices(verticeArray);
        m.RecalculateNormals();
    }

    private Vector3[,] GenerateArray(Vector3[] verticesList)
    {
        Vector3[,] vArray = new Vector3[mg.nRows + 1, mg.nColumns + 1];
        for (int i = 0; i <= mg.nRows; i++)
        {
            for (int k = 0; k <= mg.nColumns; k++)
            {
                vArray[i, k] = verticesList[i * (mg.nColumns + 1) + k];
            }
        }
        return vArray;
    }
}

关键修正点

  1. 保留原始顶点:用originalVertices存储初始位置,每次偏移都基于原始值计算,避免顶点位置失控。
  2. 修正动画逻辑:通过时间+X位置的正弦函数模拟波浪传递,符合旗帜飘动的物理效果。
  3. 优化性能:将Mesh更新移到循环外,避免每帧多次修改Mesh数据。
  4. 添加可调参数:新增waveSpeed和waveLength,方便调整飘动的速度和波浪疏密。
  5. 启用开关控制:利用activate变量控制动画启停,便于调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 06:31:11