Difference between revisions of "Texture Combiners"
(Adding vertex shader) |
|||
(19 intermediate revisions by 3 users not shown) | |||
Line 24: | Line 24: | ||
=== Example : multiply tex0 and tex1 === | === Example : multiply tex0 and tex1 === | ||
The keyword here is GL_MODULATE, which does the actual multiplication. | The keyword here is GL_MODULATE, which does the actual multiplication. | ||
+ | |||
+ | Mathematically, it look like this | ||
+ | result_rgb = texture0_rgb // Just read the texture | ||
+ | result_a = texture0_a | ||
+ | result_rgb = result_rgb * texture1_rgb | ||
+ | result_a = result_a * texture1_a | ||
+ | |||
+ | The setup code for the Texture Combiners will look like this | ||
+ | <source lang="c"> | ||
glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID0); | glBindTexture(GL_TEXTURE_2D, textureID0); | ||
− | //Simply sample the texture | + | // Simply sample the texture |
− | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, | + | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
− | // | + | // -------------------- |
glActiveTexture(GL_TEXTURE1); | glActiveTexture(GL_TEXTURE1); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID1); | glBindTexture(GL_TEXTURE_2D, textureID1); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | ||
− | //Sample RGB, multiply by previous texunit result | + | // 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_COMBINE_RGB, GL_MODULATE); // Modulate RGB with RGB |
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); | 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_OPERAND1_RGB, GL_SRC_COLOR); | ||
− | //Sample ALPHA, multiply by previous texunit result | + | // 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_COMBINE_ALPHA, GL_MODULATE); // Modulate ALPHA with ALPHA |
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); | 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_OPERAND1_ALPHA, GL_SRC_ALPHA); | ||
− | + | </source> | |
The equivalent with GL 2.0 shaders | The equivalent with GL 2.0 shaders | ||
− | //Vertex shader | + | <source lang="glsl"> |
+ | // Vertex shader | ||
#version 110 | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | attribute vec2 InTexCoord1; | ||
uniform mat4 ProjectionModelviewMatrix; | uniform mat4 ProjectionModelviewMatrix; | ||
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | varying vec2 TexCoord1; //Or just use TexCoord0 | + | varying vec2 TexCoord1; // Or just use TexCoord0 |
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
− | gl_Position = ProjectionModelviewMatrix * | + | gl_Position = ProjectionModelviewMatrix * InVertex; |
− | TexCoord0 = | + | TexCoord0 = InTexCoord0; |
− | TexCoord1 = | + | TexCoord1 = InTexCoord1; |
} | } | ||
− | + | </source> | |
− | //Fragment shader | + | |
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
#version 110 | #version 110 | ||
uniform sampler2D Texture0; | uniform sampler2D Texture0; | ||
uniform sampler2D Texture1; | uniform sampler2D Texture1; | ||
− | // | + | // -------------------- |
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | varying vec2 TexCoord1; //Or just use TexCoord0 | + | varying vec2 TexCoord1; // Or just use TexCoord0 |
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
Line 73: | Line 90: | ||
gl_FragColor = texel; | gl_FragColor = texel; | ||
} | } | ||
+ | </source> | ||
=== Example : Blend tex0 and tex1 based on a blending factor you supply === | === Example : Blend tex0 and tex1 based on a blending factor you supply === | ||
The keyword here is GL_INTERPOLATE. | The keyword here is GL_INTERPOLATE. | ||
+ | <source lang="c"> | ||
glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID0); | glBindTexture(GL_TEXTURE_2D, textureID0); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, | + | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
− | // | + | // -------------------- |
glActiveTexture(GL_TEXTURE1); | glActiveTexture(GL_TEXTURE1); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID1); | glBindTexture(GL_TEXTURE_2D, textureID1); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); | + | 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_SOURCE0_RGB, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | 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) | + | // 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_SOURCE2_RGB, GL_CONSTANT); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); | 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_OPERAND1_RGB, GL_SRC_COLOR); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_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_COMBINE_ALPHA, GL_INTERPOLATE); // Interpolate ALPHA with ALPHA |
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | 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) | + | // 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_SOURCE2_ALPHA, GL_CONSTANT); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); | 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_OPERAND1_ALPHA, GL_SRC_ALPHA); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); | ||
− | // | + | // -------------------- |
float mycolor[4]; | float mycolor[4]; | ||
− | mycolor[0]=mycolor[1]=mycolor[2]=0.0; //RGB doesn't matter since we are not using it | + | 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 | + | mycolor[3]=0.75; // Set the blend factor with this |
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor); | glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor); | ||
− | + | </source> | |
The equivalent with GL 2.0 shaders | The equivalent with GL 2.0 shaders | ||
− | //Vertex shader | + | <source lang="glsl"> |
+ | // Vertex shader | ||
#version 110 | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | attribute vec2 InTexCoord1; | ||
uniform mat4 ProjectionModelviewMatrix; | uniform mat4 ProjectionModelviewMatrix; | ||
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | varying vec2 TexCoord1; //Or just use TexCoord0 | + | varying vec2 TexCoord1; // Or just use TexCoord0 |
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
− | gl_Position = ProjectionModelviewMatrix * | + | gl_Position = ProjectionModelviewMatrix * InVertex; |
− | TexCoord0 = | + | TexCoord0 = InTexCoord0; |
− | TexCoord1 = | + | TexCoord1 = InTexCoord1; |
} | } | ||
− | + | </source> | |
− | //Fragment shader | + | |
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
#version 110 | #version 110 | ||
uniform sampler2D Texture0; | uniform sampler2D Texture0; | ||
uniform sampler2D Texture1; | uniform sampler2D Texture1; | ||
uniform float BlendFactor; | uniform float BlendFactor; | ||
− | // | + | // -------------------- |
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | varying vec2 TexCoord1; //Or just use TexCoord0 | + | varying vec2 TexCoord1; // Or just use TexCoord0 |
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
Line 135: | Line 162: | ||
gl_FragColor = mix(texel0, texel1, BlendFactor); | gl_FragColor = mix(texel0, texel1, BlendFactor); | ||
} | } | ||
− | + | </source> | |
=== Example : Blend tex0 and tex1 based on alpha of tex0 === | === Example : Blend tex0 and tex1 based on alpha of tex0 === | ||
The keyword here is GL_INTERPOLATE. | The keyword here is GL_INTERPOLATE. | ||
+ | <source lang="c"> | ||
glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID0); | glBindTexture(GL_TEXTURE_2D, textureID0); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, | + | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
− | // | + | // -------------------- |
glActiveTexture(GL_TEXTURE1); | glActiveTexture(GL_TEXTURE1); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID1); | glBindTexture(GL_TEXTURE_2D, textureID1); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); | + | 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_SOURCE0_RGB, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | ||
Line 152: | Line 182: | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_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_OPERAND2_RGB, GL_SRC_ALPHA); | ||
− | // | + | // -------------------- |
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE); | + | 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_SOURCE0_ALPHA, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | ||
Line 160: | Line 190: | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); | ||
+ | </source> | ||
The equivalent with GL 2.0 shaders | The equivalent with GL 2.0 shaders | ||
− | //Fragment shader | + | <source lang="glsl"> |
+ | // Vertex shader | ||
+ | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | attribute vec2 InTexCoord1; | ||
+ | uniform mat4 ProjectionModelviewMatrix; | ||
+ | varying vec2 TexCoord0; | ||
+ | varying vec2 TexCoord1; // Or just use TexCoord0 | ||
+ | // -------------------- | ||
+ | void main() | ||
+ | { | ||
+ | gl_Position = ProjectionModelviewMatrix * InVertex; | ||
+ | TexCoord0 = InTexCoord0; | ||
+ | TexCoord1 = InTexCoord1; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
+ | #version 110 | ||
uniform sampler2D Texture0; | uniform sampler2D Texture0; | ||
uniform sampler2D Texture1; | uniform sampler2D Texture1; | ||
− | // | + | // -------------------- |
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | varying vec2 TexCoord1; //Or just use TexCoord0 | + | varying vec2 TexCoord1; // Or just use TexCoord0 |
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
Line 175: | Line 225: | ||
gl_FragColor = mix(texel0, texel1, texel0.a); | gl_FragColor = mix(texel0, texel1, texel0.a); | ||
} | } | ||
+ | </source> | ||
+ | === Example : Blend tex1 and tex2 based on alpha of tex0 === | ||
+ | The keyword here is GL_INTERPOLATE. | ||
− | |||
− | |||
− | |||
tex0's ALPHA is the mask. | tex0's ALPHA is the mask. | ||
+ | <source lang="c"> | ||
glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID0); | glBindTexture(GL_TEXTURE_2D, textureID0); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, | + | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
− | // | + | // -------------------- |
glActiveTexture(GL_TEXTURE1); | glActiveTexture(GL_TEXTURE1); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID1); | glBindTexture(GL_TEXTURE_2D, textureID1); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, | + | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); // Get RGB of this texture (tex1) |
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); | ||
− | // | + | // -------------------- |
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, | + | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); // Get ALPHA of previous TUI (tex0) |
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); | ||
glActiveTexture(GL_TEXTURE2); | glActiveTexture(GL_TEXTURE2); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID2); | glBindTexture(GL_TEXTURE_2D, textureID2); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | ||
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); | + | 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_SOURCE0_RGB, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | ||
Line 204: | Line 258: | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_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_OPERAND2_RGB, GL_SRC_ALPHA); | ||
− | // | + | // -------------------- |
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE); | + | 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_SOURCE0_ALPHA, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | ||
Line 212: | Line 266: | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); | ||
− | + | </source> | |
With shaders, things are much more flexible. | With shaders, things are much more flexible. | ||
− | //Fragment shader | + | <source lang="glsl"> |
− | uniform sampler2D Texture0; //Mask | + | // Vertex shader |
+ | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | uniform mat4 ProjectionModelviewMatrix; | ||
+ | varying vec2 TexCoord0; | ||
+ | // -------------------- | ||
+ | void main() | ||
+ | { | ||
+ | gl_Position = ProjectionModelviewMatrix * InVertex; | ||
+ | TexCoord0 = InTexCoord0; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
+ | #version 110 | ||
+ | uniform sampler2D Texture0; // Mask | ||
uniform sampler2D Texture1; | uniform sampler2D Texture1; | ||
uniform sampler2D Texture2; | uniform sampler2D Texture2; | ||
− | // | + | // -------------------- |
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
Line 228: | Line 298: | ||
gl_FragColor = mix(texel1, texel2, texel0.a); | gl_FragColor = mix(texel1, texel2, texel0.a); | ||
} | } | ||
− | + | </source> | |
− | In this one, we place the mask at TIU 2 | + | In this one, we place the mask at TIU 2 (You can in fact have your texture with the alpha mask on any TIU you want) |
− | //Fragment shader | + | <source lang="glsl"> |
+ | // Vertex shader | ||
+ | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | uniform mat4 ProjectionModelviewMatrix; | ||
+ | varying vec2 TexCoord0; | ||
+ | // -------------------- | ||
+ | void main() | ||
+ | { | ||
+ | gl_Position = ProjectionModelviewMatrix * InVertex; | ||
+ | TexCoord0 = InTexCoord0; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
+ | #version 110 | ||
uniform sampler2D Texture0; | uniform sampler2D Texture0; | ||
uniform sampler2D Texture1; | uniform sampler2D Texture1; | ||
− | uniform sampler2D Texture2; | + | uniform sampler2D Texture2; // Mask |
− | // | + | // -------------------- |
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
Line 244: | Line 330: | ||
gl_FragColor = mix(texel0, texel1, texel2.a); | gl_FragColor = mix(texel0, texel1, texel2.a); | ||
} | } | ||
− | + | </source> | |
=== Example : Add tex0 and tex1 === | === Example : Add tex0 and tex1 === | ||
The keyword here is GL_ADD. | The keyword here is GL_ADD. | ||
+ | <source lang="c"> | ||
glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID0); | glBindTexture(GL_TEXTURE_2D, textureID0); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | ||
− | // | + | // -------------------- |
glActiveTexture(GL_TEXTURE1); | glActiveTexture(GL_TEXTURE1); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
glBindTexture(GL_TEXTURE_2D, textureID1); | glBindTexture(GL_TEXTURE_2D, textureID1); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | 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_COMBINE_RGB, GL_ADD); // Add RGB with RGB |
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); | 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_OPERAND1_RGB, GL_SRC_COLOR); | ||
− | // | + | // -------------------- |
− | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD); //Add ALPHA with ALPHA | + | 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_SOURCE0_ALPHA, GL_PREVIOUS); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); | ||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); | 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_OPERAND1_ALPHA, GL_SRC_ALPHA); | ||
− | + | </source> | |
The equivalent with GL 2.0 shaders | The equivalent with GL 2.0 shaders | ||
− | //Fragment shader | + | <source lang="glsl"> |
+ | // Vertex shader | ||
+ | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | uniform mat4 ProjectionModelviewMatrix; | ||
+ | varying vec2 TexCoord0; | ||
+ | // -------------------- | ||
+ | void main() | ||
+ | { | ||
+ | gl_Position = ProjectionModelviewMatrix * InVertex; | ||
+ | TexCoord0 = InTexCoord0; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
+ | #version 110 | ||
uniform sampler2D Texture0; | uniform sampler2D Texture0; | ||
uniform sampler2D Texture1; | uniform sampler2D Texture1; | ||
− | // | + | // -------------------- |
varying vec2 TexCoord0; | varying vec2 TexCoord0; | ||
− | // | + | // -------------------- |
void main() | void main() | ||
{ | { | ||
Line 279: | Line 384: | ||
gl_FragColor = clamp(texel0 + texel1, 0.0, 1.0); | gl_FragColor = clamp(texel0 + texel1, 0.0, 1.0); | ||
} | } | ||
+ | </source> | ||
+ | === Example : Interpolate tex0 and tex1 and multiply the result=== | ||
+ | This shows one of the limitations of Texture Combiners and how Shaders really come to the rescue. But at least, this case can be done with Texture Combiners! | ||
+ | |||
+ | From looking at the above examples, you have already noticed how texture image units and texcoord are not decoupled in Texture Combiners. This example also shows this. | ||
+ | |||
+ | Mathematically, we want to do | ||
+ | result_rgb = (Tex0_rgb * factor) + (Tex1_rgb * (1 - factor)) // Interpolate | ||
+ | result_rgb = result_rgb * color_rgb // Multiply by a color factor | ||
+ | |||
+ | Tex0 can be placed on Texture Image Unit (TIU) 0 and Tex1 can be placed on TIU 1. For doing color_rgb, you are going to need another TIU. You have to bind a dummy texture and activate the TIU. You aren't forced to send texcoords for TIU 2. | ||
+ | |||
+ | Here is the Texture Combiner setup code : | ||
+ | <source lang="c"> | ||
+ | glActiveTexture(GL_TEXTURE0); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
+ | glBindTexture(GL_TEXTURE_2D, textureID0); | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | ||
+ | // -------------------- | ||
+ | glActiveTexture(GL_TEXTURE1); | ||
+ | glEnable(GL_TEXTURE_2D); | ||
+ | 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_REPLACE); | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); // REPLACE just need a SOURCE0 and OPERAND0 | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_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); | ||
+ | glActiveTexture(GL_TEXTURE2); | ||
+ | glEnable(GL_TEXTURE_2D); // Activate the unit | ||
+ | glBindTexture(GL_TEXTURE_2D, dummyTexture); | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); | ||
+ | // GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2) | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_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_COMBINE_ALPHA, GL_REPLACE); | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT); // REPLACE just need a SOURCE0 and OPERAND0 | ||
+ | glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); | ||
+ | // -------------------- | ||
+ | float mycolor2[4]; | ||
+ | mycolor2[0]=0.6; // Red | ||
+ | mycolor2[1]=0.8; // Green | ||
+ | mycolor2[2]=1.0; // Blue | ||
+ | mycolor2[3]=1.0; // Alpha | ||
+ | // This glTexEnvfv call is loaded on TIU 2 because of the call to glActiveTexture(GL_TEXTURE2) | ||
+ | glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2); | ||
+ | </source> | ||
+ | So the above Texture Combiner setup looks really complicated and nasty. The Shader version will look like this. | ||
+ | |||
+ | The equivalent with GL 2.0 shaders | ||
+ | <source lang="glsl"> | ||
+ | // Vertex shader | ||
+ | #version 110 | ||
+ | attribute vec4 InVertex; | ||
+ | attribute vec2 InTexCoord0; | ||
+ | attribute vec2 InTexCoord1; | ||
+ | uniform mat4 ProjectionModelviewMatrix; | ||
+ | varying vec2 TexCoord0; | ||
+ | varying vec2 TexCoord1; // Or just use TexCoord0 | ||
+ | // -------------------- | ||
+ | void main() | ||
+ | { | ||
+ | gl_Position = ProjectionModelviewMatrix * InVertex; | ||
+ | TexCoord0 = InTexCoord0; | ||
+ | TexCoord1 = InTexCoord1; | ||
+ | } | ||
+ | </source> | ||
+ | <source lang="glsl"> | ||
+ | // Fragment shader | ||
+ | #version 110 | ||
+ | uniform sampler2D Texture0; | ||
+ | uniform sampler2D Texture1; | ||
+ | uniform float BlendFactor; | ||
+ | uniform vec4 ColorFactor; | ||
+ | // -------------------- | ||
+ | varying vec2 TexCoord0; | ||
+ | varying vec2 TexCoord1; // Or just use TexCoord0 | ||
+ | // -------------------- | ||
+ | void main() | ||
+ | { | ||
+ | vec4 ColorResult; | ||
+ | vec4 texel0 = texture2D(Texture0, TexCoord0); | ||
+ | vec4 texel1 = texture2D(Texture1, TexCoord1); | ||
+ | ColorResult = mix(texel0, texel1, BlendFactor); | ||
+ | gl_FragColor = ColorResult * ColorFactor; | ||
+ | } | ||
+ | </source> | ||
+ | The shader above is using custom attributes InVertex, InTexCoord0 and InTexCoord1. It is using 2 texcoord inputs although perhaps you don't need 2 if both will be the same. That is entirely up to you. There are 2 texture image units we are sampling. You don't need a dummy texture in this world of shaders and total flexibility. The ColorFactor is just another uniform. You just upload it with a glUniform* call. The shader code is short and clearcut compared to the dozens of lines for setting up a Texture Combiners. | ||
+ | [[Category:Deprecated]] |
Latest revision as of 10:26, 3 January 2018
Warning: This article describes legacy OpenGL APIs that have been removed from core OpenGL 3.1 and above (they are only deprecated in OpenGL 3.0). It is recommended that you not use this functionality in your programs. Consider using the OpenGL Shading Language instead. |
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.
For the fixed pipeline, to know how many texture units are supported, call glGetIntegerv(GL_MAX_TEXTURE_UNITS, &MaxTextureUnits).
For early hw like nVidia TNT and Geforce 256, it would be 2 units.
Even on a modern GPU like a Gf 8, the number is 4, although in reality the GPU can do far more in the programmable pipeline.
Each unit has its own texture bind, its own texture coordinate, its own texture matrix, its own TexGen, its own TexEnv states.
The examples below show us binding a texture and TexEnv.
For the programmable pipeline, the texture image samplers and texcoords are dissociated. You could for example use TexCoord0 to sample Texture Unit 5.
In the programmable pipeline, there are no texture matrices. There are no TexGen states and no TexEnv states.
You upload the matrices yourself with glUniformMatrix and the mathematics of TexGen and TexEnv, you simply code it yourself.
This page explains the math for glTexGen http://www.opengl.org/wiki/Mathematics_of_glTexGen
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &MaxTextureImageUnits) tells you how many samplers you have. This might be 16 or 32.
glGetIntegerv(GL_MAX_TEXTURE_COORDS, &MaxTextureCoords) tells you how many texcoords you have. This might be 8.
Most people don't need to send much texcoords to their vertex shaders but they need to sample a lot of textures, that is why the numbers are always not equal on all GPUs.
In the programmable pipeline, a sampler means texture image units. The states are the MIN and MAG filter, anisotropy, lower mip level.
Example : multiply tex0 and tex1
The keyword here is GL_MODULATE, which does the actual multiplication.
Mathematically, it look like this
result_rgb = texture0_rgb // Just read the texture result_a = texture0_a result_rgb = result_rgb * texture1_rgb result_a = result_a * texture1_a
The setup code for the Texture Combiners will look like this
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
// Simply sample the texture
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// --------------------
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
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
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
attribute vec2 InTexCoord1;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
varying vec2 TexCoord1; // Or just use TexCoord0
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
TexCoord1 = InTexCoord1;
}
// Fragment shader
#version 110
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);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// --------------------
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
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
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
attribute vec2 InTexCoord1;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
varying vec2 TexCoord1; // Or just use TexCoord0
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
TexCoord1 = InTexCoord1;
}
// Fragment shader
#version 110
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);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// --------------------
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
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
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
attribute vec2 InTexCoord1;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
varying vec2 TexCoord1; // Or just use TexCoord0
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
TexCoord1 = InTexCoord1;
}
// Fragment shader
#version 110
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);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// --------------------
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); // 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_REPLACE); // 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);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID2);
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);
With shaders, things are much more flexible.
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
}
// Fragment shader
#version 110
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 (You can in fact have your texture with the alpha mask on any TIU you want)
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
}
// Fragment shader
#version 110
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);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// --------------------
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
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
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
}
// Fragment shader
#version 110
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);
}
Example : Interpolate tex0 and tex1 and multiply the result
This shows one of the limitations of Texture Combiners and how Shaders really come to the rescue. But at least, this case can be done with Texture Combiners!
From looking at the above examples, you have already noticed how texture image units and texcoord are not decoupled in Texture Combiners. This example also shows this.
Mathematically, we want to do
result_rgb = (Tex0_rgb * factor) + (Tex1_rgb * (1 - factor)) // Interpolate result_rgb = result_rgb * color_rgb // Multiply by a color factor
Tex0 can be placed on Texture Image Unit (TIU) 0 and Tex1 can be placed on TIU 1. For doing color_rgb, you are going to need another TIU. You have to bind a dummy texture and activate the TIU. You aren't forced to send texcoords for TIU 2.
Here is the Texture Combiner setup code :
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// --------------------
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
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_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); // REPLACE just need a SOURCE0 and OPERAND0
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_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);
glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D); // Activate the unit
glBindTexture(GL_TEXTURE_2D, dummyTexture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
// GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_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_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT); // REPLACE just need a SOURCE0 and OPERAND0
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
// --------------------
float mycolor2[4];
mycolor2[0]=0.6; // Red
mycolor2[1]=0.8; // Green
mycolor2[2]=1.0; // Blue
mycolor2[3]=1.0; // Alpha
// This glTexEnvfv call is loaded on TIU 2 because of the call to glActiveTexture(GL_TEXTURE2)
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2);
So the above Texture Combiner setup looks really complicated and nasty. The Shader version will look like this.
The equivalent with GL 2.0 shaders
// Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
attribute vec2 InTexCoord1;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
varying vec2 TexCoord1; // Or just use TexCoord0
// --------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
TexCoord1 = InTexCoord1;
}
// Fragment shader
#version 110
uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform float BlendFactor;
uniform vec4 ColorFactor;
// --------------------
varying vec2 TexCoord0;
varying vec2 TexCoord1; // Or just use TexCoord0
// --------------------
void main()
{
vec4 ColorResult;
vec4 texel0 = texture2D(Texture0, TexCoord0);
vec4 texel1 = texture2D(Texture1, TexCoord1);
ColorResult = mix(texel0, texel1, BlendFactor);
gl_FragColor = ColorResult * ColorFactor;
}
The shader above is using custom attributes InVertex, InTexCoord0 and InTexCoord1. It is using 2 texcoord inputs although perhaps you don't need 2 if both will be the same. That is entirely up to you. There are 2 texture image units we are sampling. You don't need a dummy texture in this world of shaders and total flexibility. The ColorFactor is just another uniform. You just upload it with a glUniform* call. The shader code is short and clearcut compared to the dozens of lines for setting up a Texture Combiners.