donderdag 7 april 2016

Noir Shader


While searching for an good Noir style Image Effect shader, I noticed that there are hardly any. There are some simple black and white ones, but not real Noir effects where the blacks are really dark and the whites are super bright. So I decided to make one myself. For these tips to work you need to know the very basics of shader. They can be found here: http://www.alanzucconi.com/2015/07/08/screen-shaders-and-postprocessing-effects-in-unity3d/

The Setup

For the stylized effect that is Noir you need two simple effects combined. First you need to make the whole camera black and white, or grayscale. Then when you have a nice grayscale effect you're not done because that is not really Noir in my opinion. So the next easy step you can take is increase the contrast. This is done so all the gray parts of the grayscale image get either black or white.

Image Effect Shader

To make the camera show everything in black and white, you need to make an Image Effect Shader (also known as Post-Processing Shader). Scroll down until you see this part:
  fixed4 frag (v2f i) : SV_Target
  {
   fixed4 col = tex2D(_MainTex, i.uv);
   // just invert the colors
   col = 1 - col;
   return col;
  }
Here is where the magic happens. Unity even provides us with an sample effect. The shader will invert the colors out of the box. However the shader as it is does nothing. You need an .cs script with it to attach it to the camera. Lucky for us this isn't very hard.

You make two references, one public and one private to Shader and Material. The shader needs to be public and the material private.
Then you make a OnRenderImage function with RenderTexture source and RenderTexture Destination passed through. In this function you check if the material reference is null, or empty. If that is the case you fill it with a new Material with the public shader in it. After that you do the Graphics.Blit magic. This is better explained on Alan Zucconi's blogpost.
 
using UnityEngine;
using System.Collections;

public class Noir : MonoBehaviour {

 public Shader NoirShader;
 private Material MyMat;

 void OnRenderImage(RenderTexture source, RenderTexture destination)
 {
  if (MyMat == null) 
  {
   MyMat = new Material (NoirShader);
  }

  Graphics.Blit (source, destination, MyMat);
 }
}

Black and White 

For the camera to see only black and white, we need to edit the part that made it invert colors earlier. The formula to make colors grayscale is to add all the colors up and devide it by 3. So Colors = Red + Green + Blue / 3. This is what that looks like:

 
fixed4 frag (v2f i) : SV_Target
 {
  fixed4 col = tex2D(_MainTex, i.uv);

  col = col.r + col.b + col.g / 3, col.a;
 
  return col;
 }
}
And voila! Your scene is black and white. Not really Noir but close. Now we need to increase the contrast. For a better grayscale effect, you can use this formula: col = col.r*.3 + col.g*.59 + col.b*.11; This one is however not recommended for the Noir style.

Increasing Contrast

For increasing contrast you need another fixed4, in my case called con for contrast. Also you need a float called Contrast, just to make it clear which one is which.

Set con.rgb to ((col.rgb - 0.5f) * max(Contrast, 0)) + 0.5f. I honestly don't know why this increases the contrast, but it does. You can see the 'Contrast' float in there. This is the intensity modifier. Contrast is in my case set to 4 but you can tweak it how you like. Finally you set col.rgb to col multiplied by con and devived by 2. That's how you make a good noir shader.
fixed4 frag (v2f i) : SV_Target
 {
 fixed4 col = tex2D(_MainTex, i.uv);
 fixed4 con;
 float Contrast = 4;

 col = col.r + col.b + col.g / 3, col.a;
 con.rgb = ((col.rgb - 0.5f) * max(Contrast, 0)) + 0.5f;
 col.rgb = col * con / 2; 

 return col;
 }
}

My next step will be, making all the red objects in the scene pop out in a bright red. I already tried that for this version but without success. Everything I tried ended up with everything red tinted or blue tinted. 
So to be continued.

To see the Shader in action I made a scene where you can walk around in all the noir goodness here.

vrijdag 1 april 2016

Juicing

This one will be rather short. But in a project I recently made we wanted a fade to white effect at every beginning and end of a level. I made a rather hacky way achieve this.
For this effect you need a plane that is in front of the camera. This is your fade 'layer'. Than for the script portion you need a public boolean called fadeOut and a public Color called color.

In the Start function you set the fadeOut boolean to false. Also set the color to the material color that the renderer picks up.

 void Start () {
  fadeOut = false;
  color = GetComponent ().material.color;
  level = Application.loadedLevel;
 }


Then in the update you check if fadeOut is true. If that's true you increase the alpha value of the color, making it visible. Then when the alpha value is 1 or more, you can run some logic like load the next level in my case.

Else (if fadeOut is false) you decrease the alpha value. When the alpha value is 0 you set it to 0, so it doesn't go way past 0.
 
void Update () 
 {
  if (fadeOut == true) 
  {
   color.a += 0.05f;
   GetComponent ().material.color = color;

   if (color.a >= 1) {
    level += 1;
    Application.LoadLevel (level);
   }
  } 
  else 
  {
   color.a -= 0.05f;
   GetComponent().material.color = color;
  }
  if (color.a <= 0)
  {
   color.a = 0;
  }
 }

To make this work you only need to set the fadeOut bool to true when you want the screen to fade to white. If the plane is already visible it will fade from white, because fadeout will be false.



vrijdag 18 maart 2016

Canvas Groups

While making UI for a game, I stumbled upon something I didn't know about. Lets say you have a pause screen and in-game UI. When you pause the game, you want the in-game UI to disappear and the menu to show up. Well there is an easy way to achieve that very effect.

Canvas Groups

When making UI with Unity's canvas system, you have the option to put every UI element in the canvas. But there is also a trick you can do to make canvas groups. Groups with UI elements in it. If you create an Empty GameObject and add the Canvas Group component to it. This is now treated as a Canvas Group. These canvas groups can then be manipulated through code. For example, hide the in-game UI when the game is paused and vice versa.

It is actually very easy to manipulate these through code. Make two public references for CanvasGroups and give them appropriate names.
 public CanvasGroup inGame;
 public CanvasGroup pause;
There are four properties of the Canvas Group you can edit.

  • Alpha - Value between 0 and 1, where 0 is invisible and 1 visible
  • Interactable - Boolean for it's interactabilty. When it is set to false interaction is disabled.
  • Block Raycasts - Will this component act as a collider for Raycasts? When set to true it is interacting with Raycasts.
  • Ignore Parent Groups - Will this group also be affected by the settings in Canvas Group components further up in the Game Object hierarchy, or will it ignore those and hence override them?


 When the game is paused I want the pause menu to show up and the in-game menu to disappear. So when the Pause button is pressed, you set the in-game's alpha to 0, making it invisible and its blockraycasts property to false, because I worked with raycasts. You can also set the 'interactable' property to false here. For the pause canvas group you do the exact opposite. You set the pause alpha to 1 and the block raycasts to true. It's maybe a bit confusing to set 'block raycasts' to true for it to NOT block raycasts, but that's how it is. For the play button you do the opposite to make the in-game UI appear again.
 if (Input.GetKeyDown("Pause")
        {
  inGame.alpha = 0;
  inGame.blocksRaycasts = false;
 
  pause.alpha = 1;
  pause.blocksRaycasts = true;
 }
 if (Input.GetKeyDown("Play")
        {
  inGame.alpha = 1;
  inGame.blocksRaycasts = true;
 
  pause.alpha = 0;
  pause.blocksRaycasts = false;
 }

woensdag 16 maart 2016

Double click, click and hold and toggles

For a project of mine I needed the ability to double tap, tap and hold or toggle a button. In this blogpost I'll walk you through the steps on how to do that. These methods are also applicable for mouse clicks.

Double Tap

To make a button that reacts on double tap, you basically need a timer that starts when you push a button. If you push the button again while the timer runs, you perform a double tap. Otherwise it is counted as 2 single taps.
The following code should be placed in the TouchPhase.began code.

Let's first make 3 variables. A boolean called oneTap, a float called doubleClickTimer and a float called delay. I made them all public so I can easily check and edit them in the Inspector.

 public bool oneTap;
 public float doubleClickTimer;
 public float delay;

In your Touchphase.began you check if the button is not tapped, if that's the case set oneTap to true. If that's not the case, run the logic for the double tap.

 if (!oneTap)
 {
  oneTap = true;
 }
 else
 {
  #put logic for double tap here#
 }

If the button is tapped increase doubleClickTimer every frame. If it's equal to the delay, set one tap false (the double tap failed because you ran out of time). :
 
 if(oneTap)
 {
  doubleClickTimer++;
  if(doubleClickTimer >= delay )
  {
   oneTap = false;
   doubleClickTimer = 0;
  }
 }

And There you have it. A button that reacts to a double tap.

Tap and hold

For tap and hold you also need a timer. But this time the timer starts running when you tap and hold the button. To achieve this you need to put this in the TouchPhase.stationary part of your touch code.

For this effect we need two variables of type int. 'holding' is the time you are holding the button and 'holdTime' is the max time you need to hold the button for logic to activate.

public int holding;

public int holdTime;
Then in the TouchPhase.Stationary code you check if holding is more or equal to holdTime. If that's true, you do the tap and hold logic, otherwise you increase the holding timer.:

if (holding >= holdTime)
 {
  #do tap and hold things#
 } 
 else 
 {
  holding++;
 }

Toggle

For toggling a button there is a pretty nifty trick you can do that I didn't know about at first.
But first we make a variable with type boolean called buttonActivated
 
 public bool buttonActivated;
Then when you press that button, or other object for that matter you set the buttonActivated bool to !buttonActivated. Like this:
 
 if (hit.transform.name == "Toggle")
  {
   buttonActivated = !buttonActivated;
  }
(In this example I checked for the name to be "Toggle". Feel free to check for something else).

donderdag 28 januari 2016

City Generator [Personal Project]


In this blogpost I'll be going over a personal project. I took a rather unconventional route to make a city generator. But the end result is a very good visual representation how city generators work.

The Plan

The plan was to generate a 2D grid using a 2D array. Then selecting certain points on that grid as starting points for the roads. The roads starting points will then check the tiles next to it and decide if it can spawn a road there. When the road building phase is done, all the road tiles will again check all the tiles surrounding it. If there is not a road, then place a house.

Sounds easy right?

2D Grid (of green tiles)

The Execution

I started with the 2D array and placing the road starting points. This all went pretty well. When it was time to build the rules to make curves and intersections, I kinda ran out of knowledge and asked for help. Liam Ederzeel was the one to help me for 3 hours straight. We got a lot done but it was all above my skill level. So it was time for a plan B. I kept his code for reference because I did learn a lot from that. But I went back to the drawing table and thought how I would tackle a problem like this. 

Walker bots working hard

Plan B

So I came up with the following method: Spawn a 2D grid using a 2D array. Spawn walker "bots" which will move in one direction an place roads. Attach a script to each tile to look around, if there is nothing (or grass) next to it, place a House. After some tinkering I got this to work.


Click here to see the finished product (Unity Webplayer is required).
WASD to move around
Mouse to look
Space to spawn bots
Enter/Return to spawn houses (ONLY DO THIS WHEN BOTS HAVE DISAPPEARED)
The Generated City





maandag 9 november 2015

How to improve lighting in your scenes in Unity 5

When making games in unity I always hate how my scenes look. This is because I have no knowledge on how to make good use of the lighting capabilities in Unity. This sparked my interest in researching how to improve lighting in Unity. In this blogpost I’ll be going over some tips on how to improve lighting. I’ll show you step by step how to transform your scene from this:
Before
to this:
After


Lighting window

Skybox

Let’s start by editing the skybox, or at least the ambient light it’s providing. When creating a new Unity scene you get a standard skybox. This skybox also emits light. This can be nice for setting up a scene quickly but not for indoor scenes because the outdoor ambient light can’t go through walls.

You can change the ambient light in the lighting panel (Window > Lighting). In here you find all sorts of options about lighting in Unity. One of the options we are looking for is the Ambient Source. This is by default “Skybox”. For indoor scenes this is not optimal. So now you can do two things. Put it on Gradient or Color. For simplicity I put it on Color but you can also play with gradient. In the example I put the color on a brown, similar to the brown walls.


Emission material

The second tip you can take in consideration are Emissive materials. Emissive materials are materials that emit light. They are really good to make a computer screen light up (like I did in the example). You can also use them to make large areas light up like ceiling lights. BTW Emissive materials will only bounce on objects that are Static or Lightmap Static (I put it on Static because it gave me better results. Play with yours for the best results. See image below).

How to use the Emission map

When displaying a material in the inspector there is a Emission map. In the example scene I used 2 materials with the emission map active. The first one for the computer screens. Here I made multiple texture maps for the same object and assigned to one material. In the Albedo I placed the normal color map and in the Emission I placed the emission map. Note that everything black in the emission map does not emit light and everything white will. You can also use grey tones to make it emit less light. 
The second Emission map I used was a lot easier. I made a material with a white albedo. I also made the emission white. By doing this it looks like there is light coming from the air vent (although I was hoping for a more promising effect). 

Computer material
Air vent material
Color map for computer 
Emission map for computer

Cookies 

Cookies are like an overlay you put over your light. You can compare it to making shadow puppets. A cookie is just an image where white is transparent and black is solid. The solid parts wil block the light. I used a cookie to create the air vent shape in the light. While I could totally used the mesh from the air vent itself, I thought it would be cool to test the cookies.
Cookie for air vent

Sources

Random searches on Unity forums