Texture Combiners
Texture combiners became core in GL 1.3. You can combine by multiplying, replacing, adding, subtracting, or doing a DOT3 product.
GL 1.4 added to the core a crossbar feature. This means that you sample GL_TEXTUREX from any other texture image unit (TIU).
For example, at TUI 4, you can sample GL_TEXTURE0 or GL_TEXTURE1 or GL_TEXTURE2 or GL_TEXTURE3.
The examples here also show the equivalent shader code in GLSL to encourage people to use shaders instead of the fixed pipeline.
Example : multiply tex0 and tex1
The keyword here is GL_MODULATE, which does the actual multiplication.
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID0); //Simply sample the texture glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); //------------------------ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureID1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); //Sample RGB, multiply by previous texunit result glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); //Modulate RGB with RGB glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); //Sample ALPHA, multiply by previous texunit result glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); //Modulate ALPHA with ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
The equivalent with GL 2.0 shaders
//Fragment shader uniform sampler2D Texture0; uniform sampler2D Texture1; //------------------------ varying vec2 TexCoord0; varying vec2 TexCoord1; //Or just use TexCoord0 //------------------------ void main() { vec4 texel = texture2D(Texture0, TexCoord0); texel *= texture2D(Texture1, TexCoord1); gl_FragColor = texel; }
Example : Blend tex0 and tex1 based on a blending factor you supply
The keyword here is GL_INTERPOLATE.
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); //------------------------ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureID1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); //Interpolate RGB with RGB glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); //GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); //------------------------ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE); //Interpolate ALPHA with ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); //GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); //------------------------ float mycolor[4]; mycolor[0]=mycolor[1]=mycolor[2]=0.0; //RGB doesn't matter since we are not using it mycolor[3]=0.75; //Set the blend factor with this glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor);
The equivalent with GL 2.0 shaders
//Fragment shader uniform sampler2D Texture0; uniform sampler2D Texture1; uniform float BlendFactor; //------------------------ varying vec2 TexCoord0; varying vec2 TexCoord1; //Or just use TexCoord0 //------------------------ void main() { vec4 texel0 = texture2D(Texture0, TexCoord0); vec4 texel1 = texture2D(Texture1, TexCoord1); gl_FragColor = mix(texel0, texel1, BlendFactor); }
Example : Blend tex0 and tex1 based on alpha of tex0
The keyword here is GL_INTERPOLATE.
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); //------------------------ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureID1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); //Interpolate RGB with RGB glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); //------------------------ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE); //Interpolate ALPHA with ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
The equivalent with GL 2.0 shaders
//Fragment shader uniform sampler2D Texture0; uniform sampler2D Texture1; //------------------------ varying vec2 TexCoord0; varying vec2 TexCoord1; //Or just use TexCoord0 //------------------------ void main() { vec4 texel0 = texture2D(Texture0, TexCoord0); vec4 texel1 = texture2D(Texture1, TexCoord1); gl_FragColor = mix(texel0, texel1, texel0.a); }
Example : Blend tex1 and tex2 based on alpha of tex0
The keyword here is GL_INTERPOLATE.
tex0's ALPHA is the mask.
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); //------------------------ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureID1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DECAL); //Get RGB of this texture (tex1) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); //------------------------ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_DECAL); //Get ALPHA of previous TUI (tex0) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureID2); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); //Interpolate RGB with RGB glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); //------------------------ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE); //Interpolate ALPHA with ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
With shaders, things are much more flexible.
//Fragment shader uniform sampler2D Texture0; //Mask uniform sampler2D Texture1; uniform sampler2D Texture2; //------------------------ varying vec2 TexCoord0; //------------------------ void main() { vec4 texel0 = texture2D(Texture0, TexCoord0); vec4 texel1 = texture2D(Texture1, TexCoord0); vec4 texel2 = texture2D(Texture2, TexCoord0); gl_FragColor = mix(texel1, texel2, texel0.a); }
In this one, we place the mask at TIU 2
//Fragment shader uniform sampler2D Texture0; uniform sampler2D Texture1; uniform sampler2D Texture2; //Mask //------------------------ varying vec2 TexCoord0; //------------------------ void main() { vec4 texel0 = texture2D(Texture0, TexCoord0); vec4 texel1 = texture2D(Texture1, TexCoord0); vec4 texel2 = texture2D(Texture2, TexCoord0); gl_FragColor = mix(texel0, texel1, texel2.a); }
Example : Add tex0 and tex1
The keyword here is GL_ADD.
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //------------------------ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureID1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); //Add RGB with RGB glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); //------------------------ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD); //Add ALPHA with ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
The equivalent with GL 2.0 shaders
//Fragment shader uniform sampler2D Texture0; uniform sampler2D Texture1; //------------------------ varying vec2 TexCoord0; //------------------------ void main() { vec4 texel0 = texture2D(Texture0, TexCoord0); vec4 texel1 = texture2D(Texture1, TexCoord0); gl_FragColor = clamp(texel0 + texel1, 0.0, 1.0); }