 Posted by & filed under Blog.

I’ve recently been trying my hands at shader programming and come to several conclusions :

• I suck at maths
• AGAL coders are masochists
• Even though it’s kinda complicated, it’s super fun

I’m using Flare3D for my project, and the engine comes with its own variation of high level shader language, FLSL, wich is very similar to HLSL or GLSL, and comes with its own share of pros and cons :

The pros

• High level
• Supports common blending operations
• Implements the most common math operators
• Interpolated variables for the fragment shader
• Possibility to create FLSLFilters and FLSLMaterials (see documentation)

The cons

• No for loop
• No atan2, although that seems to come from adobe

So i’ve been toying with it a bit using the various ressources and examples Flare3D shared, simple stuff really, and wanted to share.
So here’s a few animated 2D effects, mostly adaptation of existing GLSL code found on the GLSL Sandbox and ShaderToy.

Concentric rings

Greyscale rings shrinking over time

technique rings
{
param TIME time;
param float2 center = float2( .5, .5 );
input UV0 uv;
interpolated float2 iUV = uv;

float d = distance( center, iUV ) ;
float col = ( 0.5 + sin( ( -time.w + d ) * PI2 * 5 )/2 + 0 ) ;
float4 outputcolor = float4( col, col, col, 1 ) ;

output vertex = transform();
output fragment = outputcolor;
}

A simple plasma technique simpleplasma
{
param TIME time;
interpolated float2 iUV = uv0;

float x = iUV.x * 515;
float y = iUV.y * 512;
float t = time.w * 10;

float mov0 = x + y + cos( sin( t ) * 2. ) * 100 + sin( x / 100. ) * 1000;
float mov1 = iUV.y / 0.2 + t*2;
float mov2 = iUV.x / 0.2;

float c1 = abs( sin( mov1 + t ) / 2 + mov2 / 2 – mov1 – mov2 + t );
float c2 = abs( sin( c1 + sin( mov0 / 1000 + t ) + sin( y / 40 + t ) + sin( ( x + y ) / 100 ) * 3 ) );
float c3 = abs( sin( c2 + cos( mov1 + mov2 + c2 ) + cos( mov2 ) + sin( x / 1000 ) ) );

float4 outputcolor = float4( c1, c2, c3, 1 ) ;

output vertex = transform();
output fragment = outputcolor;

}

Scanlines

Scanlines over a texture, with light flickering and a greenish tint

technique scanlines
{
param TIME time;
param sampler2D texture ;
interpolated float2 iUV = oUV;
float tval = time.y ;

float2 uv = 0.5 + (iUV-0.5) * (0.9 + 0.01*sin(0.5*tval));
float4 col;

col = sampler2D( texture , uv ) ;

col = clamp(col*0.5+0.5*col*col*1.2,0.0,1.0);
col *= 0.5 + 0.5*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y);
col *= float4(0.8,1.0,0.7,1);
col *= 0.9+0.1*sin(10.0*tval+uv.y*1000.0);
col *= 0.97+0.03*sin(110.0*tval);

output vertex = transform();
output fragment = col;
}

Ring deformation

A funny texture deformation

technique ringdeform
{
param TIME time;
param sampler2D texture ;
interpolated float2 iUV = uv0;

float timeval = time.x;
float2 p = -1 + 2 * iUV;
float r = sqrt(dot(p,p));
float s = r * (1.0+0.8*cos(timeval));
float2 uv;
uv.x = .02*p.y+.03*cos(-timeval)/s;
uv.y = .1*timeval +.02*p.x+.03*sin(-timeval)/s;
float w = .9 + pow(max(1.5-r,0),4);
w*=0.6+0.4*cos(timeval);
float4 col = float4( sampler2D(texture,uv).xyz, 1 );

output vertex = transform();
output fragment = col;
}

Another ring deformation

Similar to the previous one

technique ringdeform2
{
param TIME time;
param sampler2D texture ;
interpolated float2 iUV = uv0;

float2 p = -1.0 + 2.0 * iUV;
float r = sqrt(dot(p,p));
float2 uv;
uv.x = r – .25*time.x;
uv.y = cos( 2.0*sin(time.x+7*r)) ;

float4 col = float4( (.5+.5*uv.y)*sampler2D(texture,uv).xyz, 1 );

output vertex = transform();
output fragment = col;

}

Pulse effect

Texture pulsing around a wandering halo

technique pulse
{
param TIME time;
param COS_TIME costime;
param sampler2D texture ;

float tval = time.x;

interpolated float2 iUV = uv0;

float2 resolution = float2( 1, 1 );
float2 halfres = resolution/2 ;
float2 cPos = iUV;

cPos.x -= 0.5*halfres.x*sin(tval/2.0)+0.3*halfres.x*costime.x+.5;
cPos.y -= 0.4*halfres.y*sin(tval/5.0)+0.3*halfres.y*costime.x+.5;
float cLength = length(cPos);

float2 uv = iUV + (cPos / cLength) * sin( cLength / 30.0 – tval * 10.0 ) / 25.0;
float4 col = float4( sampler2D(texture,uv).xyz * .5 / cLength, 1 );

output vertex = transform();
output fragment = col;

}

Flying tunnel

Rotating flying tunnel

technique fly
{
param sampler2D texture ;

param TIME time;
param float scrollspeed = 1;
param float rollspeed = 1;
interpolated float2 iUV = uv0;
float2 p = -1.0 + 2.0 * iUV;
float2 uv;
float timeval = time.z;
float speedcostime = cos( timeval * rollspeed );
float speedsintime = sin( timeval * rollspeed );

float x = p.x*speedcostime-p.y*speedsintime ;
float y = p.x*speedsintime+p.y*speedcostime ;

uv.x = .25*x/abs(y);
uv.y = timeval * scrollspeed + .25/abs(y);

float4 outputcolor = float4(sampler2D(texture,uv).xyz * y*y, 1.0 );

output vertex = transform();
output fragment = outputcolor;
}

Black and white thing

sin/cos magic

technique coolrings
{
param COS_TIME costime;
param SIN_TIME sintime;
param MOUSE mouse;
interpolated float2 iUV = uv0;

float c = 1.3;
float over = 1.3;
float2 point = float2( (costime.x +1)/2 , (sintime.y +1)/2 );
float d0 = distance( iUV, 1-point ) ;
float d1 = distance( iUV, point ) ;
c = ( sin( d0 * PI * 10 ) + sin( d1 * PI * 10.0 ) ) / 2;

float4 out = float4(c*3*over, c*3*over, c*3*over, 1 );

output vertex = transform();
output fragment = out;

}

So, yeah, that’s a lot of sinus/cosinus , and those can probably be optimized. Here’s the source file regrouping all those techniques if someone interested :