AGAL multitexture shader

September 5th, 2012    by sigman    4537
  Tutorials   actionscript, programming

Inspired by the great blog post from Devon_O on conversion of GLSL (OpenGL) shaders to AGAL shaders, I decided to pick one of the examples available on Shader Toy website and to my suprise it wasn't that hard to get it working. I wanted to put the example with code on the Wonderfl but I can't get it running over there so I decided to put it here. And while I put it here, why not add just few additional words about shaders in AGAL...

Article imported from http://sierakowski.eu/list-of-tips/113-agal-multitexture-shader.html

So here is the shader itself. The original GLSL source is available here under the 'multitexture' name: http://www.iquilezles.org/apps/shadertoy/

 

As always the most difficult are the initial steps. To get started I advise to read an article from Adobe explaining what the AGAL is, what are Vertex and Fragment programs, registers, available op-codes and AGALMiniAssembler: http://www.adobe.com/devnet/flashplayer/articles/what-is-agal.html. This article is not comprehensive enough and leaves you with many questions and unfortunately I couldn't find any additional information on Adobe websites explaining AGAL in greater detail. Anyway it is good enough to get you started. Additional handy information about registers could be found here: http://www.saltgames.com/2011/agal-registers/

So now when you know all the basics and want to try creating some shaders based on one of many of the GLSL examples available on internet, read a great article from Devon_O on his blog: http://blog.onebyonedesign.com/actionscript/learning-agal-with-agalmacroassembler-and-opengl-examples/. If you read it attentively, you shouldn't have any problems understanding it as it guides you step by step how to do it.

Just to make it easier to get the whole picture of the registers and the way how to populate them from ActionScript level, take a look at the figure below. [Update: here is a pdf version]

Agal_Graph

Also take a look at these images from the Adobe article listing all available opcodes:

AGAL opcodes 1

AGAL opcodes 2

And here is the shader itself, I left the comments so you can easily find out how I got there (if you carefully followed instructions given by Devon).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
//GLSL: /////////////////////////////////////////////////////////
 
    vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
    // a rotozoom
    vec2 cst = vec2( cos(.5*time), sin(.5*time) );
    mat2 rot = 0.5*cst.x*mat2(cst.x,-cst.y,cst.y,cst.x);
    vec3 col1 = texture2D(tex0,rot*p).xyz;
 
    // scroll
    vec3 col2 = texture2D(tex1,0.5*p+sin(0.1*time)).xyz;
 
    // blend layers
    vec3 col = col2*col1;
 
    gl_FragColor = vec4(col,1.0);
    
//CONSTANTS: ////////////////////////////////////////////////////
  fc0 = [ 1, 1, 1, 1 ]
  fc1 = [ .5 * mTime, .1 * mTime, 2, 0 ]
  fc2 = [ sin(.5 * mTime), cos(.5 * mTime), sin(.1 * mTime), .5 ]
 
/////////////////////////////////////////////////////////////////
*/  
 
 
//Step 1: ft1 = vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
mov ft1, v0
mul ft1.xy, ft1.xy, fc1.z
div ft1.xy, ft1.xy, fc0.xy
sub ft1.xy, ft1.xy, fc0.x
 
//Step2: ft2 = vec2 cst = vec2( cos(.5*time), sin(.5*time) );
mov ft2.x, fc2.y
mov ft2.y, fc2.x
 
//Step3: ft3 = mat2 rot = 0.5*cst.x*mat2(cst.x,-cst.y,cst.y,cst.x);
mov ft0.x, fc2.w
mul ft0.x, ft0.x, ft2.x
 
mov ft3.x, ft2.x
mul ft3.x, ft3.x, ft0.x
 
mov ft3.y, fc1.w
sub ft3.y, ft3.y, ft2.y
mul ft3.y, ft3.y, ft0.x
 
mov ft3.z, ft2.y
mul ft3.z, ft3.z, ft0.x
 
mov ft3.w, ft2.x
mul ft3.w, ft3.w, ft0.x
 
//Step4: ft4 = rot * p
mul ft0.x, ft3.x, ft1.x
mul ft0.y, ft3.y, ft1.y
mul ft0.z, ft3.z, ft1.x
mul ft0.w, ft3.w, ft1.y
add ft4.x, ft0.x, ft0.y
add ft4.y, ft0.z, ft0.w
mov ft4.zw, fc0.zw
 
//Step5: ft5 = vec3 col1 = texture2D(tex0,rot*p).xyz;
tex ft5, ft4, fs0<2d, repeat, linear, nomip>
 
//Step6: ft6 = vec3 col2 = texture2D(tex1,0.5*p+sin(0.1*time)).xyz;
mov ft0, fc0
mul ft0, ft1, fc2.w
add ft0, ft0, fc2.z
tex ft6, ft0, fs1<2d, repeat, linear, nomip>
 
//Step7 ft7 = vec3 col = col2*col1;
mul ft7, ft6, ft5
 
//Step8 gl_FragColor = vec4(col,1.0);
mov oc, ft7

 

Constants are uploaded to registers in onTick method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if ( !mContext3d ) return;
 
mContext3d.clear ( 0, 0, 0, 1 );
 
mContext3d.setProgramConstantsFromMatrix(
  Context3DProgramType.VERTEX, 0, mMatrix, true);
 
//fc0 = [ 1, 1, 1, 1 ]
mContext3d.setProgramConstantsFromVector(
  Context3DProgramType.FRAGMENT, 0, Vector.<Number>( [ 1, 1, 1, 1 ]) );
 
 
//fc1 = [ .5 * mTime, .1 * mTime, 2, 0 ]
mContext3d.setProgramConstantsFromVector(
  Context3DProgramType.FRAGMENT, 1, Vector.<Number>( [ .5 * mTime, .1 * mTime, 2, 0 ]) );
 
 
//fc2 = [ sin(.5 * mTime), cos(.5 * mTime), sin(.1 * mTime), .5 ]
mContext3d.setProgramConstantsFromVector(
  Context3DProgramType.FRAGMENT, 2, 
  Vector.<Number>( [ Math.sin(.5 * mTime), 
  Math.cos(.5 * mTime), Math.sin(.1 * mTime), .5 ]) );
 
 
mContext3d.drawTriangles(mIndexBuffer);
mContext3d.present();
 
mTime += .025;

 

The full source code is available on wondefl (but doesn't work for no obvious reason): http://wonderfl.net/c/xZs3

or on the GitHub: https://github.com/wsierakowski/stage3d/blob/master/shader-multitexture/Main.as

 

Comments imported from the original article @sierakowski.eu

 
+- 0 #2 wojciech 2012-09-19 21:53
No problem, just added a link to it in the article.
Quote
 
 
 
+- 0 #1 Carbon 2012-09-19 21:40
Hey, would you be able to share the hires version of the AGAL image so I can print it and stick it on my wall? Thanks in advance.
Quote