-->

分類

2016年9月7日 星期三

Unity 2d wave-like motion mesh

reference

this needs one script attached to an empty GameObject and one material with texture

result video




public class WaveMesh : MonoBehaviour {
    private Mesh m_Mesh;
    private float size = 0.5f;
    private int gridSize = 8;
    public float waveFrequency = 5.0f;
    public float sizeScale = 0.5f;
    // Use this for initialization
    void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
        int dotsPerRow = gridSize + 1;
        int halfGridSize = gridSize / 2;
        Vector3[] verts = m_Mesh.vertices;
        float time = Time.time;
        for (int i = 0; i < dotsPerRow; i++)
        {
            for (int j = 0; j < dotsPerRow; j++)
            {
                int xIndex = j - halfGridSize;
                int yIndex = halfGridSize - i;
                float xSign = Mathf.Sign(xIndex);
                float ySign = Mathf.Sign(yIndex);
                float xPosTarget = xIndex;
                float yPosTarget = yIndex;
                //if (xIndex != 0 && yIndex != 0)
                {
                    Vector2 wave = waveCoord(xIndex, yIndex, halfGridSize, time);
                    verts[i * dotsPerRow + j] = new Vector3(wave.x, wave.y, 0.0f);
                }           
            }
        }
        m_Mesh.vertices = verts;
    }

    private Vector2 waveCoord(float xIndex, float yIndex, float halfGridSize, float time)
    {
        Vector2 p = new Vector2(xIndex, yIndex);
        
        p = p * sizeScale;
        float len = p.magnitude;
        float sincValue = sinc(p.magnitude * 0.5f);
        float temp = Mathf.Cos(time * waveFrequency - len / sizeScale) * 0.5f * sizeScale * sincValue;
        Vector2 offset = new Vector2(Mathf.Sign(xIndex) * temp, Mathf.Sign(yIndex) * temp);
        return offset + p;
    }

    private float clampTimeToPeriod(float time, float period)
    {
        return time - Mathf.Floor(time / period);
    }

    private float sinc(float x)
    {
        if(Mathf.Abs(x) < 0.0001f)
        {
            return Mathf.Sin(x);
        }
        return Mathf.Sin(x) / x;
    }

    void Awake()
    {
        GameObject plane = new GameObject("CreatedWaveMesh");
        MeshFilter meshFilter = (MeshFilter)plane.AddComponent(typeof(MeshFilter));
        meshFilter.mesh = CreateMesh();
        m_Mesh = meshFilter.mesh;
        MeshRenderer renderer = plane.AddComponent(typeof(MeshRenderer)) as MeshRenderer;
        //Load your material here
        Material newMat = Resources.Load("Materials/WaveStandardMaterial", typeof(Material)) as Material;
        renderer.material = newMat;
        //plane.transform.localScale = new Vector3(desiredSize / gridSize, desiredSize / gridSize, -1);
        plane.transform.localScale = new Vector3(1, 1, -1);
        plane.transform.localPosition = new Vector3(0.64f, 0.38f, -3);
    }

    Mesh CreateMesh()
    {
        Mesh m = new Mesh();
        m.name = "ScriptedMesh";
        /*
        case for gridSize == 4, there are 4x4=16 grids, dotsPerRow is 4+1=5
        .....
        .....
        .....
        .....
        .....
        */
        int dotsPerRow = gridSize + 1;
        int halfGridSize = gridSize / 2;
        Vector3[] verts = new Vector3[dotsPerRow * dotsPerRow];
        for (int i = 0; i < dotsPerRow; i++)
        {
            for(int j = 0; j < dotsPerRow; j++)
            {
                verts[i * dotsPerRow + j] = new Vector3(j - halfGridSize, halfGridSize - i, 0.0f);
            }
        }
        m.vertices = verts;

        Vector2[] uvs = new Vector2[verts.Length];
        float dotsPerRowf = (float)dotsPerRow;
        for (int i = 0; i < dotsPerRow; i++)
        {
            for (int j = 0; j < dotsPerRow; j++)
            {
                uvs[i * dotsPerRow + j] = new Vector2((float)j / dotsPerRowf, 1.0f - (float)i / dotsPerRowf);
            }
        }
        m.uv = uvs;

        int numTris = gridSize * gridSize * 2;
        int[] tris = new int[numTris * 3];
        
        for(int i = 0; i < gridSize; i++)
        {
            for(int j = 0; j < gridSize; j++)
            {
                int startIndex = 6 * (i * gridSize + j);
                tris[startIndex] = i * dotsPerRow + j;
                tris[startIndex + 1] = (i + 1) * dotsPerRow + j;
                tris[startIndex + 2] = i * dotsPerRow + j + 1;
                tris[startIndex + 3] = (i + 1) * dotsPerRow + j;
                tris[startIndex + 4] = (i + 1) * dotsPerRow + j + 1;
                tris[startIndex + 5] = i * dotsPerRow + j + 1;
            }
        }
        m.triangles = tris;
        m.RecalculateNormals();

        return m;
    }
}