How to write and use a simple shader
Introduction
In this tutorial we will show how to create a very simple rendering effect by defining a custom shader and using it in a simple scene. Our shader will simply display everything using a flat red color. Here is the final result we will get:

In this tutorial, the scene will contain just a single cube. But the scene and the shader are completely unrelated. Therefore, one can use the shader described in this tutorial on any kind of 3D geometry loaded in the scene.
Our shader will take advantage of Minko's ActionScript shaders. ActionScript shaders are an incredible feature: it makes it possible to program the graphics hardware using nothing more than pure plain ActionScript code. The ActionScript code written in those shaders is then executed on the GPU, providing an easy and powerful way to create hardware accelerated rendering effects.
Step 1: Initializing the scene
We start by defining a very simple scene containing only a cube and an ArcBallCamera:
public class Main extends Sprite
{
private var _viewport : Viewport = new Viewport();
private var _camera : ArcBallCamera = new ArcBallCamera();
private var _scene : Group = new Group(
_camera,
CubeMesh.cubeMesh
);
public function Main()
{
_camera.distance = 3.;
stage.addChild(_viewport);
stage.addEventListener(Event.ENTER_FRAME);
}
private function enterFrameHandler(event : Event) : void
{
_viewport.render(_scene);
}
}
In this configuration, the scene will be rendered using the BasicEffect because it is the default effect. Because this effect requires a texture or per-vertex colors to work properly, you'll get an error if you try to run the application as is.
Step 2: The shader
We are going to write a very simple shader using ActionScript. Our shader will simply display the geometry using a flat red color. To write an ActionScript shader, you must:
- create a new class that extends ActionScriptShader
- override the ActionScriptShader.getOutputPosition() method to define the vertex shader
- override the ActionScriptShader.getOutputColor() method to define the fragment shader
The Vertex Shader
Our vertex shader will handle no fancy features: no skinning, no morphing... It will just project our 3D vertices to the 2D flat space of the screen. This is the most basic vertex shader you can write to display 3D on the screen:
public function getOutputPosition() : SValue
{
return multiply4x4(vertexPosition, localToScreenMatrix);
}
This operation is very common. We multiply the position of the vertex by the "local to screen matrix".
To make it easier to write and add some meaning, Minko provides the vertexClipspacePosition protected property that does exactly
the same thing:
public function getOutputPosition() : SValue
{
// a shortcut for "multiply4x4(vertexPosition, localToScreenMatrix)"
return vertexClipspacePosition;
}
The Fragment Shader
The goal of the fragment shader is to compute the final color of each fragment (pixel) on the screen. The color of a fragment can be computed in a lot of different ways to handle fancy effects such as lighting, shadowing, bump mapping... In this case, we will just say that every pixel is red:
public function getOutputColor() : SValue
{
// return the color red in the RGBA format in a float4 value
return float4(1., 0., 0., 1.);
}
The Complete ActionScript Shader
Here is the complete code to write our flat red ActionScript shader:
public class RedShader extends ActionScriptShader
{
public function getOutputPosition() : SValue
{
return vertexClipspacePosition;
}
public function getOutputColor() : SValue
{
return float4(1., 0., 0., 1.);
}
}
Step 3: Use the shader
Now that we have a proper shader, we must update our scene setup to make sure it is used properly.
The default effect used in a scene is set in the Viewport.defaultEffect property.
To use our custom shader, we simply have to set this property to a new effect that will use our shader:
_viewport.defaultEffect = new SinglePassRenderingEffect(new RedShader());
Conclusion
Here is the final code for our application:
public class Main extends Sprite
{
private var _viewport : Viewport = new Viewport();
private var _camera : ArcBallCamera = new ArcBallCamera();
private var _scene : Group = new Group(
_camera,
CubeMesh.cubeMesh
);
public function Main()
{
_camera.distance = 3.;
_viewport.defaultEffect = new SinglePassRenderingEffect(new RedShader());
stage.addChild(_viewport);
stage.addEventListener(Event.ENTER_FRAME);
}
private function enterFrameHandler(event : Event) : void
{
_viewport.render(_scene);
}
}
public class RedShader extends ActionScriptShader
{
public function getOutputPosition() : SValue
{
return vertexClipspacePosition;
}
public function getOutputColor() : SValue
{
return float4(1., 0., 0., 1.);
}
}
