Search Unity

Sprite animation using mesh.uv. Batches = 999, DrawCall = 1

Discussion in '2D' started by shranet, Dec 8, 2013.

  1. shranet

    shranet

    Joined:
    Dec 5, 2013
    Posts:
    1
    Hi. My english not very good.
    I recently started learning unity3d. I needed to animated sprite. Searched the internet and wrote this code. I think this code help for beginners.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. [ExecuteInEditMode]
    6. [AddComponentMenu("Sprites/Animation sprite")]
    7. [RequireComponent(typeof(MeshFilter))]
    8. [RequireComponent(typeof(MeshRenderer))]
    9.  
    10. public class AnimationSprite : MonoBehaviour
    11. {
    12.     private MeshFilter meshFilter;
    13.     private MeshRenderer meshRenderer;
    14.  
    15.     private string materialName;
    16.     private Vector2 size = Vector2.one;
    17.     private Vector2 center = Vector2.one / 2;
    18.     private Vector2 tileSizeInPixel;
    19.     private Rect tileRect;
    20.  
    21.     private Vector2 materialTextureSize;
    22.  
    23.     //static variables
    24.     private Vector2 textureScale;
    25.     private int totalTiles;
    26.     private int fps = 30;
    27.     private Vector2[] textureCoods;
    28.  
    29.     private static Dictionary<string, Material> materialList = new Dictionary<string, Material>();
    30.  
    31.     public static AnimationSprite Create(GameObject gameObject, string materialName)
    32.     {
    33.         return Create(gameObject, materialName, Vector2.one);
    34.     }
    35.  
    36.     public static AnimationSprite Create(GameObject gameObject, string materialName, Vector2 size)
    37.     {
    38.         return Create(gameObject, materialName, size, Rect.MinMaxRect(0, 0, 0, 0), Vector2.zero, 0);
    39.     }
    40.  
    41.     public static AnimationSprite Create(GameObject gameObject, string materialName,
    42.         Vector2 size, Rect tileRect, Vector2 tileSizeInPixel, int fps)
    43.     {
    44.         AnimationSprite animSprite = gameObject.AddComponent(typeof(AnimationSprite)) as AnimationSprite;
    45.         animSprite.size = size;
    46.         animSprite.materialName = materialName;
    47.         animSprite.tileRect = tileRect;
    48.         animSprite.tileSizeInPixel = tileSizeInPixel;
    49.         animSprite.fps = fps;
    50.  
    51.         return animSprite;
    52.     }
    53.  
    54.     void Awake()
    55.     {
    56.         meshFilter = base.GetComponent(typeof(MeshFilter)) as MeshFilter;
    57.         meshRenderer = base.GetComponent(typeof(MeshRenderer)) as MeshRenderer;
    58.         meshRenderer.castShadows = false;
    59.         meshRenderer.receiveShadows = false;
    60.     }
    61.  
    62.     // Use this for initialization
    63.     void Start()
    64.     {
    65.         //Load material
    66.         //meshRenderer.sharedMaterial = Resources.Load(materialName, typeof(Material)) as Material;
    67.         meshRenderer.sharedMaterial = GetMaterial(materialName);
    68.  
    69.         //Get texture size
    70.         Texture2D texture2D = meshRenderer.sharedMaterial.GetTexture("_MainTex") as Texture2D;
    71.         materialTextureSize = new Vector2(texture2D.width, texture2D.height);
    72.  
    73.         //Create mesh
    74.         meshFilter.mesh = CreateMesh(size, center, Rect.MinMaxRect(0, 0, 1, 1));
    75.         textureCoods = (Vector2[])meshFilter.mesh.uv;
    76.  
    77.         totalTiles = (int)(tileRect.width  * tileRect.height);
    78.  
    79.         if (tileSizeInPixel.x != 0  tileSizeInPixel.y != 0  totalTiles > 1)
    80.         {
    81.             //Calculate static variables
    82.             textureScale = new Vector2(tileSizeInPixel.x / materialTextureSize.x, tileSizeInPixel.y / materialTextureSize.y);
    83.             //meshRenderer.sharedMaterial.SetTextureScale("_MainTex", textureScale);
    84.         }
    85.     }
    86.  
    87.     // Update is called once per frame
    88.     void Update()
    89.     {
    90.         if (tileSizeInPixel.x != 0  tileSizeInPixel.y != 0  totalTiles > 1)
    91.             SetSpriteAnimation();
    92.     }
    93.  
    94.     void SetSpriteAnimation()
    95.     {
    96.         int index = (int)(Time.time * fps);
    97.  
    98.         index = index % totalTiles;
    99.  
    100.         int uIndex = (int)(index % tileRect.width);
    101.         int vIndex = (int)(index / tileRect.width);
    102.  
    103.         float offsetX = (uIndex + tileRect.xMin) * textureScale.x;
    104.         float offsetY = (vIndex + tileRect.yMin) * textureScale.y;
    105.         /*
    106.         Vector2 offset = new Vector2(offsetX, offsetY);
    107.         renderer.material.SetTextureOffset("_MainTex", offset);*/
    108.  
    109.         /*
    110.         Rect textureCoords = new Rect(offsetX, offsetY, textureScale.x, textureScale.y);
    111.         var uv = new[]
    112.         {
    113.             new Vector2(textureCoords.xMin, 1 - textureCoords.yMax),
    114.             new Vector2(textureCoords.xMin, 1 - textureCoords.yMin),
    115.             new Vector2(textureCoords.xMax, 1 - textureCoords.yMin),
    116.             new Vector2(textureCoords.xMax, 1 - textureCoords.yMax)
    117.         };
    118.         */
    119.  
    120.         textureCoods[0].x = offsetX;
    121.         textureCoods[0].y = 1 - (offsetY + textureScale.y);
    122.  
    123.         textureCoods[1].x = offsetX;
    124.         textureCoods[1].y = 1 - offsetY;
    125.  
    126.         textureCoods[2].x = offsetX + textureScale.x;
    127.         textureCoods[2].y = 1 - offsetY;
    128.  
    129.         textureCoods[3].x = offsetX + textureScale.x;
    130.         textureCoods[3].y = 1 - (offsetY + textureScale.y);
    131.  
    132.         meshFilter.mesh.uv = textureCoods;
    133.     }
    134.  
    135.     private static Material GetMaterial(string materialName)
    136.     {
    137.         if (materialList.ContainsKey(materialName))
    138.             return materialList[materialName];
    139.  
    140.         return materialList[materialName] = Resources.Load(materialName, typeof(Material)) as Material;
    141.     }
    142.  
    143.     private static Mesh CreateMesh(Vector2 size, Vector2 center, Rect textureCoords)
    144.     {
    145.         var vertices = new[] {
    146.             new Vector3(0, 0, 0),
    147.             new Vector3(0, size.y, 0),
    148.             new Vector3(size.x, size.y, 0),
    149.             new Vector3(size.x, 0, 0)
    150.         };
    151.  
    152.         Vector3 shift = Vector2.Scale(center, size);
    153.         for (int i = 0; i < vertices.Length; i++)
    154.         {
    155.             vertices[i] -= shift;
    156.         }
    157.  
    158.         var uv = new[]
    159.         {
    160.             new Vector2(textureCoords.xMin, 1 - textureCoords.yMax),
    161.             new Vector2(textureCoords.xMin, 1 - textureCoords.yMin),
    162.             new Vector2(textureCoords.xMax, 1 - textureCoords.yMin),
    163.             new Vector2(textureCoords.xMax, 1 - textureCoords.yMax)
    164.         };
    165.  
    166.         var triangles = new[]
    167.         {
    168.             0, 1, 2,
    169.             0, 2, 3
    170.         };
    171.  
    172.         return new Mesh { vertices = vertices, uv = uv, triangles = triangles };
    173.     }
    174. }
    175.  
    Use. In another script
    Code (csharp):
    1. void Start()
    2.     {
    3.         GameObject rootObject = new GameObject() { name = "Root anim" };
    4.  
    5.         for (int i = 0; i < 500; i++)
    6.         {
    7.             GameObject gameObject = new GameObject() { name = "AnimationObject1-" + i.ToString() };
    8.             gameObject.transform.Translate(Random.Range(-50, 50), Random.Range(100, -100), 0);
    9.             gameObject.transform.parent = rootObject.transform;
    10.             AnimationSprite.Create(gameObject, "SmileMaterial", Vector2.one * 2, new Rect(0, 0, 4, 4), new Vector2(128, 128), Random.Range(1, 50));
    11.  
    12.             GameObject gameObject2 = new GameObject() { name = "AnimationObject2-" + i.ToString() };
    13.             AnimationSprite.Create(gameObject2, "SmileMaterial", Vector2.one, new Rect(0, 4, 4, 2), new Vector2(150, 150), 10);
    14.             gameObject2.transform.Translate(Random.Range(-50, 50), Random.Range(100, -100), 0);
    15.             gameObject2.transform.parent = rootObject.transform;
    16.         }
    17.  
    18.         MeshRenderer rootMeshRenderer = (rootObject.AddComponent(typeof(MeshRenderer)) as MeshRenderer);
    19.         rootMeshRenderer.castShadows = false;
    20.         rootMeshRenderer.receiveShadows = false;
    21. }
    Results. On PC
    Code (csharp):
    1. FPS ~= 80
    2. Objects = 1000
    3. DrawCall = 2 (1 for GUI)
    4. Batches = 999
    $result.png

    On Galaxy S
    Code (csharp):
    1. FPS ~= 40
    2. Objects = 1000
    3. DrawCall = 2 (1 for GUI)