Unity iOs - screen gets black when changing rotation while Unity is paused

1.6k Views Asked by At

I have a unity app, that uses Vuforia AR library. I extended this app with some iOs code. I wanted to be able to display my custom UIViewControllers sometimes instead of the main view controller that Unity uses. But I want to be able to switch back. I.e: I have a button that opens UIViewController with "About app" information and this controller then has "Exit" button to return to Unity controller.

This is my code for adding the new controller instead of the Unity View Controller:

self.unityRootController = self.keyWindow.rootViewController; // keep reference to the Unity Controller
self.keyWindow.rootViewController = controller; // display my own controller

// this pauses the unity and qcar -> so that QCAR doesn't try to recognize objects, when Unity Controller is not up
QCARUnityPlayer::getInstance().QCARPause(true);
UnityPause(true);

Then when returning from my own controller to Unity controller:

self.keyWindow.rootViewController = self.unityRootController; // return to Unity Controller

// start tracking with QCAR and unpause Unity View
QCARUnityPlayer::getInstance().QCARPause(false);
UnityPause(NO);

This works fine except one case, that's caused me to pull my hair ever since encountering it. My app supports changing orientation of screen in both Unity and ObjectiveC code. And this is the trouble: If I open my View Controller while the device is for example in Portrait Orientation, then turn the device to Landscape orientation, my controller gets correctly rotated. But if I at this moment want to close my custom view controller and return to unity controller, the screen gets black suddenly. After rotating the device to portrait orientation, the unity controller suddenly starts working as expected.

I'd like the unity controller to start directly after closing my custom view controller even if the screen orientation is changed. I suppose I have to add some code after I start again the Unity Player here:

QCARUnityPlayer::getInstance().QCARPause(false);
UnityPause(NO);
// TODO: supposedly some code should go here, that fixes black screen

But I tried to find something in the AppController.mm, that is builded by Unity and I could not find anything, that would help me. I found few lines of unity code, that had the word "orientation" in it, but I tried to use that code and didn't help. Does anybody know, what should I do, please? Thanks a bunch :)

1

There are 1 best solutions below

1
On

Not sure if you have fixed this, Its been a while... But the reason that your UnityViewController is not functioning properly is because a view controller that is not visible will not receive rotation events. Because you are setting your view controller as the root view controller, the UnityDefaultViewController defined in "iPhone_View.mm" is not receiving rotation events.

I have been studying Unity's rotation for a while now as I have my own issue with a similar setup.

There are a few things that you might be able to try:

  1. In iPhone_View.mm there is a function that is defined called: UpdateOrientationFromController(UIViewController* controller) that might be able to solve your problem. You would want to call this function on the view controller that you designed yourself where you placed your //TODO comment. That function calls a few key functions and methods that handle Unity's interface orientations:

    • ConvertToUnityScreenOrientation: for some reason Unity Uses their own defined screen orientations, this internally converts the orientation to what Unity uses.
    • QCARUnityPlayer::getInstance().QCARSetOrientation(): QCAR Also needs its orientation to be set
    • UnitySetScreenOrientation(_curOrientation): The unity library has an internal way of checking the screen orientation at every rendered frame. I think this function sets an internal flag for the Unity View to check in CheckOrientationRequest() defined in iPhone_View.h as well.
    • AppController_RenderPluginMethodWithArg is called, I am not sure what this does, but I think it does something important
    • OrientTo(_curOrientation): this kicks off the actual orientation change and handles the right calls. This includes the call to AppController's onForcedOrientation: method that does the final orientation.
  2. You may be able to call AppController's onForcedOrientation: method directly with a UnityScreenOrientation after you convert a UIDeviceOrientation to a UnityScreen Orientation with ConvertToUnityScreenOrientation() defined in iPhone_OrientationSupport.h. You may not want to call this method directly though, because there are quite a few things that are involved with Unity's orientation methods. You would do this when your app returns from presenting your view controller.

  3. The last thing, and the "hackiest thing" that you can do, that will get the job done, but not in the most efficient way, is to add UnityDefaultViewController to your ViewController as a child ViewController with the addChildViewController: UIViewController Docs, or maybe as just a property, and then override the willRotateToInterfaceOrientation:duration: and didRotateFromInterfaceOrientation:in your ViewController and after calling super, pass the message to the UnityDefaultViewController. This will cause the UnityDefaultViewController to update the UnityView every time the orientation changes, even though the view isn't actually visible. You may or may not need to unpause Unity in order for this to function.

Of the three methods, the last one should definitely work, because I have implemented it myself. However, the first one should work as well, because Unity uses it several times to check the devices current orientation from the splash screen.

Hope this helps!