Difference between revisions of "Texture Combiners"

From OpenGL Wiki
Jump to: navigation, search
(Adding vertex shader)
(Adding vertex shader)
Line 162: Line 162:
  
 
The equivalent with GL 2.0 shaders
 
The equivalent with GL 2.0 shaders
 +
  //Vertex shader
 +
  #version 110
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  varying vec2 TexCoord1;    //Or just use TexCoord0
 +
  //------------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * gl_Vertex;
 +
    TexCoord0 = gl_MultiTexCoord0.xy;
 +
    TexCoord1 = gl_MultiTexCoord1.xy;
 +
  }
 +
  //------------------------
 
   //Fragment shader
 
   //Fragment shader
 +
  #version 110
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
Line 175: Line 189:
 
     gl_FragColor = mix(texel0, texel1, texel0.a);
 
     gl_FragColor = mix(texel0, texel1, texel0.a);
 
   }
 
   }
 
  
 
=== Example : Blend tex1 and tex2 based on alpha of tex0 ===
 
=== Example : Blend tex1 and tex2 based on alpha of tex0 ===

Revision as of 14:45, 18 February 2011

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.

 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

 //Vertex shader
 #version 110
 uniform mat4 ProjectionModelviewMatrix;
 varying vec2 TexCoord0;
 varying vec2 TexCoord1;    //Or just use TexCoord0
 //------------------------
 void main()
 {
   gl_Position = ProjectionModelviewMatrix * gl_Vertex;
   TexCoord0 = gl_MultiTexCoord0.xy;
   TexCoord1 = gl_MultiTexCoord1.xy;
 }
 //------------------------
 //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);
 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

 //Vertex shader
 #version 110
 uniform mat4 ProjectionModelviewMatrix;
 varying vec2 TexCoord0;
 varying vec2 TexCoord1;    //Or just use TexCoord0
 //------------------------
 void main()
 {
   gl_Position = ProjectionModelviewMatrix * gl_Vertex;
   TexCoord0 = gl_MultiTexCoord0.xy;
   TexCoord1 = gl_MultiTexCoord1.xy;
 }
 //------------------------
 //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);
 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

 //Vertex shader
 #version 110
 uniform mat4 ProjectionModelviewMatrix;
 varying vec2 TexCoord0;
 varying vec2 TexCoord1;    //Or just use TexCoord0
 //------------------------
 void main()
 {
   gl_Position = ProjectionModelviewMatrix * gl_Vertex;
   TexCoord0 = gl_MultiTexCoord0.xy;
   TexCoord1 = gl_MultiTexCoord1.xy;
 }
 //------------------------
 //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);
 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_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.

 //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);
 }