- Home /
How do I load files at run-time without losing performance?
I am attempting to use a code that loads .jpgs from my 'resources' folder and displays them in succession to simulate a video. Unity Indie is all I can afford at the moment and I already have 6 minutes worth of live action video that I am attempting to fit into my project. I know this isn't the most effective way to do video but it mostly works for my needs. I am trying to run the video at 10 fps, it's made up of over 6,000 jpgs and it plays smoothly once loaded.
Here's the problem: The user walks into a trigger which instantiates a prefab with this script and the video plays. While the files are loading my game comes to a stand-still for approx. 10 seconds. How can I control that initial load to minimize impact on performance?
P.S. I use JavaScript, so this code is extra hard to understand.
// Original script by wbokunic - http://forum.unity3d.com/threads/52001-Movie-Player-for-Indie-Users
// Modified C# version by Ronan Tumelty
using UnityEngine;
using System.Collections;
using System.IO;
[RequireComponent(typeof(AudioSource))]
public class VideoPlayer : MonoBehaviour {
Object[] movie_stills;
int number_of_stills = 0;
public bool loop = false;
public bool playOnStart = false;
public int fps = 30;
public AudioClip sound;
public string resourceSubfolder = "";
private int stills = 0;
private bool play = false;
private bool loaded = false;
void Update () {
if (!resourceSubfolder.Equals("") && !loaded) {
StartCoroutine(ImportVideo());
}
if(fps > 0){
if(play == true){
StartCoroutine(Player());
}
} else {
Debug.LogError("'fps' must be set to a value greater than 0.");
}
}
IEnumerator Player(){
play = false;
if(loop){
Debug.Log("looped. stills: " + stills + ", length: " + movie_stills.Length);
if(stills >= movie_stills.Length) {
audio.Stop();
audio.clip = sound;
audio.Play();
stills = 0;
Debug.Log("restarting. stills: " + stills);
}
} else {
if(stills > movie_stills.Length) {
audio.Stop();
stills -= 1;
}
}
if (stills >= 0 && stills < movie_stills.Length) {
Texture2D MainTex = movie_stills[stills] as Texture2D;
renderer.material.SetTexture("_MainTex", MainTex);
stills += 1;
int fps_fixer = fps*3;
float wait_time = 1.0f/fps_fixer;
yield return new WaitForSeconds(wait_time);
if(!audio.clip){
if(sound){
audio.clip = sound;
audio.Play();
}
}
play = true;
}
}
public void Play() { play = true; }
public void Pause() { play = false; }
void Start ()
{
audio.loop = false;
number_of_stills -= 1;
}
IEnumerator ImportVideo() {
movie_stills = Resources.LoadAll(resourceSubfolder, typeof(Texture2D));
loaded = true;
if (playOnStart)
play = true;
yield return null;
}
public void UnloadFromMemory() {
play = false;
audio.Stop();
foreach (Object o in movie_stills) Destroy(o);
}
}
Answer by OP_toss · Sep 07, 2013 at 12:57 AM
Disclaimers:
Honestly this seems like a really bad way to do video, but if it suites your needs, have at it! I'd look into plugins and external tools well before resorting to something this manual though...
Also worth noting, anything in the Resources folder gets compiled into a special file that's built with the app. This allows for runtime loading, but at a cost of memory usage.
First off, I wouldn't do it during runtime, I'd have it serialized and loaded with the scene/game:
Create an empty gameobject
Create a new script with a public Texture2D[]
In the inspector, drag all the textures needed onto the array to add them
Drag the gameobject to the Prefabs folder to serialize it.
Anywhere you need to use the array, create a public var of the same type as your script. Drag the prefab to the var in the inspector.
Now you should have access to all those textures during runtime by reference to the prefab. You shouldn't need to load them dynamically via Resources. They should be serialized references and should be good to go.
Note: didn't have time to test this, but it should work, I do it for many other things.
If you need to do it during run-time, you can create a coroutine to load them "asyncronously", although nothing is actually async in Unity...
Something like:
protected IEnumerator LoadRoutine()
{
while (loadCount < loadAmount)
{
frames.Add( Resources.Load( images[loadCount++] ) );
yield return null;
}
}
Basically, every frame it will load one image and append it to the frames list, until they are done.
Now this assumes that the load is fast enough to not impact performance happening once per frame. You may even be able to do multiple per frame with a for loop in there.
Also a spritesheet would help since it reduces amount of textures needed, but if you really require 6000 1k textures, that won't work for you.
Hope this helps!
Are there any plugins or external tools that you would recommend? I must be looking for them in all the wrong places. And I thought plugins require Unity Pro?
Ah I suppose dlls and such platform-specific plugins are, yes. But there's still some ppl who have bound to have faced this issue and found a solution. Just check the assetstore and google, if you really don't find anything, then hopefully my suggestion works for you. Let me know!
Your answer
Follow this Question
Related Questions
I cannot apply a video 0 Answers
How do i delete my projects i have like 10 1 Answer
Select Mesh not showing anything 0 Answers
Problem with Unity 4.0.0f7 2 Answers
How to change Unity back from 2D to 3D 4 Answers