3

I'm trying to fluctuate between two values inside a shader to achieve a glowing effect. I need it to be done inside the shader itself and not via C# scripting. I've tried using the _Time value that Unity gives us for shader animation but it isn't working:

Shader "Test shader" {
Properties {
    _ColorTint ("Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _GlowColor("Glow Color", Color) = (1,0,0,1)
    _GlowPower("Glow Power", Float) = 3.0
    _UpDown("Shine Emitter Don't Change", Float) = 0
}
SubShader {
    Tags { 
        "RenderType"="Opaque" 
    }

    CGPROGRAM
    #pragma surface surf Lambert

    struct Input {
            float4 color : Color;
            float2 uv_MainTex;
            float3 viewDir;
            float4 _Time;
    };

    float4 _ColorTint;
    sampler2D _MainTex;
    float4 _GlowColor;
    float _GlowPower;
    float _UpDown;

    void surf(Input IN, inout SurfaceOutput o) {
        if (_UpDown == 0) {
            _GlowPower += _Time.y;
        }
        if (_UpDown == 1) {
            _GlowPower -= _Time.y;
        }
        if (_GlowPower <= 1) {
            _UpDown = 0;
        }
        if (_GlowPower >= 3) {
            _UpDown = 1;
        }

        IN.color = _ColorTint;
        o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * IN.color;
        half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
        o.Emission = _GlowColor.rgb * pow(rim, _GlowPower);
    }
    ENDCG
}
FallBack "Diffuse"
}

This makes the glow grow to the infinite.

What am I doing wrong?

Don't Panic
  • 41,125
  • 10
  • 61
  • 80
user6385193
  • 53
  • 1
  • 8
  • I might be wrong, but isn't _Time.y just the elapsed time since the game started? if so, then you would add/subtract growing values to _Glowpower. Think for example of the sum 1-2+3-4+5-6+7 and so on, this is going towards infinity – nyro_0 Jun 15 '16 at 09:43
  • 1
    Have you tried using _SinTime instead instead of _Time? Maybe like `_GlowPower=3*_SinTime.y`. I have never used it, but from the name I would expect it to return something like sin(time) which oscillates between -1 and 1 – nyro_0 Jun 15 '16 at 09:51
  • Uniform values don't work like that. You can't change `_UpDown` inside your shader and expect that it retains that value for the next shader execution. Sounds like you should move this code to a script instead and only supply the final `_GlowPower` to the shader. – Quinchilion Jun 15 '16 at 10:13
  • @xyLe_ thanks a lot, that helped :) – user6385193 Jun 15 '16 at 11:01

2 Answers2

4

Extending my comment slightly:

You can't use _Time.y in this case, as it is the elapsed time since the game started, thus it will increase over time.

You can use _SinTime.y instead, which represents sin(_Time.y). This means that oscillates between the values -1 and 1. You can use this and assign (maybe a scaled version of _SinTime) to your variable: _GlowPower = C * _SinTime.y

More on build-in shader variables: http://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

nyro_0
  • 1,135
  • 1
  • 7
  • 9
1

For doing a pulsing glow... I'd have a script 'outside' the shader and send in a paramater (_GlowPower) calculate in c# script like this....

glowPow = Mathf.Sin(time);

Then you only need to calculate it once. IF you put it in VErtex shader... it does it once per vertex, and if its in surface shader... then once per pixel = performance waste.

you can send variables to your shader like this... (very handy)

material.SetFloat(propertyName, valueToSend);

So you could send, time, strength, glow or whatverer you want.

If you really need to do a glow calculation per vertex or per pixel, then use

_glowPow = sin(_time);

inside the shader.

zhm
  • 3,513
  • 3
  • 34
  • 55