- Home /
Loading Textures during runtime and applying to Raw Images
Hi, for my mobile game I wanna give the user the option to choose from different camera views. Therefore he can make screenshot and they are later displayed in the menue (as child of a scroll rect, s. picture). The screenshots are saved in Application.persistentDataPath as .png. So far so good. Saving the screenshot as .png works fine. Only when I try to load them during runtime I run into some issues.
In the script attached to an empty Game Object in the scene with the empty Raw Images I am trying now to assign the textures to each Raw Image. The Array ImageHolder corresponds to each GameObject holding the Raw Image component.
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using UnityEngine.UI;
using System;
public class test : MonoBehaviour
{
Texture2D thisTexture;
byte[] bytes;
string fileName;
public GameObject[] ImageHolder = new GameObject[5];
void Start()
{
thisTexture = new Texture2D(100, 100);
string[] ImageNames = { "Image1", "Image2", "Image3", "Image4", "Image5" };
for (int i = 0; i < ImageNames.Length; i++)
{
fileName = ImageNames[i];
bytes = File.ReadAllBytes(Path.Combine(Application.persistentDataPath, fileName + ".png"));
thisTexture.LoadImage(bytes);
thisTexture.name = fileName;
ImageHolder[i].GetComponent<RawImage>().texture = thisTexture;
}
}
}
I simply can't understand why I get this instead of this
For some reason the last texture from Image5 is written in all Raw Images. Why???
Answer by LK84 · Aug 05, 2016 at 01:51 PM
Ok, figured it out myself. I just had to create a new instance of Texture2d within the for loop, not before:
public class test : MonoBehaviour
{
Texture2D thisTexture;
byte[] bytes;
string fileName;
public GameObject[] ImageHolder = new GameObject[5];
void Start()
{
string[] ImageNames = { "Image1", "Image2", "Image3", "Image4", "Image5" };
for (int i = 0; i < ImageNames.Length; i++)
{
thisTexture = new Texture2D(100, 100); //NOW INSIDE THE FOR LOOP
fileName = ImageNames[i];
bytes = File.ReadAllBytes(Path.Combine(Application.persistentDataPath, fileName + ".png"));
thisTexture.LoadImage(bytes);
thisTexture.name = fileName;
ImageHolder[i].GetComponent<RawImage>().texture = thisTexture;
}
}
}
To be honest, I can't fully comprehend why that is the solution. So ImageHolder[i].GetComponent<RawImage>().texture=thisTexture;
apparently sets thisTexture
as a reference to ImageHolder[i].GetComponent<RawImage>().texture
.
But isn't that in contrast to the follwing simple example:
public class rbReference : MonoBehaviour {
float bodyMass;
void Start()
{
bodyMass = 5.0f;
GetComponent<Rigidbody>().mass = bodyMass;
bodyMass = 10.0f;
}
}
Here the Rigidbody mass remains 5 (as I expected) and not 10 --> bodyMass
is NOT a reference to the RigidBody Component Mass. I'm really confused now and to me it seems kind of arbitrary when Unity sets references and when not. Or am I missing something completly here?
When objects are instantiated(created) and they are reference types then when you create a Texture2D object and assign it the object is referencing a pointer in memory. If you have an array or collection of this type of object and you use the same one, stuff it into that collection/array, you're stuffing the reference to the object. So when you created the outer object and you updated the properties to use a different image it was updating all of them since all the items in the collection point to the exact same object. When you're using the new keyword you're allocating new memory and new references to this object so when you change the properties they are unique, but wasn't unique when you used the same object over and over in the loop.
Example of the outer Texture2D instantiation:
thisTexture = new Texture2D(100, 100); // made up address A0000000
Each time you added to your collection:
ImageHolder[i].GetComponent<RawImage>().texture = thisTexture;
thisTexture was just adding a pointer to the object in slot A0000000(again made up address). So regardless of what index you where assocating with using I$$anonymous$$ageHolder the pointer pointed to the same reference or object in memory.
When you added the ability to instantiate per texture since it has different images associated with it, it created a new memory location for each item as you looped through the for loop.
Answer by adityainfy · Oct 23, 2020 at 01:26 AM
public class test : MonoBehaviour {
Texture2D thisTexture;
byte[] bytes;
string fileName;
public GameObject[] ImageHolder = new GameObject[5];
void Start()
{
string[] ImageNames = { "Image1", "Image2", "Image3", "Image4", "Image5" };
for (int i = 0; i < ImageNames.Length; i++)
{
thisTexture = new Texture2D(100, 100); //NOW INSIDE THE FOR LOOP
fileName = ImageNames[i];
bytes = File.ReadAllBytes(Path.Combine(Application.persistentDataPath, fileName + ".png"));
thisTexture.LoadImage(bytes);
thisTexture.name = fileName;
ImageHolder[i].GetComponent<RawImage>().texture = thisTexture;
}
}
}
Your answer
Follow this Question
Related Questions
Unity 5.6.4 Canvas RawImage hides all objects 0 Answers
How do I shrink a cube with scripts? 1 Answer
Texture2D creating blurry textures 1 Answer
[SOLVED] Bad PKCS7 While encrypting a file 1 Answer
!texture.texture error 0 Answers