Time
A shader doesn’t remember anything from one frame to the next, so it can’t count frames itself. I count them for it, two ways.
TIME
TIME is how many seconds my renderer has been running, with a point: 2.5
is two and a half seconds. It’s the same for every shader and every pixel,
and it’s real time, so a shader that moves by TIME moves at the same speed
on a slow phone and on a fast PC.
SIN turns time into something that goes back and forth: SIN(TIME) goes
from 0 up to 1, down to -1 and back again every 6.28 seconds. Multiply
TIME to make it faster.
SCREEN 320, 240
SHADER "pulse"
USE NUMBER speed DEFAULT 3.0
WHEN DRAWING
c = IMAGE
glow = 0.5 + SIN(TIME * speed) * 0.5
SET COLOR = MIX(c, RGBA(1.0, 1.0, 1.0, c.a), glow * 0.6)
END WHEN
END SHADER
LOADIMG "hero.png", "hero"
ENABLE SPRITE 0
SET SPRITE 0 !! image("hero") x(140) y(100) scale((3, 3)) shader("pulse")
SHOW SPRITE 0
PAUSE
0.5 + SIN(...) * 0.5 moves the back and forth from -1 to 1 up into 0 to 1,
which is the range most things want.
TIME with FRACT goes round instead: FRACT(TIME) climbs from 0 to 1
every second and starts again. Here it scrolls the picture forever:
SCREEN 320, 240
SHADER "conveyor"
USE NUMBER speed DEFAULT 0.25
WHEN DRAWING
SET COLOR = OWNTEXTURE(VEC2(FRACT(UV.x + TIME * speed), UV.y))
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (0, 0), "city"
SET LAYER 0 !! shader("conveyor")
PAUSE
TICK
TICK counts frames, from 0, since this shader went on this layer or this
sprite. Where TIME is the same everywhere, TICK is each one’s own: put
the shader on a sprite now and its TICK starts at 0 now, whatever any
other sprite’s is doing. That makes it the one for things that happen
once, starting when the shader goes on:
SCREEN 320, 240
SHADER "appear"
USE NUMBER frames DEFAULT 60
WHEN DRAWING
c = IMAGE
shown = CLAMP(TICK / frames, 0.0, 1.0)
SET COLOR = RGBA(c.r, c.g, c.b, c.a * shown)
END WHEN
END SHADER
LOADIMG "hero.png", "hero"
ENABLE SPRITE 0
SET SPRITE 0 !! image("hero") x(140) y(100) scale((3, 3)) shader("appear")
SHOW SPRITE 0
PAUSE
The hero fades in over 60 frames, a second at sixty frames a second.
Crash-tan’s Tip:
TICKcounts the frames that are drawn, so on a machine that’s struggling it counts more slowly than sixty a second, and the fade takes longer. It always finishes, though.TIMEis never late, but it’s the renderer’s clock, not the shader’s: a one-off driven byTIMEstarts wherever the clock happens to be.
A one-off from a setting
When a one-off has to keep to real time, have your program tell the shader how far along it is. Here my program counts the ticks, and the shader only draws what it’s told:
SCREEN 320, 240
SHADER "wipe"
USE NUMBER done DEFAULT 0
WHEN DRAWING
c = IMAGE
gone = STEP(UV.x, done)
SET COLOR = MIX(c, RGBA(0.0, 0.0, 0.0, 1.0), gone)
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("wipe") shader_params({done: 0})
done = 0
DO
IF COOLDOWN(1) AND done < 1
done = done + 1 / 90
SET LAYER 0 !! shader_params({done: done})
END IF
LOOP
The city is wiped away from the left, in 90 ticks. The next chapter is all
about settings like done.