I figured I'd write a quick tutorial that goes over the basics of writing a pixel shader.
The first turial will just be a quick overview of an existing shader so you understand how it works.
Open the directory or its equiv: C:\Program Files\Scirra\Construct\Effects\
This is where all the effects are. Each effect is a single *.fx file which can be opened in any text-based editor. I would personally recommend notepad++ because its free, simple, has syntax colouring, and multiple undos. Anyway it doesn't really matter for this tutorial, we are simply going to be reading over the file.
Open Multiply Plus.fx
Lets take a look at the first few lines of the file:
// Multiply
// Ashley Gullen
// PS 2.0
// Multiplication blend with intensity.[/code:2lblvyj0]
The first line is the name of the effect, the second is the Author, the third is the Pixel Shader version, and the fourth is its description. The // means this text is a comment, and therefore not part of the fx file...however Construct reads these specific lines and obtains information from them, so your fx files MUST contain these comments
Next we have our parameter for our effect
[code:2lblvyj0]//#PARAM percent intensity 1 : Intensity : Intensity of the effect.
float intensity;[/code:2lblvyj0]
The first line is a Construct definition, which goes in the form:
#param type fxvariablename initialValue : nameInConstruct : Description
For type we can either use percent or float. Currently these are all that are supported, but later we may include more (such as a texture!)
Next we have any declared variables that are needed for our shader.
[code:2lblvyj0]
// Foreground texture
texture ForegroundTexture;
// Background texture
texture BackgroundTexture;
[/code:2lblvyj0]
Constructs runtime will check to see if certain variables are declared in the effect file, and will pass appropriate values to them. Here is a complete list:
[ul]ForegroundTexture
BackgroundTexture
SourceTexture
PreviousTexture
frameCounter
boxLeft
boxTop
boxRight
boxBottom
boxWidth
boxHeight
hotspotX
hotspotY
pixelWidth
pixelHeight
bgStart
bgEnd
[/ul]
Other shaders such as 'wave' use most of these variables, but multiply doesn't require them so they aren't declared.
Now we have our sampler definitions:
[code:2lblvyj0]// Foreground sampler
sampler2D foreground = sampler_state {
Texture = (ForegroundTexture);
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
};
// OriginalTexture sampler
sampler2D background = sampler_state {
Texture = (BackgroundTexture);
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
};[/code:2lblvyj0]
In a pixel shader, samplers determine how the computer calculates the colour value of a point in the texture. If you use 'point', it will go to the nearest pixel, if you use linear, it does a linear interpolation between pixels. We tend to only use these two. Point is faster than linear, so we tend to only use linear when its possible we are looking up pixels that are between pixels. Magnify uses linear so that the magnified image looks smooth rather than 'pixelly'.
Now we have our effect definition.
[code:2lblvyj0]// Effect function
float4 EffectProcess( float2 Tex : TEXCOORD0 ) : COLOR0
{
float4 front = tex2D(foreground, Tex.xy);
float4 back = tex2D(background, Tex.xy);
front.a *= back.a;
front.rgb *= back.rgb * intensity;
return front;
}[/code:2lblvyj0]
This is the actual function which calculates every single pixel. It's best to write the function as simple as possible, because the fx file is converted into a machine language which is optimised and the shaders read.
[code:2lblvyj0]tex2D(foreground, Tex.xy);[/code:2lblvyj0]
the tex2D function obtains a pixel colour from a sampler.
float4 structures are awesome. You can write stuff like: front *= 2 and the a,r,g,b values all get doubled, or front.rgb * 2 will multiply only red, green, blue, or you can refer to them individually as front.r, front.g, front.b, etc.
these float values are all between 0-1, and if you want to add two colours together you simply write
front.rgb + back.rgb.
Finally we have our effect definition
[code:2lblvyj0]// ConstructEffect
technique ConstructEffect
{
pass p0
{
VertexShader = null;
PixelShader = compile ps_2_0 EffectProcess();
}
}[/code:2lblvyj0]
All our shaders tend to either be ps_2_0 or ps_1_4
The pixel shader definition determines what functions can be used, and how many lines of instructions you can have per shader.