I'm trying to build an application for OculusGO but the file is too big so I'm working with AssetBundles to lower the size. I've worked with this link so far Build and load Assetbundles in Unity but I don't know how to do this with videos.
I currently have this as my loader for the application but I need it to load from the AssetBundle
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
[CreateAssetMenu(fileName = "Situation", menuName = "Situation", order = 1)]
public class SituationData : ScriptableObject
{
public VideoClip video;
public AssetBundle.LoadFromFileAsync(Assets/StreamingAssets/AssetBundles);
public Sprite screenshot;
public Sprite situationPanel;
public Sprite situationPanelSelected;
public string objectiveText;
public string sessionName;
public float startRotation;
IEnumerator LoadAsset(string assetBundleName, string objectNameToLoad)
{
string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "AssetBundles");
filePath = System.IO.Path.Combine(filePath, assetBundleName);
//Load "animals" AssetBundle
var assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(filePath);
yield return assetBundleCreateRequest;
AssetBundle asseBundle = assetBundleCreateRequest.assetBundle;
//Load the "dog" Asset (Use Texture2D since it's a Texture. Use GameObject if prefab)
AssetBundleRequest asset = asseBundle.LoadAssetAsync<VideoClip>(objectNameToLoad);
yield return asset;
//Retrieve the object (Use Texture2D since it's a Texture. Use GameObject if prefab)
VideoClip loadedAsset = asset.asset as VideoClip;
//Do something with the loaded loadedAsset object (Load to RawImage for example)
image.texture = loadedAsset;
}
}
Just for clarity, I've already built the AssetBundles, I just don't know how to load those in instead of the actual video files so I can reduce the file size.
Related
I am working on a project where I have a script that combines all the meshes of a gameobjects childs into one mesh while in edit mode. Now the problem is that even though I have managed to then save the mesh into my assets folder it is only saved as a default asset(blank white icon) and not as a mesh that I can then use for other things. Now I would like to know how to get it saved as a mesh asset. I think I could either somehow convert the default asset file to a mesh asset if that is possible, or I could directly save an objects mesh into the asset folder but I dont know if that's possible.
I would be very grateful if you could share code that I could use to do this(it doesnt have to be fance, it should just work).
Here is the code that I have currently:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
// Copy meshes from children into the parent's Mesh.
// CombineInstance stores the list of meshes. These are combined
// and assigned to the attached Mesh.
public class CombineMeshes : EditorWindow
{
[Header("References")]
public GameObject generateFromObject;
[MenuItem("Window/My/MeshGenerator")]
static void Init()
{
CombineMeshes window = (CombineMeshes)GetWindow(typeof(CombineMeshes));
}
private void OnGUI()
{
generateFromObject = (GameObject)EditorGUILayout.ObjectField(generateFromObject, typeof(GameObject), true);
if (GUILayout.Button("Generate"))
{
Generate();
}
}
void Generate()
{
MeshFilter[] meshFilters = generateFromObject.GetComponentsInChildren<MeshFilter>();
CombineInstance[] combine = new CombineInstance[meshFilters.Length];
int i = 0;
while (i < meshFilters.Length)
{
combine[i].mesh = meshFilters[i].sharedMesh;
combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
i++;
}
generateFromObject.transform.GetComponent<MeshFilter>().mesh = new Mesh();
generateFromObject.transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine);
generateFromObject.transform.gameObject.SetActive(true);
Mesh mesh = generateFromObject.transform.GetComponent<MeshFilter>().mesh;
AssetDatabase.CreateAsset(mesh, "Assets/myAsset");
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(mesh));
AssetDatabase.SaveAssets();
}
}
Scenario: User has different tile palettes for each season (Summer, Fall, etc.) and switching between the two using popular Unity techniques would be tedious if the number of tiles in the tileset is greater than 5 or 10. How would said user switch between their tile palettes programmatically, instead of using a wasteful solution like prefab tiles?
This problem seems significant enough that Unity docs would cover it. However I found myself digging through years-old forum posts to come up with my solution. Here's what I came up with, and it's not too complicated.
Create your tilesets. Import your tilesets as multi-sprite spritesheets, and split them using the Unity sprite editor. Do not bother naming each sprite. Each tileset should be organized the same exact way (bushes/trees/objects should be in the same spot on every season's tilesheet). When you are finished, create a folder "Resources" in your "Assets" folder. Inside of resources, create a folder "Spritesheets", and place your spricesheets in it.
Run this renaming script:
using UnityEngine;
using UnityEditor;
using System.Collections;
public class SpriteRenamer : MonoBehaviour
{
public Texture2D[] texture2Ds;
public string newName;
private string path;
private TextureImporter textureImporter;
void Start ()
{
foreach(Texture2D texture2D in texture2Ds){
path = AssetDatabase.GetAssetPath (texture2D);
textureImporter = AssetImporter.GetAtPath (path) as TextureImporter;
SpriteMetaData[] sliceMetaData = textureImporter.spritesheet;
int index = 0;
foreach (SpriteMetaData individualSliceData in sliceMetaData)
{
sliceMetaData[index].name = string.Format (newName + "_{0}", index);
print (sliceMetaData[index].name);
index++;
}
textureImporter.spritesheet = sliceMetaData;
EditorUtility.SetDirty (textureImporter);
textureImporter.SaveAndReimport ();
AssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);
}
}
}
Attach it to an empty GameObject in an empty Scene (just for simplicity). Drag and drop your spritesheets into the Texture2D array. Set the newName field to whatever you want, it will be the prefix for the name of each sprite in each spritesheet. Finally, run the scene and each spritesheet's sprites will be renamed to make each corresponding sprite have the same name.
We now have each of our seasons' tilesheets modified so each tile is identically named. The next step is to create a Grid object with a child TilePalette. Draw all of your scenery, collision, etc. You can use as many TilePalettes as needed, as long as they are children of the Grid object. Now, create a script called ReskinnableTileBase:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class ReskinnableTileBase : TileBase
{
public Sprite sprite;
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
tileData.sprite = sprite;
}
}
Attach this Reskinner script to your Grid object:
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;
public class Reskinner : MonoBehaviour
{
Sprite[] subSprites;
Tilemap[] tilemaps;
void Start(){
tilemaps = GetComponentsInChildren<Tilemap>();
SetSkin("#INSERT DEFAULT TILE PALETTE NAME HERE#");
}
public void SetSkin(string name){
reloadSprites(name);
foreach(Tilemap tilemap in tilemaps){
for(int x = (int)tilemap.localBounds.min.x; x < tilemap.localBounds.max.x; x++){
for(int y = (int)tilemap.localBounds.min.y; y < tilemap.localBounds.max.y; y++){
TileBase tb = tilemap.GetTile(new Vector3Int(x, y, 0));
Debug.Log(tb);
ReskinnableTileBase rtb = (ReskinnableTileBase)ScriptableObject.CreateInstance(typeof(ReskinnableTileBase));
if(tb == null || rtb == null || tb.name.Length < 1){
continue;
}
Sprite replace = getSubSpriteByName(tb.name);
rtb.sprite = replace;
rtb.name = tb.name;
tilemap.SwapTile(tb, (TileBase)rtb);
}
}
}
}
void reloadSprites(string name){
subSprites = Resources.LoadAll<Sprite>("Spritesheets/" + name);
}
Sprite getSubSpriteByName(string name){
foreach(Sprite s in subSprites){
if(s.name == name){
return s;
}
}
return null;
}
}
And there you go! Now, any time you need to change the skin/season/tilesheet, just use a reference to the Grid's Reskinner script, and call the SetSkin method, like so:
Reskinner reskinner = gridObject.GetComponent<Reskinner>();
reskinner.SetSkin("summer");
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
Hi My scene name is a game.In that scene I am having A main panel that's name is ITEMCONTAINER. In item container I am having a panel whoes name is ITEM. I attached a script in ITEM PANEL. IN that script i am having a game object public,a raw image ,text and how many times loop will continue are public.
In the place of game object i attached my prefab,that contain 1 text and 2 rawimage.
in place of text i attached text component of prefab and same like raw image.
When I run the game the text value I am getting correctly but rawimage is showing blank in runtime.Here i am running my loop 3 times and all three times it create clone of my prefab panel as a child in itempanel
I want rawimage dynamic at my run time
output
prefab
image= in this image , it contains output.here rawimage is blank but text valuecoming perfectly
image = it is my prefab that prefab will be clone during runtime, here it shows image but during runtime , in clone it shows blank
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DynamicData : MonoBehaviour {
public GameObject prefab;
public Text name;
public int numberToCreate;
public RawImage profile;
void Start () {
for (int i = 0; i < numberToCreate; i++)
{
name.text = "a"+i;
StartCoroutine( ImageDownload( profile));
Instantiate <GameObject>(prefab, transform);
}
}
IEnumerator ImageDownload ( RawImage img) {
WWW www = new WWW("https://www.w3schools.com/w3images/fjords.jpg");
yield return www;
Texture2D texure = new Texture2D (1, 1);
texure.LoadImage (www.bytes);
texure.Apply ();
img.texture = texure;
}
}
You are assigning the downloaded image to the profile variable which is not a variable from the instantiated Object. In the loop, you need to get the child of each instantiated Object with transform.Find("profile") then get the RawImage component attached to it with GetComponent and pass it to the ImageDownload function.
Replace your for loop with this:
for (int i = 0; i < numberToCreate; i++)
{
name.text = "a" + i;
GameObject instance = Instantiate<GameObject>(prefab, transform);
//Get RawImage of the current instance
RawImage rImage = instance.transform.Find("profile").GetComponent<RawImage>();
StartCoroutine(ImageDownload(rImage));
}
Please rename public Text name; to something else like public Text userName; because the name is already declared in MonoBehavior you derived your script from.
I have created a cube in the scene and I want to attach the texture to the cube by scripting.
The problem is there is no error of my code but The cube doesn't change after I press run in my program...
Here is my code
using UnityEngine;
using System.Collections;
public class testing : MonoBehaviour {
void start(){
Texture2D tex = (Texture2D)Resources.Load("BlueColorTex.png", typeof(Texture2D));
renderer.material.mainTexture = tex;
}
}
void start()
{
Texture2D tex = (Texture2D)Resources.Load("BlueColorTex", typeof(Texture2D));
renderer.material.mainTexture = tex;
}
Resources.Load does not use extensions. This is a common mistake.
Returns the asset at path if it can be found otherwise returns null.
Only objects of type T will be returned. The path is relative to any
Resources folder inside the Assets folder of your project,
extensions must be omitted.
from: http://docs.unity3d.com/ScriptReference/Resources.Load.html