Posted: Tue Oct 09, 2007 9:58 pm
Right. Oolite’s model format only allows for one set of texture co-ordinates, so if you want to work with multiple textures you need to work out the relationships between the textures in the GLSL code. For things like specular maps and glow maps, you generally want all the textures to have the same co-ordinates anyway. For a decal, you’ll need to apply a transformation to the texture co-ordinates.Arexack_Heretic wrote:I guess decals would only be practical for vehicles that all use the same texture/model and are expected to have decals? Racers, police etc.
As each different model would need to have a different decal-shader...in order to apply the effect on the right place on the model... ?
...
Not sure how exactly tex1 is mapped on tex0 (which is AFAIK the model-base-texture.) I'll figure it out...someday
For a concrete example, let’s take a Cobra 3:
and apply this highly original decal to the bottom:
First, lets have the base texture with the decal composited on top:
Code: Select all
uniform sampler2D uBaseTexture;
uniform sampler2D uDecalTexture;
void main()
{
vec2 baseTexCoord = gl_TexCoord[0].st;
// Calculate decal texture co-ordinates.
vec2 decalTexCoord = baseTexCoord;
// Get texture values.
vec4 baseTex = texture2D(uBaseTexture, baseTexCoord);
vec4 decalTex = texture2D(uDecalTexture, decalTexCoord);
// Composite decal over base.
float alpha = decalTex.a;
vec4 color = baseTex * (1.0 - alpha) + decalTex * alpha;
// Insert lighting calculations here
gl_FragColor = color;
}
Code: Select all
const float kDecalSize = 1.0/9.0;
...
vec2 decalTexCoord = baseTexCoord;
decalTexCoord /= kDecalSize;
Code: Select all
vec4 decalTex = texture2D(uDecalTexture, decalTexCoord);
decalTex *= step(0.0, decalTexCoord.s) *
step(0.0, decalTexCoord.t) *
step(-1.0, -decalTexCoord.s) *
step(-1.0, -decalTexCoord.t);
It is especially important to avoid writing code like:
Code: Select all
if (/* coords are inside texture */)
{
// do alpha blending here
}
else
{
// just use the base texture
}
Anyway, we now have a clipped decal in the top-left corner of the base texture. All that remains is to move it to the right place, which is a simple matter of adding the required offset to the texture co-ordinates… or rather, of subtracting it. (If you want the decal’s left edge to be at 0.2, you want decalTexCoord.s to be 0 when baseTex.s is 0.2, so you subtract 0.2.)
This can be done either before or after scaling the texture co-ordinates; I chose before, so we’re working in units of the base texture co-ordinate system. We want to offset the s co-ordinate some amount to the right, and we want the t co-ordinate to be right in the middle. To get it in the middle, we use an offset of 0.5 minus half the height of the decal.
Code: Select all
vec2 decalTexCoord = baseTexCoord;
decalTexCoord -= vec2(kDecalS, 0.5 - (0.5 * kDecalSize));
decalTexCoord *= kDecalSize;
Complete shader:
Code: Select all
uniform sampler2D uBaseTexture;
uniform sampler2D uDecalTexture;
const float kDecalSize = 1.0/9.0;
const float kDecalS = 0.35;
void main()
{
vec2 baseTexCoord = gl_TexCoord[0].st;
// Calculate decal texture co-ordinates.
vec2 decalTexCoord = baseTexCoord;
decalTexCoord -= vec2(kDecalS, 0.5 - (0.5 * kDecalSize));
decalTexCoord /= kDecalSize;
// Get texture values.
vec4 baseTex = texture2D(uBaseTexture, baseTexCoord);
vec4 decalTex = texture2D(uDecalTexture, decalTexCoord);
decalTex *= step(0.0, decalTexCoord.s) *
step(0.0, decalTexCoord.t) *
step(-1.0, -decalTexCoord.s) *
step(-1.0, -decalTexCoord.t);
// Composite decal over base.
float alpha = decalTex.a;
vec4 color = baseTex * (1.0 - alpha) + decalTex * alpha;
// Insert lighting calculations here
gl_FragColor = color;
}
This shader allows you to add a static decal that’s more detailed than the base texture, but generally you’ll want to select a decal from a set. The technique used in the animation shader should be easy to adapt. Instead of universalTime, bind the controlling uniform to entityPersonality to select a random decal for each ship, or use a Behemoth-like technique with multiple shipdata.plist entries with different constant uniforms. (To specify a constant float uniform, use { uDecalOffset = { type = "float"; value = "0.25"; }} in the uniforms list.)
Oh, yeah… on the topic of the Behemoth technique, I should probably point out that you can replace textures on a model using the materials dictionary, without requiring shaders at all. But you can’t select a part of a texture this way, so the name signs would have to be put in separate files.