I'll have a go at explaining things too (the Vortex shader mentioned above). Below are the code snippets from shipdata.plist, the vertex shader and the fragment shaders. They are similar to Griff's ones previously explained, but are simplified so may be followable?
Shipdata.plist (the relevant shader bits anyway)
Code: Select all
materials = {
"vortex_player.png" = {
diffuse_map = "vortex_player.png";
emission_map = "vortex_playerEm.png";
};
};
shaders = {
"vortex_player.png" =
{
vertex_shader = "vortex_general.vertex";
fragment_shader = "vortex_general.fragment";
textures =
(
"vortex_player.png",
"vortex_playerEm.png"
);
uniforms =
{
uColorMap = { type = texture; value = 0; };
uEmissionMap = { type = texture; value = 1; };
speedFactor = { binding = "speedFactor"; clamped = true; };
hull_heat_level = "hullHeatLevel";
};
};
};
The materials bit is for non-shader machines, but I'll include it for completeness. It just means that without shaders the emission map (the engine glow) is applied at full brightness only, without any speed dependence.
Here we define the shaders used for the ship, and which texture on the model they relate to (vortex_player.png in this case, the ships texture file). We simply define the vertex and fragment shaders to be used (the two quoted below) and which textures are involved. The first texture (which will be texture 0) is the main texture (the color map) and the second one (which will be texture 1) is the emission map (used here for the speed dependent engine glow).
The uniforms are the items which the game engine passes to the shader. Here we link those two maps to uColorMap and uEmissionMap (note the value of 0 and 1 corresponding to their position in the textures array) plus we are also passing the ships speedFactor and hull heat level. Clamped just limits the output value to be between 0 and 1.
Vertex Shader
Code: Select all
// Information sent to fragment shader.
varying vec3 v_normal; // Surface normal
void main()
{
v_normal = normalize(gl_NormalMatrix * gl_Normal);
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_Position = ftransform();
}
This is a variation on the shader Griff posted before, and does exactly the same job. It is a fairly standard one which just passes the information across to the fragment shader, defining in turn each point on the model texture that the fragment shader needs to act (see the quote I posted previously for some more details).
Fragment shader
Code: Select all
// Information from Oolite.
uniform sampler2D uColorMap; // Main texture
uniform sampler2D uEmissionMap; // Engine glows, speedFactor dependent
uniform float hull_heat_level;
uniform float speedFactor;
// Information from vertex shader.
varying vec3 v_normal;
#define LIGHT(idx) { vec3 lightVector = normalize(gl_LightSource[idx].position.xyz); color += gl_FrontMaterial.diffuse * gl_LightSource[idx].diffuse * max(dot(v_normal, lightVector), 0.0); }
void main(void)
{
// Calculate illumination.
vec4 color = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
LIGHT(1);
// Load texture data
vec2 texCoord = gl_TexCoord[0].st;
vec4 colorMap = texture2D(uColorMap, texCoord);
vec4 emissionMap = texture2D(uEmissionMap, texCoord);
// Add the all over hull temperature glow.
float hullHeat = max(hull_heat_level - 0.5, 0.0) * 2.0;
colorMap.r += hullHeat;
color *= colorMap;
// Add the engine exhaust glow, controlled by speed factor
color += (speedFactor * emissionMap);
gl_FragColor = vec4(color.rgb, 1.0);
}
At the top we define the variables used within the shader - those we passed from the shipdata.plist (see the code at the top of this post).
The "light" definition again just defines the illumination point. It's either "spotlight" mode for demoships illumination (with idx=0) or in-game illumination (idx=1). In this shader we'll use the latter.
The main chunk of the code takes the illumination at the point we're dealing with, and then reads the colour of the two maps (colorMap and emissionMap) at the co-ordinates we are currently dealing with (as sent by the vertex shader).
Next we modify the colorMap's red level based on the hull heat level (to make the ship glow red when hot). colorMap.r is just the red component of the colorMap (the colour of the texture at the point we're dealing with). We write this to "color", which is the cumulative colour which will be displayed at the end (what you'll see on the screen).
After that we deal with the engine glow, but adding a speed-weighted value of the emission map to the running "color" total. As that emission map is black everywhere but the engine area, it doesn't affect anywhere else but the engine ports. There it is a blue colour, so as the ship goes faster the engines glow more brightly blue.
Lastly we set gl_FragColor, which is the final colour of the ship at the co-ordinates on its surface. Here we set this to the red/green/blue components of "color", plus 1.0 for the alpha channel (the transparency - here we just fix that to 1.0).
Basically the vertex shader just raster-scans across the model texture, going from point to point. At each of those points the fragment shader is applied, so we build up the whole output texture which is what appears on the screen and in the game.[/color]