Dalukar
Dalukar

Reputation: 21

Merge textures at Runtime

Is there any way to "bake" one texture to another, except for using SetPixels()? Now i'm trying to use something like that, but it too slow:

public static Texture2D CombineTextures(Texture2D aBaseTexture, Texture2D aToCopyTexture, int x, int y)
{
    int aWidth = aBaseTexture.width;
    int aHeight = aBaseTexture.height;

    int bWidth = aToCopyTexture.width;
    int bHeight = aToCopyTexture.height;

    Texture2D aReturnTexture = new Texture2D(aWidth, aHeight, TextureFormat.RGBA32, false);

    Color[] aBaseTexturePixels = aBaseTexture.GetPixels();
    Color[] aCopyTexturePixels = aToCopyTexture.GetPixels();

    int aPixelLength = aBaseTexturePixels.Length;
    for(int y1 = y, y2 = 0; y1 < aHeight && y2 < bHeight ; y1++, y2++)
    {
        for(int x1 = x, x2 = 0 ; x1 < aWidth && x2 < bWidth; x1++, x2++)
        {
            aBaseTexturePixels[x1 + y1*aWidth] = Color.Lerp(aBaseTexturePixels[x1 + y1*aWidth], aCopyTexturePixels[x2 + y2*bWidth], aCopyTexturePixels[x2 + y2*bWidth].a);
        }
    }

    aReturnTexture.SetPixels(aBaseTexturePixels);
    aReturnTexture.Apply(false);

    return aReturnTexture;
}

The problem is, that i need to display a lot of sprites on 2d surface (blood, enemy corpses, etc.), and just instantiating every sprite will greatly reduce fps.

Upvotes: 2

Views: 1414

Answers (1)

Greg Lukosek
Greg Lukosek

Reputation: 1792

If you are concerned about fps drop when instantiating prefabs you should definitely build a Object pooling system. So you will have a system that:

  1. Instantiating all objects in the pool and keep it far away from the main camera
  2. Once you need the object you will "borrow" it from the pool
  3. Once object is not needed anymore you will return it back to the object pool (for example when sprite is out the camera view

Baking it all to one texture isn't the best practice. You will need huge amounts of RAM for this. Consider steps above, its very common practice

Good example here:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;

public class BackgroundPool : MonoBehaviour 
{
    public static BackgroundPool instance;
    public List<BackgroundSection> sectionsLibrary = new List<BackgroundSection>();
    public int poolSize = 4;
    public List<BackgroundSection> pool = new List<BackgroundSection>();


    void Awake()
    {
        instance = this;

        DateTime startGenTime = DateTime.Now;

        //generateSectionsPool
        for (int i=0; i<sectionsLibrary.Count; i++)
        {
            for (int j=0; j<poolSize; j++)
            {
                if (j == 0) 
                {
                    sectionsLibrary[i].positionInPool = sectionsLibrary[i].transform.position;
                    pool.Add(sectionsLibrary[i]);
                }
                else
                {
                    BackgroundSection section = (BackgroundSection)Instantiate(sectionsLibrary[i]);

                    section.transform.parent = this.transform;
                    section.transform.position = new Vector3((-(ExtensionMethods.GetBounds(sectionsLibrary[i].gameObject).extents.x * 2) * j) + sectionsLibrary[i].transform.position.x,
                                                         sectionsLibrary[i].transform.position.y);
                    section.transform.localEulerAngles = Vector3.zero;

                    section.gameObject.name = sectionsLibrary[i].gameObject.name + ":" + j.ToString();
                    section.positionInPool = section.transform.position;
                    pool.Add(section);  
                }
           }
        }
        Debug.Log("Background Pool generated in: " + (DateTime.Now - startGenTime).TotalSeconds.ToString() + " s");
    }


    public BackgroundSection GetPiece(Scenery scenery, SceneryLayer _layer)
    {
        List<BackgroundSection> allScenery = new List<BackgroundSection>();
        foreach (BackgroundSection section in pool) { if (section.scenery == scenery) allScenery.Add(section); }

        List<BackgroundSection> matchingPieces = new List<BackgroundSection>();
        foreach (BackgroundSection section in allScenery)  { if (section.sceneryLayer == _layer) matchingPieces.Add(section); }

        if (matchingPieces.Count > 0) 
        {
            BackgroundSection pickedSection = matchingPieces[UnityEngine.Random.Range(0,matchingPieces.Count-1)];
            pool.Remove(pickedSection);
            return pickedSection;
        }
        else
        {
            Debug.LogError("Cann't get background piece matching criteria, scenery: " + scenery + ", layer" + _layer);
            return null;
        }
    }


    public void ReturnPiece(BackgroundSection section)
    {
        pool.Add(section);
        section.transform.parent = this.transform;
        section.transform.position = section.positionInPool;
    }
}

Upvotes: 0

Related Questions