Unity Android and iOS handle textures at runtime - c#

I am developing an mobile application for Android an iOS with Unity to display panoramic images.
The images are downloaded and saved in the local storage of the device. One image is about 5mb to 10mb.
I am using WWW.LoadImageIntoTexture at start of the app. But if I have more than seven images the app crashes. I figured out that LoadImageToTexture creates images with RGBA32 format. So each texture has about 100mb. So the crash is caused by full memory.
I tried Texture2d.Compress() but it only compresses to DXT1 or DTX5. Android can not handle DXT format.
New idea is to preload the image I want to view next. (Only one image is visible)
I tried to load the texture with a Coroutine. But the app stucks while using WWW.LoadImageIntoTexture about one second. So I tried threading. But WWW.LoadImageIntoTexture can not be executed outside the unity-main-thread.
Is there a way to execute WWW.LoadImageIntoTexture asynchronous? I tried with UniRX from the AssetStore:
public void StartPreloadPanorama(string targetid){
preloadFinished = false;
StartCoroutine (PreloadHandler ());
}
IEnumerator PreloadHandler(){
var preload = Observable.FromCoroutine(PreloadPanorama)
.Subscribe();
while (!preloadFinished) {
yield return null;
}
}
IEnumerator PreloadPanorama(){
//texture is a public string
WWW preloadTexturer = new WWW("file://"+texture);
Texture2D texTemp = new Texture2D (8192, 4096, TextureFormat.RGBA32, true);
preloadTexturer.LoadImageIntoTexture(texTemp);
preloadFinished = true;
//edit - there is some more code after that:
//preloadRenderer is a public Renderer attached to the gameobject displaying the panorama image
preloadRenderer.material.mainTexture = texTemp;
Resources.UnloadUnusedAssets();
Debug.Log("FINISHED");
yield return null;
}
But I still get the stucking...
Any ideas? Thanks!
Edit: according to the comments here is my setup:
I have two spheres, one active, one disabled. (GameObject.SetActive(false))
My camera is inside the spheres. Camera and the two spheres have the position 0,0,0 - you can move the camera by gyro.
There are some buttons placed inside the spheres. If you gaze at a button for 2 seconds the active sphere is disabled and the other sphere is activated. By starting the gaze the StartPreloadPanorama() function is called and a new picture is attached to the disabled sphere.

Related

Previous scene lingering in the background Unity

I've been trying to switch from the main menu for our game into the first level. But the main menu keeps showing in the background no matter what I try.
So, this is our main menu (the loading screen looks just about identical, but with a loading bar in the center and without the buttons or SOMNIUM):
Yes, I know it looks ridiculous. This was a stand-in that one of our artists did in ten minutes in paint. They're still working on the real main menu art.
And this is what I get when I try to start a new game (you can see how the loading canvas from the main menu scene is still there in the background):
I got the code I'm currently using from a tutorial (I hoped copying their code would help - it didn't, but it looks nicer than mine).
public class StartGame : MonoBehaviour
{
public GameObject mainMenuCanvas;
public GameObject loadingScreenCanvas;
public Slider slider;
public void NewGame(int levelToLoad)
{
StartCoroutine(LoadAsynchronously(levelToLoad));
}
IEnumerator LoadAsynchronously(int levelToLoad)
{
// Set the loading of the level as an async operation
AsyncOperation operation = SceneManager.LoadSceneAsync(levelToLoad, LoadSceneMode.Single);
while(!operation.isDone)
{
// Get the 0-1 progress value
float progress = Mathf.Clamp01(operation.progress / 0.9f);
// Apply the progress value to the slider, which also goes from 0-1
slider.value = progress;
// Going to have a thing here to show the percentage completed as text
// End the Coroutine
yield return null;
}
}
}
Other than specifying LoadSceneMode.Single, I've trying directly destroying the main menu scene when moving to the game scene. But that had no effect. I've also trying turning off the canvas for the main menu scene when moving to the game scene. But that didn't work either.
Before loading the new scene, you can get a handle to the current scene with SceneManager.GetActiveScene. Then when the new scene has finished loading, you can manually unload the old scene with SceneManager.UnloadSceneAsync.

WebCamTexture is not being rendered on a 3D plane

I am trying to access HoloLens camera using WebCamTexture, it works fine on standalone app, I am passing the frames to DLL for image processing but when deployed on HoloLens the communication between the script and the DLL is perfect it also works fine. The problem is I am not able to render the frames on 3D plane.
I tried this code on standalone app as well as on hololens. If tried this code without calling the DLL it worked for me. But when passing the frames to DLL the the 3D plane is missing.
// Use this for initialization
void Start ()
{
webcamTexture = new WebCamTexture();
Renderer renderer = GetComponent<Renderer>();
renderer.material.mainTexture = webcamTexture;
webcamTexture.Play();
data = new Color32[webcamTexture.width * webcamTexture.height];
}
Expected result: I want to display live video on 3D plane on HoloLens.

Apply coordinates after scene restart in hololens

I have the following setup right now:
"Startup" scene which initializes all managers (spatial mapping, cursors, camera, ...)
"Main" scene with animations and one object which moves around
Once the users interacts with the program the scene restarts at some point, then the following should happen:
Object's coordinates get stored (E.g. DontDestroyOnLoad() on a "storage object". I need to destroy the object since it needs to reset itself on scene restart)
Scene restarts
Object gets recreated with stored coordinates
Code:
DataPositionStorer positionStorer = new GameObject("DataPositionStorer").AddComponent<DataPositionStorer>();
DontDestroyOnLoad(positionStorer.gameObject);
// dataPoints is the specific object I need to keep the coordinates of
positionStorer.Position = dataPoints.transform.position;
positionStorer.Rotation = dataPoints.transform.rotation;
positionStorer.Zoom = dataPoints.transform.localScale;
// Reload current scene ("Main")
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
And in the startup method of the object:
DataPositionStorer positionStorer = FindObjectOfType<DataPositionStorer>();
if (positionStorer!= null)
{
dataPoints.transform.position = positionStorer.Position;
dataPoints.transform.localRotation = positionStorer.Rotation;
dataPoints.transform.localScale = positionStorer.Zoom;
}
This setup works in the unity player but once I run it in the hololens emulator / on a hololens the position afterwards isn't correct anymore.
Can somebody help me resolve this problem on the emulator / hololens?
Thanks to the two guys commenting I've found a solution:
Load the WorldAnchorManager Script in the Setup scene and make it DontDestroyOnLoad
Attach a World Anchor before the scene restarts
Load the World Anchor after the scene restarted
This however only works on the emulator / HoloLens itself. In the Unity Editor World Anchors don't work! So just copy paste the coordinates over like I did in my initial post.

Unity3d Screen.orientation not forcing screen to rotate on scene initialization

I am trying to develop an Android app in Unity3d which needs the screen to change orientation when going from one scene to another.
I've added this code to the script attached to the first scene:
void Start()
{
Screen.orientation = ScreenOrientation.Portrait;
}
And this is attached to the second scene:
void Start()
{
Screen.orientation = ScreenOrientation.Landscape;
}
I assume that this should force the screen to rotate and stay in the specified rotation. However, when I go from scene 1 to scene 2, it does not force the orientation on scene initialization, instead, if I am switching from the first scene to the second, the screen stays in portrait orientation as long as I don't move the device. When I move the device in any direction, the screen changes to landscape orientation and stays locked in landscape.
For whatever reason, this does not apply when going from scene 2 to scene 1: the screen rotates properly, no matter its previous rotation. I find this really frustrating as the UI in the second scene is designed to be viewed in landscape mode and it is inconvenient to move the device every time you try to change scenes. So am I missing something or is this a bug?
Use LandscapeLeft or LandscapeRight instead
https://docs.unity3d.com/ScriptReference/ScreenOrientation.html

How can I properly use WebCamTexture in Unity iOS?

I was recently using the WebCamTexture API in Unity, but ran across a couple issues.
My biggest issue is orientation. When I ran the app on my phone, it wouldn't work properly in portrait mode: the image was orientated so it was landscape while the phone was portrait. Rotating the phone didn't help.
Then I changed the default orientation of the app to landscape and it worked, but the image was reflected: letters and such would be backwards in the image. Rotating the image 180 on the y-axis didn't help since it was a 1 sided image.
Here's the code for the camera alone:
cam = new WebCamTexture();
camImage.texture = cam;
camImage.material.mainTexture = cam;
cam.Play ();
camImage.transform.localScale = new Vector3(-1,-1,1);
where camImage is a RawImage.
How would I rotate the image to work correctly in portrait as well as reflecting the image correctly? Am I using the API incorrectly?
important -
for some years now, it is really only practical to use "NatCam" now for camera work, either ios or droid, in Unity3D - every app which uses the camera, uses it.
There is no other realistic solution, until Unity actually do the job and include (working :) ) camera software.
solution is basically this ...
you have to do this EVERY FRAME, you can't do it "when the camera starts".
Unity f'd up and the actual values only arrive after a second or so. it's a well-known problem
private void _orient()
{
float physical = (float)wct.width/(float)wct.height;
rawImageARF.aspectRatio = physical;
float scaleY = wct.videoVerticallyMirrored ? -1f : 1f;
rawImageRT.localScale = new Vector3(1f, scaleY, 1f);
int orient = -wct.videoRotationAngle;
rawImageRT.localEulerAngles = new Vector3(0f,0f,orient);
showOrient.text = orient.ToString();
}

Categories