Monday 16 February 2015

Unity3D Shaders–Surface Shaders Continued

<< Previous                                                                                           Next >>
In the last post we started to look at surface shaders and we even applied it to a sprite to show that we can apply these shaders to simple 2D objects, but we had not set the shader up for alpha blending so we had a few artefacts. In this post, we will look making a surface shader work with alpha blending and we will set both our quad and sprite to fade in and out on command.
Like before, we will create a new shader, call it SSFadeShader, also a new material like before and name it SSFadeMaterial

SSFadeShader

Shader "Randomchaos/Tutorial/SSFadeShader" 
{
 Properties 
 {
  _MainTex ("Base (RGB)", 2D) = "white" {}
  _FadeOut("Fade out value", Range(0,1)) = 1
 }

 SubShader 
 {
  Tags { "Queue"="Transparent" "RenderType"="Transparent" }
  LOD 200
  
  CGPROGRAM

  #pragma surface surf Lambert alpha

  sampler2D _MainTex;
  float _FadeOut;

  struct Input 
  {
   float2 uv_MainTex;
  };

  
  void surf (Input IN, inout SurfaceOutput o) 
  {
   half4 c = tex2D (_MainTex, IN.uv_MainTex);
   o.Albedo = c.rgb;
   o.Alpha = c.a * _FadeOut;   
  }
  ENDCG
 } 
 Fallback "Diffuse"
}

A couple of things here, we have a fade parameter called _FadeOut as a range from 0 to 1, and an associated variable, we have also appended “alpha” to the #pragma, as well as setting the queue and rendertype to “Transparent” in the Tag line. This tells Unity that this surface shader uses transparency.

We can now apply this shader to our new material and then put this material on our sprite and quad. I have a nice flower png with transparency I am going to use for the quad.

image

As you can see, the artefacts from before have been fixed with this new shader.

You can test the shader by moving the Fate Out Slider, as you reduce the value, the texture fades out, as you increase it, it fades back in.

We can now create a script that will control the fade level, create a script and call it FadeMaterialScript.cs

FadeMaterialScript.cs


using UnityEngine;
using System.Collections;

public class FadeMaterialScript : MonoBehaviour 
{
    public float FadeSpeed = .01f;

    float currentFade;
    bool fade;
    float fadeValue = 1;

    Renderer renderer;

 // Use this for initialization
 void Start () 
    {
        currentFade = FadeSpeed ;

        renderer = GetComponent<Renderer>();
 }
 
 // Update is called once per frame
 void Update () 
    {
        if (fade)
        {
            fadeValue += currentFade;

            fadeValue = Mathf.Clamp01(fadeValue);

            if (fadeValue == 0 || fadeValue == 1)
                fade = false;

            renderer.material.SetFloat("_FadeOut", fadeValue);
        }
 }

    public void Fade()
    {
        currentFade *= -1;
        fade = true;
    }
}

This is a pretty simple script, we set up five variables, one public float to hold the speed of the fade we want to implement, one to hold the current fade (this is also the current fade direction, in or out) a bool to indicate if we are actually fading or not, another float to store the current fade value and a Renderer so we can get at the material.

In the Start method we set the currentFade and get the objects Renderer.

In the Update method we have an if to see if we are fading or not, if we are then we alter the value by the current fade direction/speed, we then clamp the fade value as we only want values in the range of 0 and 1. We then switch the fade flag off if we have fully faded, either in or out. Then we pass the fade value to the shader via

            renderer.material.SetFloat("_FadeOut", fadeValue);

We then have a public function that can be called externally to kick off the fade, it first flips the current fade direction and then sets the fade flag to true, the Update will then pick it up from here.

The next thing I am going to do is add two UI.Buttons to my scene, I rename the text, one to “Fade Flower” and one to “Fade Sprite”. With the UI.Button we can hand an object to the OnClick event, and from that tell it what script and what method to execute when the button is clicked, so I set the buttons up with each of my objects

image

We can now run the code, and I can now fade out and back in the game objects by clicking the UI buttons.

image

I have found with surface shaders there are a few idiosyncrasies, with transparency, I can’t control the blend type, it seems only alpha blend are available, so no additive or multiplication blends. Also the shadow pass takes all of the geom into account, it ignores the level of alpha. I find that you have much more control in a vertex/fragment shader.

This has been a bit of a quick post, partly as I have a pretty busy week, also someone requested a practical example of the surface shader I described in the last post, so thought this might be something to show quick that can be done with a shader. I do plan on doing some shader examples towards the end of the posts, but really do want to get the basics covered before I dig too deep into that. I hope this gives you an idea of how you can use something as simple as a surface shader, in my next post I am going to stick with the surface shader and cover creating our own lighting equations. 

As ever comments and critique is more than welcome, even suggest an effect you would like to apply and Ill look at adding at the end of the series.

<< Previous                                                                                           Next >>

No comments:

Post a Comment