Avoiding that brief 'Empty Screen' using SceneKit - ios

I'm making a scene kit app and it all works very nicely indeed. My only annoyance is that for a brief second after loading, my SCNView object is completely blank. I presume that this is because the scene hasn't loaded or rendered yet, but I'd like to avoid it if possible.
I tried putting a masking view mimicking the app's loading screen in front of the SCNView and fading it out once rendering began using renderer:didRenderScene:atTime but alas, the animation for fading out the masking view doesn't happen (it just flashes off immediately instead of fading out). So I put the masking view in the app's main window as an experiment and gave it a short delay. However, even with the delay before removing that mask, the SCNView was still entirely blank for a split second before the scene appeared.
Can anyone tell me how to avoid this annoying graphical artefact?

As usual there is a simple fix that I just failed to find until now. After your scene has been completely set up, simply do:
sceneView.prepareObject(scene, shouldAbortBlock:nil)
...and bingo! No delay. It's caused because scenes, like all objects in a SCNView, are lazily loaded. Calling prepareObject lets you cache them in advance.

Related

AVPlayerLayer Popgesture Glitch

EDIT: https://bitbucket.org/KevinvandenhoekBeast/avplayerlayerpopgesture/overview <-- A simple sample project that recreates the problem, click on the video to push the detailviewcontroller, then popgesture back. The animations happen in the NavigationAnimator, and the popgesture logic is in the NavigationInteractor. The NavigationTransitioningView protocol defines the methods that are used by the animator to transition the video from one frame to the other.
Hello fellow developers,
For the past few evenings I’ve been struggling with a persistent and 100% reproducable animation glitch. I’ve been working on an app that has custom navigation transition animations that work both ways (push and pop). The transition I made is having a UIView type object moving in the transitioncontext from 1 view to the other, and so far it’s been working wonderfully using a protocol that I made for the two involved viewcontrollers, which lets them tell the animator what view they want to transition, and their respective from and to frames.
I use this on images, and on videoplayers, IE when the user clicks on an image in a collectionView the image frame animates from its origin in the original viewcontroller towards the position it should take in the detailViewController. The same happens for playing videoplayers. It works perfectly when I simply push a viewcontroller, and pop, for both videoplayers and images. However, recently I implemented a custom pop gesture (with a UIPercentDrivenInteractiveTransition subclassing class). The popgesture seemed to work wonderfully and I was looking at some beautifully lerped animation states, until I tried it with a videoplayer and the horror started.
When doing the popgesture with a videoplayer that is animated from one frame to another (as in CGRect) there is some extremely glitchy behaviour. The popgesture pretty much consistently cancels after a (very) short amount of time, generally at about 0.1 ish progress (an interesting detail: if I swipe very quick the gesture is completed and nothing bugs/glitches), but despite cancelling, the pop does (seem to) happen and I land back at the previous viewcontroller. This is where things get really funky. The visibility / frame of the viewcontroller is changed somewhat, like there is some clipping (somewhere past halfway the view cuts off), and the entire view seems to be shifted (upwards in my case), and generally repeating the popgesture worsens things. However, tapping on the view still responds as if the view is in its normal position (without the shift upwards). This leads me to believe this is some sort of a layer glitch with some of the stuff happening when animating an AVPlayerLayer with a UIPercentDrivenInteractiveTransition.
When I don't update the playerlayer containing view it’s frame while animating, the bug doesn’t occur. Similarly, when I remove the player’s layerClass override, and simply add an AVPlayerLayer as a sublayer (and update it’s frame in the layoutSubviews call), I also don’t experience the bug, but I get the side effect that the playerlayer immediately jumps to it’s final frame, despite the containing view animating properly).
I’m sincerely hoping there is someone that has a deeper knowledge in CALayers, and maybe recognizes these symptoms and could hopefully point me to what’s really causing them. Many thanks in advance.
I useful, I’m willing to upload a video of the issue.
tl;dr using a custom UIPercentDrivenInteractiveTransition subclass to lerp the frame property of a view with a layerClass of AVPlayerLayer from 1 CGRect to another causes very strange things to happen in the destination viewcontroller (its root view visually shifting / changing frame / clipping, while the touch area is as if the view isnt shifted (IE tapping a collectionViewCell highlights / selects the cell above)), despite the exact same animation logic working flawlessly when used without the UIPercentDrivenInteractiveTransition subclass popgesture handling.

Loading sprites and lags [duplicate]

My iOS game has a couple of scenes. I've noticed some lag between switching scenes, and I was wondering if it might be because I'm not removing all nodes and labels from parents when I transition to another scene. Is it good practice to remove all nodes from their parent when transitioning to another scene?
Also, I've noticed that when I do remove all nodes, the transition effect is kind of ruined, as the screen goes all black during the transition.
Is it possible to delete nodes(of previous scene) after the transition to next scene?
When you perform the transition, the scene and its nodes will be released from memory, unless you have a strong reference cycle. Also, you should know that SpriteKit has its own cache system for the SKTextures, so not all memory will freed.
The lag could be caused by a lot of thing, some possibilities:
If you instantiate the new scene on touchesEnded (or your custom button callback closure), the lag could be caused because you're doing too much work on the initialization. This can be solved by, for example, preloading the scene with a closure that run in background and, when you have to run the transition, you already have everything loaded. An example follows:
Maybe you're using assets that are too large and because they take longer to be loaded, you have the lag. You could solve this by, for example, converting images that don't need an alpha channel to .jpeg.
Another solution would be to preload assets. A code example follows.

Children of a Scene not releasing fast enough?

Have a couple of child nodes in a scene, and do a quick transition to a new scene.
In the new scene, didMove(to view: ….) is used to add the children from the previous scene to this next scene.
SceneKit crashes when doing this quickly, seemingly because the children of the old scene haven’t yet been released.
If I add a slight delay before adding the children to the second scene, it’s fine… it seems SpriteKit isn’t releasing the child fast enough for the scene transition.
the above is the most important thing to understand with regard the purpose for this question. I (wrongly) assumed SpriteKit would make sure all nodes attached to a scene were released before attempting to add them to a subsequent scene. It doesn't do this. But it does release them, it just takes a little time. Is this one frame? One second? Dunno...
My scene transition time is 0.25 seconds
Also tried using willMove(to view: ….) in the original scene to manually remove the children. This also doesn’t work, seemingly same behaviour: not fast enough.
Also tried assuming the child still has a relationship to its parent, so tried moving to its new parent, the new scene, with move(toParent:…) this also crashes. So maybe the children are already flagged as about to be released, I suppose.
Is this known about, and if so, how is it dealt with?
You can't present a scene and have willMove function at the same time in the same frame (SK loop)--your next scene's viewDidLoad will be called before the previous scene is destroyed. You have to remove all of the nodes before calling presentScene:
I suggest making a global variable of some sort to access your SKView; with that you can have control over your scenes from anywhere:
currentScene.removeAllChildren()
gView!.presentScene(nextScene)
“Is this a known about, and if so, how is it dealt with?"
Yes, this is a known issue of the SceneKit and IOS design and operational paradigms. It is considered that a scene must always be present and upon the screen. Can't have time without a scene onscreen.
As a result, for a brief time during transitions, both scenes are loaded, and active.
There are three ways to do deal with this problem:
Remove all content from the old scene prior to executing the transition so it can be instantly loaded by the new scene in didMove(to view...
or
Wait for completion of the transition before loading any content from the old scene into the new scene so there's no ownership conflicts of children.
or
KnightOfDragon’s first suggestion to use .copy() so there’s not the same instances being fought over by the scenes.

buttons appear on screen before SCNView

In storyboard, I have buttons attached to main view as siblings to SCNView(both buttons and SCNView are subviews of main view). At launch time, the buttons appear on screen before the SCNView does. This is quite unfortunate. Do you have any idea how to fix this?
//edit: added button programatically in viedDidLoad: as a subview of SCNView..Still the same problem.
SettingsButton and View appear before SceneView. This happens on iPhone 5,5c and lower and on iPads.(3 for sure, don't know for others)
Code for adding view programatically:
let uv = UIView(frame:myFrame)
uv.backgroundColor = UIColor.blackColor
sceneView.addSubview(uv)// scene view from storyboard
Thats it. How can iOS take 5-10s to load an app, but than rushes with adding views to the screen in an unpredictable order.. Couldn't it just take 0.2s more and present view properly? Really stupid problem
I imagine if you check via debugger breakpoints or logging in viewDidLoad, you'll find that the SCNView instance is indeed in the view hierarchy immediately.
What you're seeing is that said view's SceneKit content does not appear immediately. Depending on what you're doing with SceneKit, it may take some time to load content and prepare for rendering, and during that time the rest of the view hierarchy remains visible. That delay is probably unavoidable — you might be able to minimize it by optimizing asset formats, reducing the amount of stuff in your scene, etc. So it sounds like the key issue here is getting your app launch experience to look the way you want while accounting for the delay.
A good way to do that might be to show a splash image of some sort until SceneKit is ready to display. You could put a UIImageView in your storyboard, set up to obscure everything with a splash screen (possibly the same launch image iOS displays before your app takes over), then hide that image view (with a fade out even?) when SceneKit starts rendering.
To find out when SceneKit starts rendering, make one of your objects the scene renderer delegate and implement renderer:didRenderScene:atTime:. That method gets called on every frame, so you can use it to catch when the first frame has been rendered (and then ignore it for subsequent frames).

View transitions slowed down on adding OpenGL view

Facing a really, really weird problem with an OpenGL View we are using in our app to perform some custom animations. As soon as the Open GL View is added into the project, all native View animations slow down. And by slow down I don't mean a drop in frame rate. The animations are stutter-free, except much much MUCH slower than normal (like someone enabled "Toggle Slow Animations" in the Simulator).
This is affecting only view transitions animations, for example:
a. transitionFromView
b. presentViewController (iOS6, or presentModalViewController on earlier)
While regular UIView Animations, CABasicAnimation etc proceed at the regular pace.
I haven't seen anything like this, and the results honestly have to be seen to be believed. :) But any idea what the problem could be (I'm not sure which piece of the code would help you debug, and I'm unfortunately not in a position to share screenshots or video)
It seems like the animation gets stuck while loading the OpenGL View, debug the
Lifecycle methods like loadView, viewWillLoad. The loadview, etc. happens within the
transition animation, maybe you can solve the slow animation by sending most of the loading
code in to a custom method which you call in viewdidload or viewdidappear.
It does not interrupt any other animation because thats a totally new action in the queue.
Hope this helps!
Found the solution accidentally several days later.
The problem turned out to be much sillier and unrelated. It so happens that if you have a UIView beginAnimation block that is not closed properly, future animations get all wonky. This faultily coded animation happened to be triggered at more or less the same time as the OpenGL view was being initialized, which led to my erroneous belief that the OpenGL View was at the root of this.
Thanks for the help!

Resources