Loading a PNG image as a texture at runtime in Unity3d
Asked Answered
F

2

9

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;
}
Freckle answered 4/4, 2013 at 20:16 Comment(0)
B
12

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

Boschvark answered 4/4, 2013 at 21:57 Comment(2)
+1 That did the trick. I suspect I was having issues with paths and the Texture requirement I was using in load.Freckle
this requires for the file to be in Resources folder. I came from google search trying to load texture from anywhere I want.Buccal
I
2

I achieved the same thing by placing any sequence of .png images (with an alpha channel) in a folder Resources/Sequence1 inside the main Assets folder. The output is a seamless movie playing with transparency exactly according to the alpha channels of the images.

This code is applied to a plane which is assigned a default New Material with Transparent/Diffused shader. This shader supports PNG images with alpha as transparency. You just have to give the name of the folder which contains the images to the variable framespath.

#pragma strict

var framespath: String = "";
var vidframes: Object[];
var count: int;

function Start () {

    vidframes = Resources.LoadAll(framespath, Texture);
    Debug.Log(vidframes.Length);

    count = 0;
    renderer.material.mainTexture = vidframes[count];
}

function Update () {
    count++;
    renderer.material.mainTexture = vidframes[count];
    if (count == vidframes.Length-1)
    {
        count = 0;
    }
}
Ithaca answered 18/11, 2013 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.