11 min read

(For more resources related to this topic, see here.)

Creating a picture-in-picture effect

Having more than one viewport displayed can be useful in many situations. For example, you might want to show simultaneous events going on in different locations, or maybe you want to have a separate window for hot-seat multiplayer games. Although you could do it manually by adjusting the Normalized Viewport Rect parameters on your camera, this recipe includes a series of extra preferences to make it more independent from the user’s display configuration.

Getting ready

For this recipe, we have prepared a package named basicLevel containing a scene. The package is in the 0423_02_01_02 folder.

How to do it…

To create a picture-in-picture display, just follow these steps:

  1. Import the basicLevel package into your Unity project.
  2. In the Project view, open basicScene, inside the folder 02_01_02. This is a basic scene featuring a directional light, a camera, and some geometry.
  3. Add the Camera option to the scene through the Create dropdown menu on top of the Hierarchy view, as shown in the following screenshot:

  4. Select the camera you have created and, in the Inspector view, set its Depth to 1:

  5. In the Project view, create a new C# script and rename it PictureInPicture.
  6. Open your script and replace everything with the following code:

    using UnityEngine;
    public class PictureInPicture: MonoBehaviour {
    public enum HorizontalAlignment{left, center, right};
    public enum VerticalAlignment{top, middle, bottom};
    public HorizontalAlignment horizontalAlignment =
    HorizontalAlignment.left;
    public VerticalAlignment verticalAlignment =
    VerticalAlignment.top;
    public enum ScreenDimensions{pixels, screen_percentage};
    public ScreenDimensions dimensionsIn = ScreenDimensions.
    pixels;
    public int width = 50;
    public int height= 50;
    public float xOffset = 0f;
    public float yOffset = 0f;
    public bool update = true;
    private int hsize, vsize, hloc, vloc;
    void Start (){
    AdjustCamera ();
    }
    void Update (){
    if(update)
    AdjustCamera ();
    }
    void AdjustCamera(){
    if(dimensionsIn == ScreenDimensions.screen_percentage){
    hsize = Mathf.RoundToInt(width * 0.01f * Screen.
    width);
    vsize = Mathf.RoundToInt(height * 0.01f * Screen.
    height);
    } else {
    hsize = width;
    vsize = height;
    }
    if(horizontalAlignment == HorizontalAlignment.left){
    hloc = Mathf.RoundToInt(xOffset * 0.01f *
    Screen.width);
    } else if(horizontalAlignment == HorizontalAlignment.
    right){
    hloc = Mathf.RoundToInt((Screen.width - hsize)
    - (xOffset * 0.01f * Screen.width));
    } else {
    hloc = Mathf.RoundToInt(((Screen.width * 0.5f)
    - (hsize * 0.5f)) - (xOffset * 0.01f * Screen.height));
    }
    if(verticalAlignment == VerticalAlignment.top){
    vloc = Mathf.RoundToInt((Screen.height -
    vsize) - (yOffset * 0.01f * Screen.height));
    } else if(verticalAlignment == VerticalAlignment.
    bottom){
    vloc = Mathf.RoundToInt(yOffset * 0.01f *
    Screen.height);
    } else {
    vloc = Mathf.RoundToInt(((Screen.height *
    0.5f) - (vsize * 0.5f)) - (yOffset * 0.01f * Screen.height));
    }
    camera.pixelRect = new Rect(hloc,vloc,hsize,vsize);
    }
    }

  7. In case you haven’t noticed, we are not achieving percentage by dividing numbers by 100, but rather multiplying them by 0.01. The reason behind that is performance: computer processors are faster multiplying than dividing.

  8. Save your script and attach it to the new camera that you created previously.
  9. Uncheck the new camera’s Audio Listener component and change some of the PictureInPicture parameters: change Horizontal Alignment to Right, Vertical Alignment to Top, and Dimensions In to pixels. Leave XOffset and YOffset as 0, change Width to 400 and Height to 200, as shown below:

  10. Play your scene. The new camera’s viewport should be visible on the top right of the screen:

How it works…

Our script changes the camera’s Normalized Viewport Rect parameters, thus resizing and positioning the viewport according to the user preferences.

There’s more…

The following are some aspects of your picture-in-picture you could change.

Making the picture-in-picture proportional to the screen’s size
If you change the Dimensions In option to screen_percentage, the viewport size will be based on the actual screen’s dimensions instead of pixels.

Changing the position of the picture-in-picture
Vertical Alignment and Horizontal Alignment can be used to change the viewport’s origin. Use them to place it where you wish.

Preventing the picture-in-picture from updating on every frame
Leave the Update option unchecked if you don’t plan to change the viewport position in running mode. Also, it’s a good idea to leave it checked when testing and then uncheck it once the position has been decided and set up.

See also

  • The Displaying a mini-map recipe.

Switching between multiple cameras

Choosing from a variety of cameras is a common feature in many genres: race sims, sports sims, tycoon/strategy, and many others. In this recipe, we will learn how to give players the ability of choosing an option from many cameras using their keyboard.

Getting ready

In order to follow this recipe, we have prepared a package containing a basic level named basicScene. The package is in the folder 0423_02_01_02.

How to do it…

To implement switchable cameras, follow these steps:

  1. Import the basicLevel package into your Unity project.
  2. In the Project view, open basicScene from the 02_01_02 folder. This is a basic scene featuring a directional light, a camera, and some geometry.
  3. Add two more cameras to the scene. You can do it through the Create drop-down menu on top of the Hierarchy view. Rename them cam1 and cam2.
  4. Change the cam2 camera’s position and rotation so it won’t be identical to cam1.
  5. Create an Empty game object by navigating to Game Object | Create Empty. Then, rename it Switchboard.
  6. In the Inspector view, disable the Camera and Audio Listener components of both cam1 and cam2.

  7. In the Project view, create a new C# script. Rename it CameraSwitch and open it in your editor.
  8. Open your script and replace everything with the following code:

    using UnityEngine;
    public class CameraSwitch : MonoBehaviour {
    public GameObject[] cameras;
    public string[] shortcuts;
    public bool changeAudioListener = true;
    void Update (){
    int i = 0;
    for(i=0; i<cameras.Length; i++){
    if (Input.GetKeyUp(shortcuts[i]))
    SwitchCamera(i);
    }
    }
    void SwitchCamera ( int index ){
    int i = 0;
    for(i=0; i<cameras.Length; i++){
    if(i != index){
    if(changeAudioListener){
    cameras[i].
    GetComponent<AudioListener>().enabled = false;
    }
    cameras[i].camera.enabled = false;
    } else {
    if(changeAudioListener){
    cameras[i].
    GetComponent<AudioListener>().enabled = true;
    }
    cameras[i].camera.enabled = true;
    }
    }
    }
    }

  9. Attach CameraSwitch to the Switchboard game object.
  10. In the Inspector view, set both Cameras and Shortcuts size to 3. Then, drag the scene cameras into the Cameras slots, and type 1, 2, and 3 into the Shortcuts text fields, as shown in the next screenshot.

  11. Play your scene and test your cameras.

How it works…

The script is very straightforward. All it does is capture the key pressed and enable its respective camera (and its Audio Listener, in case the Change Audio Listener option is checked).

There’s more…

Here are some ideas on how you could try twisting this recipe a bit.

Using a single-enabled camera

A different approach to the problem would be keeping all the secondary cameras disabled and assigning their position and rotation to the main camera via a script (you would need to make a copy of the main camera and add it to the list, in case you wanted to save its transform settings).

Triggering the switch from other events

Also, you could change your camera from other game object’s scripts by using a line of code, such as the one shown here:

GameObject.Find("Switchboard").GetComponent("CameraSwitch").
SwitchCamera(1);

See also

  • The Making an inspect camera recipe.

Customizing the lens flare effect

As anyone who has played a game set in an outdoor environment in the last 15 years can tell you, the lens flare effect is used to simulate the incidence of bright lights over the player’s field of view. Although it has become a bit overused, it is still very much present in all kinds of games. In this recipe, we will create and test our own lens flare texture.

Getting ready

In order to continue with this recipe, it’s strongly recommended that you have access to image editor software such as Adobe Photoshop or GIMP. The source for lens texture created in this recipe can be found in the 0423_02_03 folder.

How to do it…

To create a new lens flare texture and apply it to the scene, follow these steps:

  1. Import Unity’s Character Controller package by navigating to Assets | Import Package | Character Controller.
  2. Do the same for the Light Flares package.
  3. In the Hierarchy view, use the Create button to add a Directional Light effect to your scene.
  4. Select your camera and add a Mouse Look component by accessing the Component | Camera Control | Mouse Look menu option.
  5. In the Project view, locate the Sun flare (inside Standard Assets | Light Flares), duplicate it and rename it to MySun, as shown in the following screenshot:

  6. In the Inspector view, click Flare Texture to reveal the base texture’s location in the Project view. It should be a texture named 50mmflare.
  7. Duplicate the texture and rename it My50mmflare.

  8. Right-click My50mmflare and choose Open. This should open the file (actually a.psd) in your image editor. If you’re using Adobe Photoshop, you might see the guidelines for the texture, as shown here:

  9. To create the light rings, create new Circle shapes and add different Layer Effects such as Gradient Overlay, Stroke, Inner Glow, and Outer Glow.
  10. Recreate the star-shaped flares by editing the originals or by drawing lines and blurring them.

  11. Save the file and go back to the Unity Editor.
  12. In the Inspector view, select MySun, and set Flare Texture to My50mmflare:

  13. Select Directional Light and, in the Inspector view, set Flare to MySun.

  14. Play the scene and move your mouse around. You will be able to see the lens flare as the camera faces the light.

How it works…

We have used Unity’s built-in lens flare texture as a blueprint for our own. Once applied, the lens flare texture will be displayed when the player looks into the approximate direction of the light.

There’s more…

Flare textures can use different layouts and parameters for each element. In case you want to learn more about the Lens Flare effect, check out Unity’s documentation at http://docs. unity3d.com/Documentation/Components/class-LensFlare.html.

Making textures from screen content

If you want your game or player to take in-game snapshots and apply it as a texture, this recipe will show you how. This can be very useful if you plan to implement an in-game photo gallery or display a snapshot of a past key moment at the end of a level (Race Games and Stunt Sims use this feature a lot).

Getting ready

In order to follow this recipe, please import the basicTerrain package, available in the 0423_02_04_05 folder, into your project. The package includes a basic terrain and a camera that can be rotated via a mouse.

How to do it…

To create textures from screen content, follow these steps:

  1. Import the Unity package and open the 02_04_05 scene.
  2. We need to create a script. In the Project view, click on the Create drop-down menu and choose C# Script. Rename it ScreenTexture and open it in your editor.
  3. Open your script and replace everything with the following code:

    using UnityEngine;
    using System.Collections;
    public class ScreenTexture : MonoBehaviour {
    public int photoWidth = 50;
    public int photoHeight = 50;
    public int thumbProportion = 25;
    public Color borderColor = Color.white;
    public int borderWidth = 2;
    private Texture2D texture;
    private Texture2D border;
    private int screenWidth;
    private int screenHeight;
    private int frameWidth;
    private int frameHeight;
    private bool shoot = false;
    void Start (){
    screenWidth = Screen.width;
    screenHeight = Screen.height;
    frameWidth = Mathf.RoundToInt(screenWidth * photoWidth *
    0.01f);
    frameHeight = Mathf.RoundToInt(screenHeight * photoHeight
    * 0.01f);
    texture = new Texture2D (frameWidth,frameHeight,TextureFor
    mat.RGB24,false);
    border = new Texture2D (1,1,TextureFormat.ARGB32, false);
    border.SetPixel(0,0,borderColor);
    border.Apply();
    }
    void Update (){
    if (Input.GetKeyUp(KeyCode.Mouse0))
    StartCoroutine(CaptureScreen());
    }
    void OnGUI (){
    GUI.DrawTexture(new Rect((screenWidth*0.5f)-
    (frameWidth*0.5f) - borderWidth*2,((screenHeight*0.5f)-
    (frameHeight*0.5f)) - borderWidth,frameWidth + borderWidth*2,borde
    rWidth),border,ScaleMode.StretchToFill);
    GUI.DrawTexture(new Rect((screenWidth*0.5f)-
    (frameWidth*0.5f) - borderWidth*2,(screenHeight*0.5f)+(frameHeigh
    t*0.5f),frameWidth + borderWidth*2,borderWidth),border,ScaleMode.
    StretchToFill);
    GUI.DrawTexture(new Rect((screenWidth*0.5f)-
    (frameWidth*0.5f)- borderWidth*2,(screenHeight*0.5f)-(frameHeight*
    0.5f),borderWidth,frameHeight),border,ScaleMode.StretchToFill);
    GUI.DrawTexture(new Rect((screenWidth*0.5f)+(frameWidth*0.
    5f),(screenHeight*0.5f)-(frameHeight*0.5f),borderWidth,frameHeight
    ),border,ScaleMode.StretchToFill);
    if(shoot){
    GUI.DrawTexture(new Rect (10,10,frameWidth*thumbPropo
    rtion*0.01f,frameHeight*thumbProportion* 0.01f),texture,ScaleMode.
    StretchToFill);
    }
    }
    IEnumerator CaptureScreen (){
    yield return new WaitForEndOfFrame();
    texture.ReadPixels(new Rect((screenWidth*0.5f)-(frameWidth
    *0.5f),(screenHeight*0.5f)-(frameHeight*0.5f),frameWidth,frameHeig
    ht),0,0);
    texture.Apply();
    shoot = true;
    }
    }

  4. Save your script and apply it to the Main Camera game object.
  5. In the Inspector view, change the values for the Screen Capturecomponent, leaving Photo Width and Photo Height as 25 and Thumb Proportion as 75, as shown here:

  6. Play the scene. You will be able to take a snapshot of the screen (and have it displayed on the top-left corner) by clicking the mouse button.

How it works…

Clicking the mouse triggers a function that reads pixels within the specified rectangle and applies them into a texture that is drawn by the GUI.

There’s more…

Apart from displaying the texture as a GUI element, you could use it in other ways.

Applying your texture to a material
You apply your texture to an existing object’s material by adding a line similar to
GameObject.Find(“MyObject”).renderer.material.mainTexture = texture;
at the end of the CaptureScreen function.

Using your texture as a screenshot
You can encode your texture as a PNG image file and save it. Check out Unity’s documentation on this feature at http://docs.unity3d.com/Documentation/ScriptReference/ Texture2D.EncodeToPNG.html.

LEAVE A REPLY

Please enter your comment!
Please enter your name here