Search code examples
unity-game-enginetextures

Loading a PNG image as a texture at runtime in Unity3d


I'm using a series of PNG images as sprites to create animations on a plane for an augmented reality application in Unity. The PNG images are loaded as textures, and the textures are applied to a plane to create an animation sequence that tracks with an augmented reality target.

Here is the script that is attached to the plane and controls the animation sequence.

File PNGSequence.js

#pragma strict
var tecture : Texture[];

var changeInterval : float = 0.06;
var isRunning = false;
var isLooping = false;

function Start () {
    var isRunning = true;
}

function Update () {
    if( isRunning == true) {
        Animation ();
    }
}

function Animation () {
    var index : int = Time.time/changeInterval;
    index = index % tecture.Length;
    renderer.material.mainTexture = tecture[index];
    if ( index == tecture.Length-1){
        if( isLooping == false){
            isRunning = false;
        }
           renderer.material.mainTexture = tecture[0];
    }
}

Textures are assigned by drag-and-drop of PNG files in the editor and everything works fine if I limit the PNG count. As my texture count increases, however, I'm getting out of memory errors on Android.

I would like to load the PNG files as textures at run time to limit the number memory, but I'm having trouble getting the code working.

I've tried LoadImage.

var imageTextAsset : TextAsset = Resources.Load("test.png");
var tex = new Texture2D (4, 4);
tex.LoadImage(imageTextAsset.bytes);
renderer.material.mainTexture = tex;

I've also tried loading the image directly as a texture (since this seems to work with the editor).

renderer.material.mainTexture = Resources.LoadAssetAtPath"Assets/Images/test.png",Texture);

No luck with either. Any suggestions on how to accomplish this?

EDITED

I was able to get this working thanks to the link provided by Xerosigma. I had an issue with paths (and I suspect with the Texture requirement on load).

Outside of loading the PNG textures, I also discovered that Unity does not do memory management on textures. To recover memory, textures need to be manually unloaded after use.

Textures are all placed in a "Resources" folder. The resources folder can be placed anywhere in the Assets hierarchy - I created several individual folders for each of my PNG sequences to organize them, then added a Resources folder within each to hold the actual PNGs.

Textures are assigned through the editor by specifying a texture count (ie. 100), a base name ("texture_" for instance), and zero padding.

File PNGSequenceRunTime.js

#pragma strict

var imageCount : int = 0;
var imageNameBase : String = "";
var imageNameZeroPadding : int = 0;

var changeInterval : float = 0.06;
var isRunning = false;
var isLooping = false;

private var texture : Texture = null;

function PlayRocket () {
    isRunning = true;
}

function Start () {
    var isRunning = false;
    var fileName : String = imageNameBase + ZeroPad(0,imageNameZeroPadding);
    texture = Resources.Load(fileName);
}

function Update () {
    if( isRunning == true) {
        PNGAnimation ();
    }
}

function PNGAnimation () {
    var index : int = Time.time/changeInterval;
    index = index % imageCount;
    var fileName : String = imageNameBase + ZeroPad(index,imageNameZeroPadding);
    Resources.UnloadAsset(texture);
    texture = Resources.Load(fileName);
    renderer.material.mainTexture = texture;


    if ( index == imageCount-1){
        Debug.Log("End of Animation");
        Debug.LogWarning("End of Animation");
        if( isLooping == false){
            isRunning = false;
        }
        fileName = imageNameBase + ZeroPad(0,imageNameZeroPadding);
        Resources.UnloadAsset(texture);
        texture = Resources.Load(fileName);
        renderer.material.mainTexture = texture;
    }
}

function ZeroPad(number : int, size : int) {
    var numberString : String = number.ToString();
    while (numberString.Length < size) numberString = "0" + numberString;
    return numberString;
}

Solution

  • In C#:

    // Load all textures into an array
    Object[] textures = Resources.LoadAll("Textures", typeof(Texture2D));
    
    // Load a single texture
    Texture2D texture = Resources.Load("Texture") as Texture2D;
    
    renderer.material.mainTexture = texture;
    

    Hope it helps. You should be able to convert it into JS no problem. Just look at the Unity documentation.

    http://docs.unity3d.com/Documentation/ScriptReference/Resources.html