Currently I am using the following piece of code to load Textures from image files.
Texture my_pic = (Texture) AssetDatabase.LoadAssetAtPath(path, typeof(Texture));
Unfortunately this method doesn't work if the target path isn't in the Asset/ folder. I was wondering how I would load an image, given some absolute path of the form
/Users/Alan/SomeFolder/SomePic.png
(note that I am currently writing a custom Unity editor plugin by extending EditorWindow if that matters)
AssetDatabase is an Editor-only class.
Furthermore, it can only read assets in the /Assets directory (you know, the ones that are known to the asset database).
If you want to read any file on the file system, you need to use the System.IO classes.
Here is some code that will open a unity file dialog, and load the selected texture into a material of the attached object.
string path = EditorUtility.OpenFilePanel("Load an image", "", "png");
if (string.IsNullOrEmpty(path)) {
return;
}
// Load the images bytes from file (this is a synchronous call!)
byte[] bytes = null;
try {
bytes = System.IO.File.ReadAllBytes(path);
} catch (System.Exception e) {
Debug.LogError(e.Message);
return;
}
// Load the bytes into a Unity Texture2D
Texture2D _tex = new Texture2D(2,2);
_tex.LoadImage(bytes);
// Apply this texture to the object
Renderer r = (target as Component).gameObject.GetComponent<Renderer>();
if (r != null) {
r.material.SetTexture("_MainTex", _tex);
}
The last part, just for demonstration, will work only on a script derived from Editor because it uses target to find the attached renderer. It's up to you to decide what to do with the texture in your EditorWindow script.
Also, remember to explicitly call DestroyImmediate on your texture when you no longer need it, as you may end up with a memory leak in your editor code.
You can use UnityWebRequestTexture
var www = UnityWebRequestTexture.GetTexture("file:///Users/Alan/SomeFolder/SomePic.png");
www.SendWebRequest();
while(!www.isDone)
continue;
var texture = DownloadHandlerTexture.GetContent(www);
Related
I am creating a Unity Editor script which takes a texture, slices it (this part works) and adds these sprites to a selected SpriteLibraryAsset:
foreach(var currentGroup in selectedDefinitionFile.Groups)
{
for (int i = 1; i <= currentGroup.Item2; i++) {
var rects = dataProvider.GetSpriteRects();
var targetName = String.Format("{0}-{1}", currentGroup.Item1, i);
var sprite = (Sprite)allSprites.Where(x => x.name == targetName).First();
spriteLibraryToPopulate.AddCategoryLabel(sprite, currentGroup.Item1, i.ToString());
}
}
// None of these do anything
spriteLibraryToPopulate.SetDirty();
EditorUtility.SetDirty(spriteLibraryToPopulate);
AssetDatabase.SaveAssets();
AssetDatabase.SaveAssetIfDirty(new UnityEditor.GUID(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(spriteLibraryToPopulate))));
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(spriteLibraryToPopulate));
AssetDatabase.Refresh();
UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
If I run this script multiple times and stop on a breakpoint, I can see in Visual Studio that the sprites are being added as expected to the in-memory object. However, when I examine the Sprite Library asset, both in the editor and in the asset file using Notepad++, none of them appear.
Reimporting via the menu in the editor does nothing as well.
Investigation with a debugger shows that internally, Unity uses the class SpriteLibrarySourceAsset when importing a .spriteLib asset and creates the SpriteLibraryAsset I have access to in my scripts. I haven't been able to find how to go the other way.
I finally was able to achieve what I intended using reflection to call some internal Unity APIs.
// Perform your modification to the sprite library before this
// The logic to transform the SpriteLibraryAsset to the internal representation works on the selected objects.
Selection.objects = new UnityEngine.Object[]
{
spriteLibraryToPopulate
};
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(spriteLibraryToPopulate)) as SpriteLibrarySourceAssetImporter;
var saveMethod = typeof(SpriteLibrarySourceAssetImporter).GetMethod("ConvertToSourceAsset", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
saveMethod.Invoke(null, null);
var rootPath = Path.Join(AssetDatabase.GetAssetPath(spriteLibraryToPopulate), "..");
// The save logic creates a differently named instance of the asset, so we copy the data from our newly created one into the original
File.Copy(Path.Join(rootPath, string.Format("{0} 1.spriteLib", spriteLibraryToPopulate.name)),
Path.Join(rootPath, string.Format("{0}.spriteLib", spriteLibraryToPopulate.name)), true);
// Get rid of the extra asset and its associated meta file.
File.Delete(Path.Join(rootPath, string.Format("{0} 1.spriteLib", spriteLibraryToPopulate.name)));
File.Delete(Path.Join(rootPath, string.Format("{0} 1.spriteLib.meta", spriteLibraryToPopulate.name)));
At the end, the library should be selected in the Unity Editor. If you try and click away, it will be marked dirty and Unity will prompt you to save or revert; it appears to me that both have the same result.
I have am developing a HoloLens project that needs to reference .txt files. I have the files stored in Unity's 'Resources' folder and have them working perfectly fine (when run via Unity):
string basePath = Application.dataPath;
string metadataPath = String.Format(#"\Resources\...\metadata.txt", list);
// If metadata exists, set title and introduction strings.
if (File.Exists(basePath + metadataPath))
{
using (StreamReader sr = new StreamReader(new FileStream(basePath + metadataPath, FileMode.Open)))
{
...
}
}
However, when building the program for HoloLens deployment, I am able to run the code but it doesn't work. None of the resources show up and when examining the HoloLens Visual Studio solution (created by selecting build in Unity), I don't even see a resources or assets folder. I am wondering if I am doing something wrong or if there was a special way to deal with such resources.
Also with image and sound files...
foreach (string str in im)
{
spriteList.Add(Resources.Load<Sprite>(str));
}
The string 'str' is valid; it works absolutely fine with Unity. However, again, it's not loading anything when running through the HoloLens.
You can't read the Resources directory with the StreamReader or the File class. You must use Resources.Load.
1.The path is relative to any Resources folder inside the Assets folder of your project.
2.Do not include the file extension names such as .txt, .png, .mp3 in the path parameter.
3.Use forward slashes instead of back slashes when you have another folder inside the Resources folder. backslashes won't work.
Text files:
TextAsset txtAsset = (TextAsset)Resources.Load("textfile", typeof(TextAsset));
string tileFile = txtAsset.text;
Supported TextAsset formats:
txt .html .htm .xml .bytes .json .csv .yaml .fnt
Sound files:
AudioClip audio = Resources.Load("soundFile", typeof(AudioClip)) as AudioClip;
Image files:
Texture2D texture = Resources.Load("textureFile", typeof(Texture2D)) as Texture2D;
Sprites - Single:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Single.
Sprite sprite = Resources.Load("spriteFile", typeof(Sprite)) as Sprite;
Sprites - Multiple:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Multiple.
Sprite[] sprite = Resources.LoadAll<Sprite>("spriteFile") as Sprite[];
Video files (Unity >= 5.6):
VideoClip video = Resources.Load("videoFile", typeof(VideoClip)) as VideoClip;
GameObject Prefab:
GameObject prefab = Resources.Load("shipPrefab", typeof(GameObject)) as GameObject;
3D Mesh (such as FBX files)
Mesh model = Resources.Load("yourModelFileName", typeof(Mesh)) as Mesh;
3D Mesh (from GameObject Prefab)
MeshFilter modelFromGameObject = Resources.Load("yourGameObject", typeof(MeshFilter)) as MeshFilter;
Mesh loadedMesh = modelFromGameObject.sharedMesh; //Or design.mesh
3D Model (as GameObject)
GameObject loadedObj = Resources.Load("yourGameObject") as GameObject;
//MeshFilter meshFilter = loadedObj.GetComponent<MeshFilter>();
//Mesh loadedMesh = meshFilter.sharedMesh;
GameObject object1 = Instantiate(loadedObj) as GameObject;
Accessing files in a sub-folder:
For example, if you have a shoot.mp3 file which is in a sub-folder called "Sound" that is placed in the Resources folder, you use the forward slash:
AudioClip audio = Resources.Load("Sound/shoot", typeof(AudioClip)) as AudioClip;
Asynchronous Loading:
IEnumerator loadFromResourcesFolder()
{
//Request data to be loaded
ResourceRequest loadAsync = Resources.LoadAsync("shipPrefab", typeof(GameObject));
//Wait till we are done loading
while (!loadAsync.isDone)
{
Debug.Log("Load Progress: " + loadAsync.progress);
yield return null;
}
//Get the loaded data
GameObject prefab = loadAsync.asset as GameObject;
}
To use: StartCoroutine(loadFromResourcesFolder());
If you want to load text file from resource please do not specify file extension
just simply follow the below given code
private void Start()
{
TextAsset t = Resources.Load<TextAsset>("textFileName");
List<string> lines = new List<string>(t.text.Split('\n'));
foreach (string line in lines)
{
Debug.Log(line);
}
}
debug.Log can print all the data that are available in text file
You can try to store your text files in streamingsasset folder. It works fine in my project
I have am developing a HoloLens project that needs to reference .txt files. I have the files stored in Unity's 'Resources' folder and have them working perfectly fine (when run via Unity):
string basePath = Application.dataPath;
string metadataPath = String.Format(#"\Resources\...\metadata.txt", list);
// If metadata exists, set title and introduction strings.
if (File.Exists(basePath + metadataPath))
{
using (StreamReader sr = new StreamReader(new FileStream(basePath + metadataPath, FileMode.Open)))
{
...
}
}
However, when building the program for HoloLens deployment, I am able to run the code but it doesn't work. None of the resources show up and when examining the HoloLens Visual Studio solution (created by selecting build in Unity), I don't even see a resources or assets folder. I am wondering if I am doing something wrong or if there was a special way to deal with such resources.
Also with image and sound files...
foreach (string str in im)
{
spriteList.Add(Resources.Load<Sprite>(str));
}
The string 'str' is valid; it works absolutely fine with Unity. However, again, it's not loading anything when running through the HoloLens.
You can't read the Resources directory with the StreamReader or the File class. You must use Resources.Load.
1.The path is relative to any Resources folder inside the Assets folder of your project.
2.Do not include the file extension names such as .txt, .png, .mp3 in the path parameter.
3.Use forward slashes instead of back slashes when you have another folder inside the Resources folder. backslashes won't work.
Text files:
TextAsset txtAsset = (TextAsset)Resources.Load("textfile", typeof(TextAsset));
string tileFile = txtAsset.text;
Supported TextAsset formats:
txt .html .htm .xml .bytes .json .csv .yaml .fnt
Sound files:
AudioClip audio = Resources.Load("soundFile", typeof(AudioClip)) as AudioClip;
Image files:
Texture2D texture = Resources.Load("textureFile", typeof(Texture2D)) as Texture2D;
Sprites - Single:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Single.
Sprite sprite = Resources.Load("spriteFile", typeof(Sprite)) as Sprite;
Sprites - Multiple:
Image with Texture Type set to Sprite (2D and UI) and
Image with Sprite Mode set to Multiple.
Sprite[] sprite = Resources.LoadAll<Sprite>("spriteFile") as Sprite[];
Video files (Unity >= 5.6):
VideoClip video = Resources.Load("videoFile", typeof(VideoClip)) as VideoClip;
GameObject Prefab:
GameObject prefab = Resources.Load("shipPrefab", typeof(GameObject)) as GameObject;
3D Mesh (such as FBX files)
Mesh model = Resources.Load("yourModelFileName", typeof(Mesh)) as Mesh;
3D Mesh (from GameObject Prefab)
MeshFilter modelFromGameObject = Resources.Load("yourGameObject", typeof(MeshFilter)) as MeshFilter;
Mesh loadedMesh = modelFromGameObject.sharedMesh; //Or design.mesh
3D Model (as GameObject)
GameObject loadedObj = Resources.Load("yourGameObject") as GameObject;
//MeshFilter meshFilter = loadedObj.GetComponent<MeshFilter>();
//Mesh loadedMesh = meshFilter.sharedMesh;
GameObject object1 = Instantiate(loadedObj) as GameObject;
Accessing files in a sub-folder:
For example, if you have a shoot.mp3 file which is in a sub-folder called "Sound" that is placed in the Resources folder, you use the forward slash:
AudioClip audio = Resources.Load("Sound/shoot", typeof(AudioClip)) as AudioClip;
Asynchronous Loading:
IEnumerator loadFromResourcesFolder()
{
//Request data to be loaded
ResourceRequest loadAsync = Resources.LoadAsync("shipPrefab", typeof(GameObject));
//Wait till we are done loading
while (!loadAsync.isDone)
{
Debug.Log("Load Progress: " + loadAsync.progress);
yield return null;
}
//Get the loaded data
GameObject prefab = loadAsync.asset as GameObject;
}
To use: StartCoroutine(loadFromResourcesFolder());
If you want to load text file from resource please do not specify file extension
just simply follow the below given code
private void Start()
{
TextAsset t = Resources.Load<TextAsset>("textFileName");
List<string> lines = new List<string>(t.text.Split('\n'));
foreach (string line in lines)
{
Debug.Log(line);
}
}
debug.Log can print all the data that are available in text file
You can try to store your text files in streamingsasset folder. It works fine in my project
I'm loading a .jpeg file in at runtime from disk, it works absolutely fine in the player but when I build the project the texture being loaded in via WWW doesn't display - no errors. It suggests a format issue, but like I said it renders as expected in the player:
Unit doc: https://docs.unity3d.com/ScriptReference/WWW.LoadImageIntoTexture.html
private IEnumerator SetMaterialImage(string path)
{
Texture2D tex;
tex = new Texture2D(4, 4, TextureFormat.RGB24, false, true);
WWW www = new WWW(path);
if (!string.IsNullOrEmpty(www.error))
{
Debug.Log("ERROR REDNERING IMAGE --- " + www.error);
}
while (!www.isDone) yield return null;
if (www.isDone)
{
Debug.Log("WWW,ISDONE = TRUE");
Shader shader = Shader.Find("Standard");
www.LoadImageIntoTexture(tex);
GetComponent<Renderer>().material.mainTexture = tex;
GetComponent<Renderer>().material.shader = shader;
}
}
Edit: please don't suggest the Resources folder - this particular application must load from disk
I was unable to locate any Unity documentation that explains why this scenario differed between Player and Build, however I was able to confirm that:
GetComponent<Renderer>().material.mainTexture = tex;
Renderer>().material.shader = shader;
Should have been declared in the opposite order:
Renderer>().material.shader = shader;
GetComponent<Renderer>().material.mainTexture = tex;
Edit: Credit #Programmer 'The reason that code work in the Editor is because the Editor remembers which Shader or Texture is assigned to a material. So, when you change the shader, it uses the old texture'
I created an asset bundle from an .fbx file. Then; I use this code for loading it into a very simple unity project
public class k : MonoBehaviour {
public string url;
// Use this for initialization
public string AssetName;
void Start()
{
}
IEnumerator DownloadAndCache(string bundleURL)
{
while (!Caching.ready)
yield return null;
using (WWW www = WWW.LoadFromCacheOrDownload(bundleURL, 1))
{
yield return www;
if (www.error != null)
throw new Exception("WWW download had an error:" + www.error);
AssetBundle bundle = www.assetBundle;
if (AssetName == "")
Instantiate(bundle.mainAsset);
else
Instantiate(bundle.LoadAsset(AssetName));
bundle.Unload(false);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.D))
StartCoroutine(DownloadAndCache(url));
}
}
but always is having the next issue
and I don't understand. Since i'm passing a valid local url in the next format :
file:///c:/asset/robot.unity3d
please help
A file with a unity3d extension isn't usually an AssetBundle.
To have an AssetBundle with the model in it you have to:
Import the model in Unity
Select the imported model so you see its properties in the Inspector
At the bottom of the Inspector there is a little interface to create and select AssetBundles (this way the model will be assigned to the selected AssetBundle)
After assigning every asset to their AssetBundle, you need to build the Bundles
Put the bundles files on a server or in the StreamingAssets folder and use their URL
AssetBundle management in Unity is still a painfull process so I suggest you to thoroughly read the Guide to AssetBundles and Resources.
There is also an AssetBundleManager here but I find it's code is a mess.
It's buggy and almost impossible to decipher: I ended up writing my own so I can't really suggest you to use it yet (I linked it because it might get better in the future).
Try calling bundle.GetAllAssetNames() to see what is inside the bundle before trying to instantiate anything.
AssetBundle bundle = www.assetBundle;
foreach(var name in bundle.GetAllAssetNames()){
Debug.Log(name);
}
mainAsset may be null depending on how the AssetBundle was created, so maybe that is what happening here, does it gives you the null exception if you try loading assets by name?