Advanced Textures
CS 481 Lecture, Dr. Lawlor
Texture Handles and Units
You can have a bunch of different texture images uploaded on the
graphics card at the same time. You then tell OpenGL which
texture you want by "binding" a "texture handle" with glBindTexture. Almost all the texture calls apply to the currently-bound texture.
You can make a new texture with glGenTextures(1,&newHandle).
To render with the texture, you just need it bound to a texture "unit". You set the active texture unit with glActiveTexture,
passing a constant like GL_TEXTURE1 to select the first texture
unit. You then indicate that unit should render a texture by
binding the texture. Here's how it looks:
static unsigned int someTex=0; /* my texture "handle" */
if (someTex==0) { /* initialize the texture only once */
glGenTextures(1,&someTex); /* make one texture */
glBindTexture(GL_TEXTURE_2D,someTex); /* use texture */
readTextureFromFile("some_thing.bmp"); /* load texture with data */
}
// Later, at rendering time:
glActiveTexture(GL_TEXTURE3); // for texture unit 3...
glBindTexture(GL_TEXTURE_2D,someTex); // ...render someTex
// Tell GLSL that the "uniform sampler2D frigginTex;" is texture unit 3:
glUniform1iARB(glGetUniformLocationARB(prog,"frigginTex"),3);
Yes, it's kinda wonky. The problem here is that four separate generations of OpenGL added these features one at a time:
- Way back in OpenGL 1.0, you could only have one texture. You read the texture, uploaded it, and rendered.
- To leave several textures loaded on the card at once, in OpenGL
1.1 they added "glGenTextures" and "glBindTexture" to switch between
textures. Only one texture was rendered at a time, though.
- Then they wanted to be able to have several textures rendered at
once, so (via the "multitexture" extension) they added the "texture
unit" concept and glActiveTexture to pick the texture unit.
- Finally, they added GLSL, and just hooked it directly into the texture units.
Texture Parameters
There sure is a lot of texture state accessible via the glTexParameter
function. All this state applies to the currently-bound texture
(last call to glBindTexture).
You can adjust whether textures wrap-around (GL_REPEAT) or clamp
(GL_CLAMP_TO_EDGE) out-of-bounds texture coordinates, on a per-axis
basis:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
You can adjust the minification and magnification modes to disable all filtering:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
Or you can turn on mipmaps, and have beautiful linear filtering:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
You can even turn on anisotropic filtering (via this extension), and avoid plain mipmapping's too-blurry horizon:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,100);
You can ask OpenGL to rebuild the mipmaps whenever texture level 0 changes:
glTexParameteri(GL_TEXTURE_2D,GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
And suprisingly *none* of this really costs much runtime performance!
Framebuffer Feedback
You can copy the currently-rendered display into the currently-bound texture with
glCopyTexSubImage2D.