How to apply a postprocess effect to a UI element - unity3d

I have a post-process effect that uses Unity's Graphics.Blit to pixelate or apply a crt-screen effect to a scene. There are some UI elements that display after the fact (basically making it not a true post process, but let's put that aside for a moment).
Now, I want to apply a second process that performs a screen wipe and transitions out one scene for another. This time I want to include the UI buttons in the effect.
I've looked into using a render texture and then rendering to a second camera, but I feel like there is a smarter/more accurate way to handle this.
1st version of this question:
Can I selectively include the screenspace-overlay UI in the script that applies the post process?
or, 2nd version of this question
Is there a trick to getting the render texture to preserve resolution and display accurately (i.e.: without lost quality) when re rendering to a second camera?

Related

Unity - Post process foreground, but leave background as is

I am using Unity 2019.3.5f1 and I am using the Universal Render Pipeline (URP).
I am trying to use the post processing in URP for the foreground only (in my case, the players), and I want the leave the background (which in my case, is just a quad with a texture), as is.
I have tried using the Camera Stack but it wont work for me because the overlay camera can't have post processing effects according to the documentation.
The only solution that I could come up with is create the some sort of custom render which:
Render the background to buffer A.
Render the foreground to buffer B, and save the depth.
Combine the two using a shader that gets both textures, and the depth texture, and based on the depth, takes buffer A or buffer B.
The problem with this I believe is that I cant use it with the post processing for Unity.
Any idea what I can do?
EDIT:
I tried another thing in Unity which seem to not be working (might be a bug):
I created 3 cameras: Foreground Camera, Depth Camera (only render the foreground), and a Background Camera.
I set up the Depth camera so it will render to a render texture and, indeed now I have a render texture with the proper depth I need.
Now, from here everything went wrong, there seem to be odd things happening when using Unity new Post processing (the built in one):
The Foreground Camera is set to Tag=MainCamera, and when I enable Post Processing and add an effect, indeed we can see it. (as expected)
The Background Camera is essentially a duplicate of the Foreground one, but with Tag=Untagged, I use the same options (enabled Post).
Now, the expected thing is we see the Background Camera with effects like Foreground, but no:
When using Volume Mask on my background layer, the Post processing just turns off, no effect at all no matter what (and I have set my background the Background layer).
When I disable the Foreground Camera (or remove its tag) and set the Background Camera to MainCamera, still nothing changes, the post still wont work.
When I set Volume Mask to Default (or everything), the result is shown ONLY in the scene view, I tried rendering the camera to a RenderTexture but still, you clearly see no effect applied!

Edit camera center directly and instantly in Mapbox GL JS

I want to edit the camera center directly in Mapbox GL JS. I know about the existence of the map.easeTo and map.flyTo methods but I do not want to use them because I have to do multiple requests to them (around 60 per second), which in turn results in decreased performance because transitions are stacking upon each other (only an assumption from my side).
Essentially, instead of doing map.flyTo or map.easeTo, I want to do change the camera center directly and instantly. Alternatively, I would like to know if it is possible to remove all the previous transitions before calling map.flyTo or map.easeTo.
To update the camera without an animation use Map#jumpTo.
If you're trying to do your own smooth camera animation you might want to also use requestAnimationFrame like in https://docs.mapbox.com/mapbox-gl-js/example/animate-camera-around-point/

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.

Unity shader to render objects with same material to subsequent GrabPasses

Overview
I'm working on a shader in Unity 2017.1 to enable UnityEngine.UI.Image components to blur what is behind them.
As some of the approaches in this Unity forum topic, I use GrabPasses, specifically a tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(<uv with offset>)) call to look up the pixels that I use in my blur summations. I'm doing a basic 2-pass box blur, and not looking to optimize performance right now.
This works as expected:
I also want to mask the blur effect based on the image alpha. I use tex2D(_MainTex, IN.uvmain) to look up the alpha color of the sprite on the pixel I am calculating the blur for, which I then combine with the alpha of the blur.
This works fine when working with just a single UI.Image object:
The Problem
However when I have multiple UI.Image objects that share the same Material created from this shader, images layered above will cut into the images below:
I believe this is because objects with the same material may be drawn simultaneously and so don't appear in each other's GrabPasses, or at least something to that effect.
That at least would explain why, if I duplicate the material and use each material on its own object, I don't have this problem.
Here is the source code for the shader: https://gist.github.com/JohannesMP/8d0f531b815dfad07823d44bc12b8112
The Question
Is there a way to force objects of the same material to draw consecutively and not in parallel? Basically, I would like the result of a lower object's render passes to be visible to the grab pass of subsequent objects.
I could imagine creating a component that dynamically instantiates materials to force this, or using render textures, but I would really like a solution that doesn't require adding components or creating multiple materials to swap out.
I would love a solution that is entirely self-contained within one shader/one material but is unsure if this is possible. I'm still only starting to get familiar with shaders so I'm positive there are some features I am not familiar with.
It turns out that it was me re-drawing what I grabbed from the _GrabTexture that was causing the the issue. By correctly handling the alpha logic there I was able to get exactly the desired behavior:
Here is the updated sourcecode: https://gist.github.com/JohannesMP/7d62f282705169a2855a0aac315ff381
As mentioned before, optimizing the convolution step was not my priority.

How to create a trail effect in a rendertexture?

I'm trying to create a cumulative trail effect in a render texture. By cumulative I mean that the render texture would show the last few frames overlaid on each other. Currently, when my camera outputs to a render texture it completely overwrites whatever was there previously.
Let me know if I can clarify anything.
Thanks!
You could set the clear flag on the camera to Don't clear. This will prevent the clearing of previous frame on your camera and then will create this overlapping kinda like Flash movement style.
The issue is that everything will be kept on screen so if only the character moves then it is ok but if the camera moves then the effect also applies to environment and your scene becomes a big blur.
You could have two cameras for the effect, each with different rendering layers. One takes care of the items that should not have the effect and one takes care of those that are considered for the effect. This way you can apply the effect on characters and ignore the environment, if that is required else just go with one camera.