flashes of previous SceneKit content - swift

My app alternates "pages" of SceneKit content with images and text. When I advance from an image page to a new SceneKit page, the content from the previous SceneKit page is briefly displayed before being replaced by the new content. Funky.
I'm only using one SCNScene and one SCNView. When I transition to an image type page, I hide the SCNView. To reinstate a new SceneKit display I:
remove all nodes from the rootNode
load new node graphs from file
add the new node graphs to the rootNode
unhide the SCNView
Evidently the unhiding is asynchronous and I'm seeing the remnants of the earlier scene while the new one is establishing. I'm having a similar issue with AVPlayer as well.
In past apps I experienced this same issue with MPMoviePlayer and delt with it by displaying a blank view over the movie view and then hiding that on notification that the current movie had loaded. Perhaps I can deal with the AVPlayer issue in the same manner but I don't see this applying to SceneKit. Even in the case of AVPlayer I'd like a better way of dealing with the issue if possible.
edit_1: I've tried Hal's idea of swapping out SCNScenes but still get the momentary residual image. I've tried using two SCNViews and alternately swapping them out. I've also tried moving the camera past visible elements before exiting the current scene. The prepareObjects:withCompletion handler did nothing.
It appears that it's not the nodes nor the SCNScene that is persisting but a rendered image of the scene. This is also supported by witnessing this effect with movie players as mentioned above.
edit_2: I tried a mask but like all other attempts it fails. I did have "success" with using an SCNAction to move the camera offscreen plus a completion handler to effect changes only after. However, this extends the load time by about 800%! Better to have the ugly "flash".

I've got something that works but I'm skeptical. I've created a "nullCamera", one that points to an empty field of view. Before switching out my scenes I assign that camera to the SCNView. When the new scene loads the principal camera is re-assigned. But I'm nervous about this approach.
I tried this before and it didn't work. It now works because I moved the code upstream (instead of where it seems to belong). But the interveining code has nothing to do with SceneKit. It merely parses data for strings, sets color prefs and displays a title in a label. So I'm worried that it's only about timing and I may see the issue again on, say, a faster device. Maybe writing the title to a view element forces a re-display of the SCNView too? (Which I couldn't seem to effect with code.)

Related

Image animation problems in Unity

I state that I am not very experienced in Unity.
I am working on a project in which I have some pictures. To these images I have added an animation that modifies the viewing scale (x,y,z), in such a way as to obtain a pulsation effect. ("ImageEffectPingPong")
To these same images, however, I added another animation that when the image is clicked, a fade effect is obtained, in such a way as to make the image disappear.("fadeOut_x")
When I go to make transition one of the two animations to the animator, it works as it should. the problem is when I try to merge them.
The ImageEffectPingPong animation is set in loop, while the other is activated by setting a bool to the onclick event.
animator.SetBool($"img_{pos}",true);
This is my animator
I tried a combination like this, but when I hit the first image, the fade works, but I no longer get the "pingpong" effect I want.
So how do i get the pingpong effect and when i click on an image, the fade effect, without losing the pingpong effect on the other images?
PS: to create the first effect I created a single animation that changes the scale of each image at the same time, while for the fade effect, each image has its own animation. Images can disappear following the correct sequence.
Sorry for my bad English, I hope I have explained myself as well as possible, I remain available for any misunderstandings. thank you
in case anyone has the same problem as me, I was able to solve it by adding a layer. In the first layer I run the fade animation, while in the second the pingpong effect. It is important to set the weight of the layer.

Panel/Sprites won't update after being set inactive then reactivated

I've run through an entire fault tree trying to diagnose this, with no joy.
I'm writing a 2D card game in Unity/C#. I have four panels (one per player) that hold the cards, name, discard pile, etc. for each player. I need to have a pop-up dialog panel come up over the player panels when the user wants to change options. For some reason, I cannot get the pop-up to appear over the card sprites (it does appear over the other elements: interior panels, images, text boxes, etc.). I've tried adjust the Zpos for the dialog box panel, but nothing changes. That's problem one, but it leads to a more worrisome issue.
The bigger issue is this. Since the options panel won't display in front of the players' cards, I thought I'd just deactivate the player panels, display the dialog, then deactivate it and re-activate the player panels when it's closed. That works fine: for three of the panels. The fourth panel comes back on in its previous state, but the graphics on it will no longer update.
I've debugged and discovered the new cards are being handled correctly (sprite names changing, etc.), the discard pile is being updated, the player's name is being highlight/de-highlighted as the game progress, but none of it is appearing! It's visually stuck in the state it was when I deactivated it.
Investigating further, I've determined the error crops up anytime I deactivate and the re-activate that player's panel, whether I do it via the inspector (attaching those events to a button click), or do it in-line in script. I don't even have to open the options dialog box: I put SetActive(false/true) statements in my game code and it immediately kills the graphics updating for that panel. The sprites, text, etc. remain as they were when I deactivated and will not update.
player3Obj.gameObject.SetActive(false)
player3Obj.gameObject.SetActive(true);
Doing that to the other three panels has no effect and works fine. I see nothing different about panel 4. In fact, I can deactivate only one of its card sprites, and when I turn it back on, it is now "stuck" and won't update, even though all the other cards in that player's hand will. Same if I deactivate/re-activate one of the text fields. It will no longer update, but everything else does.
I've got no exception errors or anything, but this looks to me like some kind of memory problem, though I can't imagine what. It shows up in my Android build, no it's not specific to my machine. I'm throwing this question out there hoping someone has seen something similar.
If nothing else, maybe someone can tell me how to get my options panel to display over the card sprites. But I hate to leave a problem undiagnosed: they have a way of coming back and biting.
Update
Here's the code that isn't getting displayed. The cardBackSprit values are updating correctly, as is the gameObjectSprite, but the image onscreen isn't changing:
void DrawCardBitmap2(int Player, int cardSpot, int cardIndex)
{
string spriteObjectName;
spriteObjectName = "Sprite_Player" + Player + "_" + cardSpot;
gameObjectSprite = GameObject.Find(spriteObjectName);
gameObjectSprite.GetComponent<SpriteRenderer>().sprite = cardBackSprite;
}
There's a lot to unpack here. Let's break down your post into a series of questions:
1. I cannot get the pop-up to appear over the card sprites
It sounds like you're using the UI Canvas in Unity to handle your info panels for your players, but gameObjects for other elements. This is good, but the UI Canvas' sorting order is a bit different from standard game objects.
UI elements in the Canvas are drawn in the same order they appear in the Hierarchy. The first child is drawn first, the second child next, and so on. If two UI elements overlap, the later one will appear on top of the earlier one.
In order for your pop-up to appear above other elements in your canvas, they need be be higher in your scene's Canvas hierarchy.
Important to note: Canvases set to any Screen Space render mode will render over other game objects in the scene. Canvases set to World Space will render in their world position in the scene. The only render mode that uses Z Position to choose sorting order is World Space, but this is not my recommended solution to your problem.
My recommended solution:
Break your UI into multiple different canvases. Specifically, move your pop-up to a different canvas and place it higher in the scene hierarchy than your card sprites. When you enable/disable or move the pop-up, it will now appear over the card sprites.
2. Four panels (one per player) that hold the cards
From context and some of your code, it sounds like you have SpriteRenderers in your UI Canvas. This is known to be a complex rendering problem. Common advice involves using 2 cameras for rendering, and use camera depth to raise sprites over UI elements. However, redesigning your UI canvas is probably simpler.
3. Using GameObject.Find and complex strings at runtime
GameObject.Find is not performant, and it's not robust. It looks through all elements in the scene and returns the first object it finds with that name.
This poses a few problems:
You cannot have game objects with the same name anywhere in your hierarchy, even if they are nested in different places.
CPU cycles are wasted searching through all objects.
Hidden dependencies on object names that only show up during runtime.
Here's a great blog post on some better practices. I recommend using the [SerializeField] attribute and configuring it via inspector.
4. Canvas isn't updating when objects inside of it change
You can consider invoking Canvas.ForceUpdateCanvases() in LateUpdate(). This is more of a hack than an actual solution, but if this solves your problem it is likely an issue with canvas rendering. If this does not solve your problem, then this problem is likely elsewhere in your code that is currently not provided.
A canvas performs its layout and content generation calculations at the end of a frame, just before rendering, in order to ensure that it's based on all the latest changes that may have happened during that frame. This means that in the Start callback and the first Update callback, the layout and content under the canvas may not be up-to-date.

UI GameObject not visible in scene tab

I am working on a networking game where a roomListItem shows all the available gamerooms online. for every gameroom a button gets instantiated inside the roomListItem and this happens as intended, the problem is that the button that gets instentiated is invisible, i can resize it but still can't see it.
i already tried moving the button at the bottom of the hierarchy but it's still not visible.
The problem is that you are masking all the content, there is an object named Viewport that contains a mask component, this component causes that all UI elements below it will be masked, you can try:
Remove it.
Change the sprite for another one if you like to mask it in some way.
GIF here: https://share.getcloudapp.com/YEu8JPXN

Zooming doesn't work in Unity although FOV changes

I am working on a 2D project and I want to zoom in my map by scrollwheel. I am sure that my code is working (because during the play mode, field of view changes when scrollwheel is rotated) but no change on the screen is observed.
Besides, during play mode even if I change the field of view manually (from the editor), the screen view remains same. That is, although field of view is observed to be seen changing but the screen view is not.
What are the possible reasons for that?
Here is the screenshot of the editor attached:
Possibly because you're using screen space canvas. Put the canvas in the world space for field of view to have any effect.

Get Swift4 SCNScene 30 snapshots per second and draw them smoothly on external screen in UIImageView

I have one little problem, maybe wrong approach. I created an ipad app (swift4) with SCNView, it works great, all transformations, lights, gestures... But I would like to display this scene on an external screen, connected by air play, not just to duplicate what i see on ipad. The SCNView is in UIView with another ui elements, that i don't want to display on external screen. How to get it work with smooth transformations on both screens? I have tried to clone scene nodes, but it did't work (maybe wrong code), another solution was to create new SCNView and load new scene, but then i don't know how to detect gestures to get the same transformations as on the main ipad display, and i think it costs more gpu calculations. Last solution was to snapshot the view and on an external screen display just the image, but again, i don't know how to listen to gestures or camera movements and make it smooth. Do you have few minutes to write me an example with the solution? With proper way, listeners on SCNView or different approach? I will be very grateful to you!
If you don't want to use AirPlay you may try ReplayKit. It allows you to stream your screen content and you can create TV app that will display it.
I may don't have the solution but I think is very possible to setup Airplay just for stream what you want, hidding UI elements.
Duplication or buffering frames to video seems such expensive approach but not that crazy... just check how ARKit does it.