Edit: Here's the shader in a demo oxp
http://www.box.net/shared/4h8aykmzjg
Here's the multiple decal shader from Ramirez's Feudal States oxp
I'm hoping it works OK, it's running fine on a pc with an Nvidia Geforce FX 5200 in it. I haven't tested it yet but a similar shader wouldn't run on a pc with an Nvidia 8800GTS in it, the error seems to be related to the line where the texture is rotated
decal_TexCoord *= mat2(decal_c, decal_s, -decal_s, decal_c);
it doesn't like the *=
I've tried to make the decal placing code more generic, it can now be called multiple times in the main shader code, and each time you call it you can pass it different decal placement info as a uniform vec4
vertex shader (it's the same same as before)
Code: Select all
varying vec3 v_normal; // Surface normal
varying vec3 v_pos; // Vertex/fragment position in eye space
void main()
{
v_normal = normalize(gl_NormalMatrix * gl_Normal);
v_pos = vec3(gl_ModelViewMatrix * gl_Vertex);
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
fragment shader
Code: Select all
// Texture Information from Oolite.
uniform sampler2D tex0; // Difuse and Illumination map
uniform sampler2D tex1; // Decal Texture
// Uniforms from Oolite
uniform float uDecalSelect; // used to decide which decal to select
uniform vec4 Decal1SettingsUniform; // position settings for decal 1
uniform vec4 Decal2SettingsUniform; // position settings for decal 2
/*
the decal settings vec4's should be made up of the following data - in this order!
vec4(Decal_S_pos, Decal_T_pos, Decal Size, Decal Orientation) eg
in the shader/uniforms setion of shipdata.plist you'd write something like
Decal1SettingsUniform = { type = vector; value = "0.38 0.9 9.0 0.78540"; };
Decal2SettingsUniform = { type = vector; value = "0.98 0.9 9.0 -0.78540"; };
Decal_S_pos & Decal_T_pos controll where your decal will be placed on your ships
unfolded UV map and thus where it will appear on your ships hull in the game
Decal Size controls how big to draw the decal (smaller number = bigger decal)
Decal Orientation controls the amount of rotation to apply to the decal
*/
// Information from vertex shader.
varying vec3 v_normal; // Surface normal
varying vec3 v_pos; // Vertex/fragment position in eye space
// Constants
const float specExponent = 2.0;
const float kDecalCount = 4.0; // Number of decals in your idecal image texture
/*
"the_decaliser" - this function scales & positions the decal image using data passed
to it from the main shader (see lines 105 & 106 below)
*/
vec4 the_decaliser(vec4 Your_Decal_Settings)
{
vec2 baseTexCoord = gl_TexCoord[0].st;
// Setup the basic texture co-ords for the decals
vec2 decal_TexCoord = baseTexCoord;
// Position the decal
decal_TexCoord -= vec2(Your_Decal_Settings.s, Your_Decal_Settings.t - (0.5 / Your_Decal_Settings.p));
// Orientate & scale the decal
float decal_s = sin(Your_Decal_Settings.q);
float decal_c = cos(Your_Decal_Settings.q);
decal_TexCoord *= mat2(decal_c, decal_s, -decal_s, decal_c);
decal_TexCoord += vec2(0.5 / Your_Decal_Settings.p);
decal_TexCoord *= vec2(Your_Decal_Settings.p / kDecalCount, Your_Decal_Settings.p);
// Select the desired decal from the set.
float offset = floor(uDecalSelect * kDecalCount) / kDecalCount;
decal_TexCoord.s += offset;
// Get texture values.
vec4 decal_Tex = texture2D(tex1, decal_TexCoord);
// Modify the Decals texture co-oords
decal_Tex *= step(offset, decal_TexCoord.s) *
step(0.0, decal_TexCoord.t) *
step(-1.0 / kDecalCount - offset, -decal_TexCoord.s) *
step(-1.0, -decal_TexCoord.t);
// Use the Alpha in the decal as a transparency mask so you can 'cutout' your decal from it's background
float alpha = decal_Tex.a;
// Return the scaled, position & rotated decal, it's mixed into the colour texture further on in the shader .
return alpha * decal_Tex; // decal_Tex;
}
// Calculate the contribution of a single light. Ought to be a function, but OS X's GLSlang implementation isn't sufficiently clever.
#define LIGHT(idx) \
{ \
vec3 lightVector = normalize(gl_LightSource[idx].position.xyz); \
vec3 reflection = normalize(-reflect(lightVector, v_normal)); \
diffuse += gl_FrontMaterial.diffuse * gl_LightSource[idx].diffuse * max(dot(v_normal, lightVector), 0.0); \
specular += gl_LightSource[idx].diffuse * pow(max(dot(reflection, eyeVector), 0.0), specExponent); \
}
void main(void)
{
vec4 diffuse = vec4(0.0), specular = vec4(0.0);
vec3 eyeVector = normalize(-v_pos);
// Load texture data
vec2 texCoord = gl_TexCoord[0].st;
vec4 colorMap = texture2D(tex0, texCoord);
// calculate specular effects
float specIntensity = 0.1;
/* Light 0 is the "showroom" light, used in the demo screen and shipyard.
Light 1 is the sun.
*/
#ifdef OO_LIGHT_0_FIX
LIGHT(0);
#endif
LIGHT(1);
diffuse += gl_FrontMaterial.ambient * gl_LightModel.ambient;
// Calculate the lighting for full shader mode, (adds in the decals)
#ifndef OO_REDUCED_COMPLEXITY
vec4 color = diffuse * colorMap; // set up the basic colour texture...
/* .. then apply the decals on top of it, if you need more decals , set up extra DecalXSettingsUniforms
// and duplicate the line below modifying the 'Decal2SettingsUniform' so it's the same as
// your new uniform */
color += diffuse * the_decaliser(Decal1SettingsUniform); // apply decal 2
color += diffuse * the_decaliser(Decal2SettingsUniform); // apply decal 2
color += specular * specIntensity; // add in the lighting
#endif
// Calculate the lighting for simple shader mode
#ifdef OO_REDUCED_COMPLEXITY
vec4 color = diffuse * colorMap + specular * specIntensity;
#endif
// Output final color
gl_FragColor = vec4(color.rgb, 1.0);
}
This example places 2 decals, if you need more, then simply add more uniforms to place the decal and edit the fragment shader so it runs the 'the_decaliser' function for each new decal (see lines 106 & 107 for examples, add your new lines below these.)
When copy & pasting this code, check there's no spaces after the \ at the end of every line in the LIGHT macro, ther must be nothing after the \ or the shader won't work and you'll get a flood of syntax errors reported in the log.
The shader will use the alpha channel in the decalimage to cut out any unwanted background image, shades of grey in the alpha channel will control various levels of transparency when the decal texture is mided into the diffuse texture, with black being fully transparent and white being fully opaque.