How to create blur effect to all the scene except for one object (focus on that object)? - unity3d

I want to create a blur effect similar to the picture below:
the picture is taken from this site:
https://forum.unity.com/threads/how-to-blur-specific-layers-only.555520/
I tried the post-processing profile and played around with the depth of field in the post-processing volume but it blurs all the scene.
I came across a YouTube Video that explains how to implement similar results to what I am looking for but things have changed drastically in the settings. For example, at 1:57 (minute and 57 seconds) he clicks on Add Additional Camera Data which I am struggling to find in the latest versions of LWRP.
I am using Unity version 2019.2.9f1
How can I achieve the result in the picture above? (Blurring all the scene except for one object)
Your guidance will be appreciated.
NOTE: My project is in VR using SteamVR and VRTK

Though your question is a bit broad I took some time to show you how it can be done.
First of all you will need to import the Post Processing package via the PackageManager
Window → PackageManager
Make sure to be in the All Packages view, search for post, find the Post Processing package and hit Install
Now first of all go to the Layer settings (Layers → Edit Layers)
and add two additional Layers: e.g. PostProcessing and Focused
Now to the cameras. Afaik it makes no difference whether you are in VR or not, usually you have one MainCamera that is moved along with your headset. If there should be two of them in your project setup just repeat the same steps for the second camera.
Make sure the MainCamera doesn't render the two added Layers → remove them from the Culling Mask
Add a new Camera FocusCamera as child to the existing MainCamera. This way it is automatically moved along with the main Camera.
RightClick on MainCamera &rightarrow Camera
It should have all the settings equal to the MainCamera except:
Clear Flags : Don't Clear
If you set it to Depth Only the focused object will always be rendered on top of everything, even if it is actually behind other objects in 3D space. You decide which effect you want here ;)
CullingMask : only Focused
Depth : Anything higher than the MainCamera so this camera is rendered on top of it
Make sure to remove the AudioListener component.
Finally add a new PostProcessingVolume to the scene. I would add it as child to the FocusCamera! Why? - Because this way it is automatically disabled together with the FocusCamera!
RightClick on FocusCamera → 3D Object → Post Processing Volume
Set its Layer to the added PostProcessing
enable Is Global so the distance to the volume doesn't matter and add a new profile by hitting new → Unity → Depth of field
In your case you want to overwrite the Focus Distance so check the box on the left and set a value close to the camera like e.g. 0.5
Until now nothing has really changed in your scene.
Now go to the MainCamera and, a component PostProcessingLayer and set the Layer to our added layer PostProcessing
Now everything should be blurred in your scene!
Almost ready to go! Now Disable the FocusCamera and add this script to it
using UnityEngine;
public class FocusSwitcher : MonoBehaviour
{
public string FocusedLayer = "Focused";
private GameObject currentlyFocused;
private int previousLayer;
public void SetFocused(GameObject obj)
{
// enables this camera and the postProcessingVolume which is the child
gameObject.SetActive(true);
// if something else was focused before reset it
if (currentlyFocused) currentlyFocused.layer = previousLayer;
// store and focus the new object
currentlyFocused = obj;
if (currentlyFocused)
{
previousLayer = currentlyFocused.layer;
currentlyFocused.layer = LayerMask.NameToLayer(FocusedLayer);
}
else
{
// if no object is focused disable the FocusCamera
// and PostProcessingVolume for not wasting rendering resources
gameObject.SetActive(false);
}
}
// On disable make sure to reset the current object
private void OnDisable()
{
if (currentlyFocused) currentlyFocused.layer =previousLayer;
currentlyFocused = null;
}
}
This will allow you to focus a certain GameObject on runtime by changing its layer to the Focused layer we added, the only one that is rendered by the FocusCamera. So this object will be rendered on top of the image without any blur effect!
For demonstration I just added this simple script to every cube object in order to enable focus on mouse enter and disable it on mouse exit:
using UnityEngine;
public class FocusMe : MonoBehaviour
{
[SerializeField] private FocusSwitcher focus;
private void OnMouseEnter()
{
focus.SetFocused(gameObject);
}
private void OnMouseExit()
{
// reset the focus
// in the future you should maybe check first
// if this object is actually the focused one currently
focus.SetFocused(null);
}
}
And here is what it looks like
as said I don't know exactly what your VR setup looks like. If you have to MainCameras simply add two child cameras to them. You still will need only one PostProcessingVolume and only one FocusSwitcher so you would probably move them to another object and handle the camera disabling etc differently but I hope the idea gets clear enough.

Use a separate camera for objects you don't want to blur and set a higher depth value.
Set the ClearFlags to depth only and in the CullingMask select the layer of that one object(or more objects). Obviously you would require to have a different layer for unblurred objects.

Related

Unity 3d OnClick to ignore specific layer (or fire only on specific laye

Is there a way to make standard unity OnClick even fire while ignoring specific layers?
For example, i have army of soldiers on layer "Units" and ground on Layer "Ground". When i click on soldier, it gets selected. Then i click on the ground, soldier moves there. But if i click on the ground obscured by another soldier, it fires even for that soldier rather than ground, cos he is closer to the camera.
Can i ignore "Units" layer without rewriting whole mouse click even handling and using my custom raycast?
EDIT:
code is here, dont thnk it will show anything but
static public void Interact2(Cell target) //this fires from OnClick
{
if (GameLogic.Mode == mode.move)
{
grid.MoveTo(target);
if (selected.actionsAvilable[action.move])
selected.actionsAvilable[action.move] = false;
else
selected.actionsAvilable[action.standard] = false;
GameLogic.Mode = GameLogic.mode.normal;
}
}
MORE EDIT:
void OnMouseDown() {
if (!UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
GameLogic.Interact2(this);
}
The PhysicsRaycaster/PhysicsRaycaster2D/GraphicsRaycaster components have an Event Mask property which allows you to limit the layers they raycast against. You should update that property from code when you want to block/allow certain layers.

How do I replace a sprite in unity with another one?

Okay so I've been making a 2d platformer and had a terrible image/sprite for my player. Now I've got a better one and want to just replace the images but keep all the same values and data/scripts etc.
I've been trying to figure it out for awhile but to no avail. Thanks for any help
If you want to permanently change a sprite on your prefabs/objects you can drag the new sprite from your asset folder to into the "Sprite Renderer" Component of the object you want to change, replacing whatever is currently in the sprite box. Check out this image to see exactly where you want to drag the sprite:
O you can change it via script using a public variable:
public class ChangeSprite: MonoBehaviour
{
public Sprite newSprite;
private void ChangeSprite(){
gameObject.GetComponent<SpriteRenderer>().sprite == newSprite;
}
}
One way to do it, not sure it is the best way but it works, is to:
- import your new Sprite (let's call it SpriteB)
- select the GameObject where you have been using your first sprite (SpriteA)
- in the "Sprite Renderer" component of your selected GameObject, replace "Sprite=SpriteA" with your new sprite so that "Sprite=SpriteB"
Obviously you will have to repeat the operation for every GameObject where you may have used SpriteA.

How to ignore mouse click at background layers or objects?

I'm developing simple fix it kind of games. Here if i clicked at the object it will instantiate new layer in front of the background layer. But the problem is when i click on the top layer the click also affects the background layer. How to avoid it? I used layer based collision and collider on the top layer but no use.
I recommend using a raycast. When you click, cast from the mouse cursor into the scene and check for the object's tag (or other attributes if you need to). This way, you do not have to use OnMouseOver() or OnMouseDown() on many different objects, and have the logic in a single place.
It is also more flexible, for example you can specify the range of the raycast as well as ignoring certain layers.
3D or 2D?
check this out: OnMouseDown on box collider 2D not firing
I would also check for specific tags and create different modes to check them, like.
int mode=0;
In 'mode 0' would check the collision for #basicLayers,
in 'mode 1' would check for #topLayers
Like (using the above link answer +suggestion):
void check3DObjectClicked ()
{
if (Input.GetMouseButtonDown (0)) {
RaycastHit hitInfo = new RaycastHit ();
if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hitInfo)) {
Debug.Log ("Object Hit is " + hitInfo.collider.gameObject.name);
switch(mode){
case 0:
if (hitInfo.collider.gameObject.CompareTag ("basicLayerObject1"){
mode=1;
//do stuff
}
break;
case 1:
if (hitInfo.collider.gameObject.CompareTag ("createdTopLayerObj1"){
mode=2;
//do stuff
}else if (hitInfo.collider.gameObject.CompareTag ("quitTopLayer"){
mode=0;
//do stuff
}
//ignoring basicLayers tagged objects on background.
break;
}
}
}
}
hope this make sense somehow.
Before i get the answer i did this by using animation. If i'm interacting with the top layer then i removed the background layer from background after the top layer work is done then the i placed background layer. Is this good or bad?

A panel to change 3d object properties when right click on it

I'm building a UI system to edit selected 3D objects. I have spheres on the screen and I want to be able to edit their proprieties (radius for example). In order to do that I want the user to be able to click on a sphere and then it show a panel next to the object. When the user changes slider value the radius of the sphere which as been clicked on change. Using the new unity event system, I think it's easy to achieve, but I'm a new to unity and even if I know the basic I don't know how to organize this properly.
At the end my goal would be to select multiple sphere, right click and edit the radius to all selected spheres.!
Any tips on how to do that ? Sorry for my poor english. Thanks
Here's how you can do it:
Keep a bool for tracking if the object is selected, say, bool _isSelected
Toggle this boolean in the OnMouseUpAsButton() function. This function is called when you click on an object and release that click on the same object. Unity's OnMouseXXX() interfaces are very good for handling mouse events. You just need to define this function in the sphere objects' script.
Put together a Slider and arrange its value interval from editor. Define a function that will edit the scale value of the spheres and tie that function to that slider.
Below you can see an example of how I did that in a game of mine.
Unity simply catches the slider's value if you provide it with a public void _f(float val). It will appear on the top of the list as "Dynamic float". So, in your case, your slider update function should look like this:
public void SphereScaleSliderUpdate(float val)
{
foreach (GameObject sphere in GameObject.FindGameObjectsWithTag("your tag here"))
{
if (sphere.IsSelected) // don't forget to provide a public getter for _isSphere variable
{
sphere.transform.localScale = new Vector3(val, val, val);
}
}
}
Also, you need to create another script for toggling the menu(Canvas/Panel(optional)) that contains the slider, and you may add it to another object, like a UIManager. Assign the Canvas in the game hierarchy to a variable in that script, and then scan for RClick in the Update() function of the UIManager.
.
void Update()
{
if (Input.GetMouseButtonDown(1) // RClick event
{
// makes the slider appear through enabling canvas
_canvasHandle.enabled = true;
}
}

Show/ hide Unity 3D elements

I hope I am posting in the correct section. I know that it is possible to write a custom code in Unity so I have the following questions:
Imagine a house model in Unity. Would it be possible to have a code which helps to hide/unhide certain objects? For example, letter "W" would hide/unhide all windows, letter "C" would hide/unhide all columns etc.
If it would be possible to develop a code for that, what would be the workflow? How would Unity know what is window and what is door?
Taking one step further.. Would it be possible to have a code that unhides the next step of the project. For example, the first step would be building foundations. Would it be possible to have a code that would unhide the next step, say, 1st floor floor element, with a klick of a keyboard key? And then with the same key unhide the next step which might be 1st floor walls. And would it be possible with another key go backwards?
If such code would be possible, what do you think would be the workflow? How would Unity know which element is in which step?
Yes just have a class with an array of objects to show/hide and another property for what button will do it. Then just have a method that will hide/unhide each object in that class. In the update method of a behavior just check the input and call the method of the class based on what button was pressed.
Would it be possible to have a code which helps to hide/unhide?
Yes, you can do that by calling GameObject.SetActive() function
door.SetActive(true); // door is a game object;
How would Unity know what is window and what is door?
You can give the window/door a name, then access the game object by name
var door = GameObject.Find("MyDoor") as GameObject;
Would it be possible to have a code that would show the next step, say, 1st floor floor element, with a klick of a keyboard key?
Yes, you can do that with code snippet below:
int step = 1;
void Update() {
if (Input.GetKeyDown("space")){
print("space key was pressed");
step++;
}
if(step == 1) {
// do sth
}
else if(step == 2) {
// do sth
}
}
Given the above snippet, your last answer can be easily deduced.
I see 2 ways of doing what you asked.
1st way
GameObject[] walls;
walls = GameObject.FindGameObjectsWithTag("Wall");
foreach (GameObject wall in walls)
{
wall.setActive(true);
}
What you will have to do, besides the code, is to assign to those object a correct tag (like "Wall" "Window" "WatheverYouWillNeed"). So you can easily find all objects by giving them some kind of order (with tags).
Best practice tip
You may want to create a static class "Tags", and set public constants string inside the class, with all tag names.
public static class Tags
{
public static const WINDOW_TAG = "Window";
// ... more tags
}
2nd way
If what you want to set is only "visibility", you may want to modify only camera tag rendering. It doesn't even require any cycle at all. When you want to view windows, you just tell your camera to render the tag "Window".
// Turns on Windows Layer on mask using an OR operation
private void Show()
{
camera.cullingMask |= 1 << LayerMask.NameToLayer("Window");
}
// Turn off the bit using an AND operation with the complement of the shifted int:
private void Hide()
{
camera.cullingMask &= ~(1 << LayerMask.NameToLayer("Window"));
}
It may look odd the second option, but keep in mind that the cullingMask is composed of bits, and every bit is a Layer defined by your tags. The "Everything" culling mask is 111111. If you want to see only Window, for example, and window is the last element, your culling mask would look something like 0000001
Hope it helped! :)